From bb868613d931340d6f5a5d3b272c653cfa4e3cca Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Fri, 22 May 2026 14:37:42 +0200 Subject: [PATCH] feat: add password handling helpers --- login.c | 66 ++++++++++++++++++++++--------- nwcrypt.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ nwcrypt.h | 2 + 3 files changed, 163 insertions(+), 18 deletions(-) diff --git a/login.c b/login.c index b4e7c7e..e11269b 100644 --- a/login.c +++ b/login.c @@ -14,31 +14,55 @@ static int do_change_object_passwd(char *name, { uint8 key[8]; - if (0 && !ncp_17_17(key)) { + + if (!ncp_17_17(key)) { uint32 objid = ncp_17_35(name, objtyp); if (objid) { - uint8 buff[128]; - uint8 encrypted[8]; - uint8 newcryptpasswd[16]; - int passwdx=0; + uint8 oldpwd[16]; /* old passwd as stored by server */ + uint8 newpwd[16]; /* new passwd as stored by server */ + uint8 cryptkey[8]; uint8 tmpid[4]; + uint8 passwdx; + int newlen; + + memcpy(cryptkey, key, 8); U32_TO_BE32(objid, tmpid); - shuffle(tmpid, oldpassword, strlen(oldpassword), buff); - nw_encrypt(key, buff, encrypted); - shuffle(tmpid, newpassword, strlen(newpassword), buff); + shuffle(tmpid, oldpassword, strlen(oldpassword), oldpwd); + shuffle(tmpid, newpassword, strlen(newpassword), newpwd); - if (!ncp_17_4b(encrypted, name, objtyp, passwdx, newcryptpasswd)) { + nw_encrypt(cryptkey, oldpwd, cryptkey); + + /* + * Same keyed change password transformation as ncpfs + * ncp_change_login_passwd(): encrypt both 8-byte halves of the + * stored new password using the stored old password as key material. + * newpassencrypt() intentionally mutates oldpwd; the passwd length + * byte must be calculated afterwards, just like ncpfs does it. + */ + newpassencrypt(oldpwd, newpwd); + newpassencrypt(oldpwd + 8, newpwd + 8); + + newlen = strlen(newpassword); + if (newlen > 63) newlen = 63; + passwdx = (uint8)(((newlen ^ oldpwd[0] ^ oldpwd[1]) & 0x7f) | 0x40); + + if (!ncp_17_4b(cryptkey, name, objtyp, passwdx, newpwd)) { ;; return(0); } } - } else { /* now we use old unencrypted algorithmus */ - if (!ncp_17_40(name, objtyp, oldpassword, newpassword)) { - ;; - return(0); - } } + + /* + * Fallback for old servers/requesters where Get Encryption Key is not + * available. Keep the original unencrypted behavior as fallback only. + */ + if (!ncp_17_40(name, objtyp, oldpassword, newpassword)) { + ;; + return(0); + } + return(-1); } @@ -83,7 +107,10 @@ static int get_raw_str(uint8 *s, int maxlen, int doecho) case 8 : if (len) { --len; --s; - if (doecho) fprintf(stdout, "\010 \010"); + if (doecho) { + fprintf(stdout, "\010 \010"); + fflush(stdout); + } } else beep(); continue; @@ -94,7 +121,10 @@ static int get_raw_str(uint8 *s, int maxlen, int doecho) len++; break; } /* switch */ - if (doecho) fprintf(stdout, "%c", (uint8)key); + if (doecho) { + fprintf(stdout, "%c", (uint8)key); + fflush(stdout); + } } *s='\0'; return(len); @@ -392,9 +422,9 @@ int func_exec(int argc, char *argv[], int mode) xfree(buff); if (nargv != NULL) { if (!mode) - spawnvp(P_WAIT, buf, nargv); + spawnvp(P_WAIT, buf, (const char *const *)nargv); else - execvp(buf, nargv); + execvp(buf, (const char *const *)nargv); } xfree(buf); } diff --git a/nwcrypt.c b/nwcrypt.c index 507ce54..b39d112 100644 --- a/nwcrypt.c +++ b/nwcrypt.c @@ -118,6 +118,7 @@ static buf32 encryptkeys = 0x6B,0x0F,0xD5,0x70,0xAE,0xFB,0xAD,0x11, 0xF4,0x47,0xDC,0xA7,0xEC,0xCF,0x50,0xC0}; +#include #include "nwcrypt.h" static void shuffle1(buf32 temp, unsigned char *target) @@ -210,4 +211,116 @@ nw_encrypt(unsigned char *fra,unsigned char *buf,unsigned char *til) til[s] = k[s] ^ k[15 - s]; } +static unsigned char + newshuffle[256] = +{ + 0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09, + 0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a, + 0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08, + 0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07, + + 0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00, + 0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07, + 0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09, + 0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e, + + 0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00, + 0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09, + 0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c, + 0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e, + + 0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07, + 0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f, + 0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e, + 0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c, + + 0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a, + 0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09, + 0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f, + 0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09, + + 0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00, + 0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08, + 0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04, + 0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06, + + 0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b, + 0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d, + 0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c, + 0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d, + + 0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01, + 0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a, + 0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00, + 0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02, +}; + +static const unsigned char final_shuffle[16] = { + 0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05, + 0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08, +}; + +/* + * verschluesseln des neuen Passworts fuer keyed change password + * Verwendung: + * - Shuffle (aus nwcrypt.c) altes passwort nach old (16 bytes) + * - shuffle neues passwort nach new (16 bytes) + * - nwpassencrypt (diese Funktion) zweimal aufrufen fuer je 8 bytes: + * nwpassencrypt(old+0, new+0, out+0) + * nwpassencrypt(old+8, new+8, out+8) + * - NCP-Buffer aufbauen: + * 2 byte Laenge im Hi-Lo-Format + * 1 byte Funktion (0x4b) + * 8 byte (nwcrypt Ergebnis analog login/verify password) + * 2 byte Objecttype + * 1 byte Objectname-Laenge + * n byte Objectname + * 1 byte (Laenge des eingegebenen neuen Passworts ^ old[0] ^ old[1])&0x7f|0x40 + * 16 byte (Ergebnis dieser Funktion doppelt aufgerufen, s.o.) + */ + +/* + * Encrypt the new password for keyed change password + * For info on how to use this function, look at ncp_change_login_passwd + * in ncplib.c. + */ + +void +newpassencrypt(unsigned char *old, unsigned char *npwd) +{ + int i; + + for (i = 0; i < 16; i++) { + int di, ax; + unsigned char *p, *bx; + unsigned char cl, dl, ch; + unsigned char copy[8]; + + memcpy(copy, npwd, 8); + for (di = 0, ax = 0, p = old; di < 8; di++, ax += 0x20, p++) + { + cl = newshuffle[(((copy[di] ^ *p) >> 4) & 0x0f) + ax + 0x10] << 4; + dl = newshuffle[((copy[di] ^ *p) & 0xf) + ax]; + copy[di] = cl | dl; + } + + ch = old[7]; + for (bx = old + 7; bx > old; bx--) + { + *bx = ((bx[-1] >> 4) & 0x0f) | ((*bx) << 4); + } + *old = ((ch >> 4) & 0x0f) | (*old) << 4; + + memset(npwd, 0, 8); + + for (di = 0; di < 16; di++) + { + if (final_shuffle[di] & 1) + ch = ((copy[final_shuffle[di] / 2] >> 4) & 0x0f); + else + ch = copy[final_shuffle[di] / 2] & 0x0f; + npwd[di / 2] |= ((di & 1) ? ch << 4 : ch); + } + } +} diff --git a/nwcrypt.h b/nwcrypt.h index 3876b0b..4287d14 100644 --- a/nwcrypt.h +++ b/nwcrypt.h @@ -5,3 +5,5 @@ extern void shuffle(unsigned char *lon, extern void nw_encrypt(unsigned char *fra, unsigned char *buf,unsigned char *til); + +extern void newpassencrypt(unsigned char *old, unsigned char *npwd);