From d4b29aea5d71261f412ac9ccd620071852cd5d44 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Fri, 22 May 2026 15:55:29 +0200 Subject: [PATCH] passwd --- login.c | 62 +++++++++++++++--------------- nwcrypt.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ nwcrypt.h | 2 + 3 files changed, 144 insertions(+), 32 deletions(-) diff --git a/login.c b/login.c index 208fba6..ca84107 100644 --- a/login.c +++ b/login.c @@ -15,56 +15,54 @@ static int do_change_object_passwd(char *name, { uint8 key[8]; - fprintf(stderr, "PASSWD debug: user='%s' oldlen=%u newlen=%u\n", - name, (uint)strlen(oldpassword), (uint)strlen(newpassword)); - if (!ncp_17_17(key)) { - uint32 objid; - - fprintf(stderr, "PASSWD debug: ncp_17_17 OK\n"); - - objid = ncp_17_35(name, objtyp); + uint32 objid = ncp_17_35(name, objtyp); if (objid) { - uint8 buff[128]; - uint8 encrypted[8]; - uint8 newcryptpasswd[16]; - int passwdx = (int)strlen(newpassword); + 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; - fprintf(stderr, "PASSWD debug: ncp_17_35 OK objid=%08lx name='%s'\n", - objid, name); - + memcpy(cryptkey, key, 8); U32_TO_BE32(objid, tmpid); - shuffle(tmpid, oldpassword, strlen(oldpassword), buff); - nw_encrypt(key, buff, encrypted); + shuffle(tmpid, oldpassword, strlen(oldpassword), oldpwd); + shuffle(tmpid, newpassword, strlen(newpassword), newpwd); - shuffle(tmpid, newpassword, strlen(newpassword), buff); - memcpy(newcryptpasswd, buff, sizeof(newcryptpasswd)); + nw_encrypt(cryptkey, oldpwd, cryptkey); - fprintf(stderr, "PASSWD debug: trying encrypted ncp_17_4b passwdx=%d\n", - passwdx); + /* + * 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); - if (!ncp_17_4b(encrypted, name, objtyp, passwdx, newcryptpasswd)) { - fprintf(stderr, "PASSWD debug: ncp_17_4b OK\n"); + 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); } - - fprintf(stderr, "PASSWD debug: ncp_17_4b failed neterrno=%d\n", neterrno); - } else { - fprintf(stderr, "PASSWD debug: ncp_17_35 failed neterrno=%d\n", neterrno); } - } else { - fprintf(stderr, "PASSWD debug: ncp_17_17 failed neterrno=%d\n", neterrno); } - fprintf(stderr, "PASSWD debug: trying fallback unencrypted ncp_17_40\n"); + /* + * 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)) { - fprintf(stderr, "PASSWD debug: ncp_17_40 OK\n"); + ;; return(0); } - fprintf(stderr, "PASSWD debug: ncp_17_40 failed neterrno=%d\n", neterrno); return(-1); } diff --git a/nwcrypt.c b/nwcrypt.c index 507ce54..da276d0 100644 --- a/nwcrypt.c +++ b/nwcrypt.c @@ -210,4 +210,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);