X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/302845cd067a96b3e353f3f85a83dae7d23b4609..HEAD:/sshdes.c diff --git a/sshdes.c b/sshdes.c index fa8e53ce..03d2b3ae 100644 --- a/sshdes.c +++ b/sshdes.c @@ -600,19 +600,7 @@ static void des_decipher(word32 * output, word32 L, word32 R, output[1] = R; } -#define GET_32BIT_MSB_FIRST(cp) \ - (((unsigned long)(unsigned char)(cp)[3]) | \ - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ - ((unsigned long)(unsigned char)(cp)[0] << 24)) - -#define PUT_32BIT_MSB_FIRST(cp, value) do { \ - (cp)[3] = (value); \ - (cp)[2] = (value) >> 8; \ - (cp)[1] = (value) >> 16; \ - (cp)[0] = (value) >> 24; } while (0) - -static void des_cbc_encrypt(unsigned char *dest, const unsigned char *src, +static void des_cbc_encrypt(unsigned char *blk, unsigned int len, DESContext * sched) { word32 out[2], iv0, iv1; @@ -623,23 +611,20 @@ static void des_cbc_encrypt(unsigned char *dest, const unsigned char *src, iv0 = sched->iv0; iv1 = sched->iv1; for (i = 0; i < len; i += 8) { - iv0 ^= GET_32BIT_MSB_FIRST(src); - src += 4; - iv1 ^= GET_32BIT_MSB_FIRST(src); - src += 4; + iv0 ^= GET_32BIT_MSB_FIRST(blk); + iv1 ^= GET_32BIT_MSB_FIRST(blk + 4); des_encipher(out, iv0, iv1, sched); iv0 = out[0]; iv1 = out[1]; - PUT_32BIT_MSB_FIRST(dest, iv0); - dest += 4; - PUT_32BIT_MSB_FIRST(dest, iv1); - dest += 4; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk + 4, iv1); + blk += 8; } sched->iv0 = iv0; sched->iv1 = iv1; } -static void des_cbc_decrypt(unsigned char *dest, const unsigned char *src, +static void des_cbc_decrypt(unsigned char *blk, unsigned int len, DESContext * sched) { word32 out[2], iv0, iv1, xL, xR; @@ -650,17 +635,14 @@ static void des_cbc_decrypt(unsigned char *dest, const unsigned char *src, iv0 = sched->iv0; iv1 = sched->iv1; for (i = 0; i < len; i += 8) { - xL = GET_32BIT_MSB_FIRST(src); - src += 4; - xR = GET_32BIT_MSB_FIRST(src); - src += 4; + xL = GET_32BIT_MSB_FIRST(blk); + xR = GET_32BIT_MSB_FIRST(blk + 4); des_decipher(out, xL, xR, sched); iv0 ^= out[0]; iv1 ^= out[1]; - PUT_32BIT_MSB_FIRST(dest, iv0); - dest += 4; - PUT_32BIT_MSB_FIRST(dest, iv1); - dest += 4; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk + 4, iv1); + blk += 8; iv0 = xL; iv1 = xR; } @@ -668,15 +650,15 @@ static void des_cbc_decrypt(unsigned char *dest, const unsigned char *src, sched->iv1 = iv1; } -static void des_3cbc_encrypt(unsigned char *dest, const unsigned char *src, +static void des_3cbc_encrypt(unsigned char *blk, unsigned int len, DESContext * scheds) { - des_cbc_encrypt(dest, src, len, &scheds[0]); - des_cbc_decrypt(dest, src, len, &scheds[1]); - des_cbc_encrypt(dest, src, len, &scheds[2]); + des_cbc_encrypt(blk, len, &scheds[0]); + des_cbc_decrypt(blk, len, &scheds[1]); + des_cbc_encrypt(blk, len, &scheds[2]); } -static void des_cbc3_encrypt(unsigned char *dest, const unsigned char *src, +static void des_cbc3_encrypt(unsigned char *blk, unsigned int len, DESContext * scheds) { word32 out[2], iv0, iv1; @@ -687,33 +669,30 @@ static void des_cbc3_encrypt(unsigned char *dest, const unsigned char *src, iv0 = scheds->iv0; iv1 = scheds->iv1; for (i = 0; i < len; i += 8) { - iv0 ^= GET_32BIT_MSB_FIRST(src); - src += 4; - iv1 ^= GET_32BIT_MSB_FIRST(src); - src += 4; + iv0 ^= GET_32BIT_MSB_FIRST(blk); + iv1 ^= GET_32BIT_MSB_FIRST(blk + 4); des_encipher(out, iv0, iv1, &scheds[0]); des_decipher(out, out[0], out[1], &scheds[1]); des_encipher(out, out[0], out[1], &scheds[2]); iv0 = out[0]; iv1 = out[1]; - PUT_32BIT_MSB_FIRST(dest, iv0); - dest += 4; - PUT_32BIT_MSB_FIRST(dest, iv1); - dest += 4; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk + 4, iv1); + blk += 8; } scheds->iv0 = iv0; scheds->iv1 = iv1; } -static void des_3cbc_decrypt(unsigned char *dest, const unsigned char *src, +static void des_3cbc_decrypt(unsigned char *blk, unsigned int len, DESContext * scheds) { - des_cbc_decrypt(dest, src, len, &scheds[2]); - des_cbc_encrypt(dest, src, len, &scheds[1]); - des_cbc_decrypt(dest, src, len, &scheds[0]); + des_cbc_decrypt(blk, len, &scheds[2]); + des_cbc_encrypt(blk, len, &scheds[1]); + des_cbc_decrypt(blk, len, &scheds[0]); } -static void des_cbc3_decrypt(unsigned char *dest, const unsigned char *src, +static void des_cbc3_decrypt(unsigned char *blk, unsigned int len, DESContext * scheds) { word32 out[2], iv0, iv1, xL, xR; @@ -724,19 +703,16 @@ static void des_cbc3_decrypt(unsigned char *dest, const unsigned char *src, iv0 = scheds->iv0; iv1 = scheds->iv1; for (i = 0; i < len; i += 8) { - xL = GET_32BIT_MSB_FIRST(src); - src += 4; - xR = GET_32BIT_MSB_FIRST(src); - src += 4; + xL = GET_32BIT_MSB_FIRST(blk); + xR = GET_32BIT_MSB_FIRST(blk + 4); des_decipher(out, xL, xR, &scheds[2]); des_encipher(out, out[0], out[1], &scheds[1]); des_decipher(out, out[0], out[1], &scheds[0]); iv0 ^= out[0]; iv1 ^= out[1]; - PUT_32BIT_MSB_FIRST(dest, iv0); - dest += 4; - PUT_32BIT_MSB_FIRST(dest, iv1); - dest += 4; + PUT_32BIT_MSB_FIRST(blk, iv0); + PUT_32BIT_MSB_FIRST(blk + 4, iv1); + blk += 8; iv0 = xL; iv1 = xR; } @@ -744,26 +720,53 @@ static void des_cbc3_decrypt(unsigned char *dest, const unsigned char *src, scheds->iv1 = iv1; } +static void des_sdctr3(unsigned char *blk, + unsigned int len, DESContext * scheds) +{ + word32 b[2], iv0, iv1, tmp; + unsigned int i; + + assert((len & 7) == 0); + + iv0 = scheds->iv0; + iv1 = scheds->iv1; + for (i = 0; i < len; i += 8) { + des_encipher(b, iv0, iv1, &scheds[0]); + des_decipher(b, b[0], b[1], &scheds[1]); + des_encipher(b, b[0], b[1], &scheds[2]); + tmp = GET_32BIT_MSB_FIRST(blk); + PUT_32BIT_MSB_FIRST(blk, tmp ^ b[0]); + blk += 4; + tmp = GET_32BIT_MSB_FIRST(blk); + PUT_32BIT_MSB_FIRST(blk, tmp ^ b[1]); + blk += 4; + if ((iv1 = (iv1 + 1) & 0xffffffff) == 0) + iv0 = (iv0 + 1) & 0xffffffff; + } + scheds->iv0 = iv0; + scheds->iv1 = iv1; +} + static void *des3_make_context(void) { - return smalloc(3*sizeof(DESContext)); + return snewn(3, DESContext); } static void *des3_ssh1_make_context(void) { - /* Need 3 keys for each direction, in SSH1 */ - return smalloc(6*sizeof(DESContext)); + /* Need 3 keys for each direction, in SSH-1 */ + return snewn(6, DESContext); } static void *des_make_context(void) { - return smalloc(sizeof(DESContext)); + return snew(DESContext); } static void *des_ssh1_make_context(void) { - /* Need one key for each direction, in SSH1 */ - return smalloc(2*sizeof(DESContext)); + /* Need one key for each direction, in SSH-1 */ + return snewn(2, DESContext); } static void des3_free_context(void *handle) /* used for both 3DES and DES */ @@ -806,37 +809,43 @@ static void des3_sesskey(void *handle, unsigned char *key) static void des3_encrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_3cbc_encrypt(blk, blk, len, keys); + des_3cbc_encrypt(blk, len, keys); } static void des3_decrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_3cbc_decrypt(blk, blk, len, keys+3); + des_3cbc_decrypt(blk, len, keys+3); } static void des3_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_cbc3_encrypt(blk, blk, len, keys); + des_cbc3_encrypt(blk, len, keys); } static void des3_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_cbc3_decrypt(blk, blk, len, keys); + des_cbc3_decrypt(blk, len, keys); +} + +static void des3_ssh2_sdctr(void *handle, unsigned char *blk, int len) +{ + DESContext *keys = (DESContext *) handle; + des_sdctr3(blk, len, keys); } static void des_ssh2_encrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_cbc_encrypt(blk, blk, len, keys); + des_cbc_encrypt(blk, len, keys); } static void des_ssh2_decrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_cbc_decrypt(blk, blk, len, keys); + des_cbc_decrypt(blk, len, keys); } void des3_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len) @@ -848,8 +857,8 @@ void des3_decrypt_pubkey(unsigned char *key, unsigned char *blk, int len) GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]); - des_3cbc_decrypt(blk, blk, len, ourkeys); - memset(ourkeys, 0, sizeof(ourkeys)); + des_3cbc_decrypt(blk, len, ourkeys); + smemclr(ourkeys, sizeof(ourkeys)); } void des3_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) @@ -861,8 +870,8 @@ void des3_encrypt_pubkey(unsigned char *key, unsigned char *blk, int len) GET_32BIT_MSB_FIRST(key + 12), &ourkeys[1]); des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), &ourkeys[2]); - des_3cbc_encrypt(blk, blk, len, ourkeys); - memset(ourkeys, 0, sizeof(ourkeys)); + des_3cbc_encrypt(blk, len, ourkeys); + smemclr(ourkeys, sizeof(ourkeys)); } void des3_decrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, @@ -877,8 +886,8 @@ void des3_decrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, GET_32BIT_MSB_FIRST(key + 20), &ourkeys[2]); ourkeys[0].iv0 = GET_32BIT_MSB_FIRST(iv); ourkeys[0].iv1 = GET_32BIT_MSB_FIRST(iv+4); - des_cbc3_decrypt(blk, blk, len, ourkeys); - memset(ourkeys, 0, sizeof(ourkeys)); + des_cbc3_decrypt(blk, len, ourkeys); + smemclr(ourkeys, sizeof(ourkeys)); } void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, @@ -893,30 +902,85 @@ void des3_encrypt_pubkey_ossh(unsigned char *key, unsigned char *iv, GET_32BIT_MSB_FIRST(key + 20), &ourkeys[2]); ourkeys[0].iv0 = GET_32BIT_MSB_FIRST(iv); ourkeys[0].iv1 = GET_32BIT_MSB_FIRST(iv+4); - des_cbc3_encrypt(blk, blk, len, ourkeys); - memset(ourkeys, 0, sizeof(ourkeys)); + des_cbc3_encrypt(blk, len, ourkeys); + smemclr(ourkeys, sizeof(ourkeys)); +} + +static void des_keysetup_xdmauth(unsigned char *keydata, DESContext *dc) +{ + unsigned char key[8]; + int i, nbits, j; + unsigned int bits; + + bits = 0; + nbits = 0; + j = 0; + for (i = 0; i < 8; i++) { + if (nbits < 7) { + bits = (bits << 8) | keydata[j]; + nbits += 8; + j++; + } + key[i] = (bits >> (nbits - 7)) << 1; + bits &= ~(0x7F << (nbits - 7)); + nbits -= 7; + } + + des_key_setup(GET_32BIT_MSB_FIRST(key), GET_32BIT_MSB_FIRST(key + 4), dc); +} + +void des_encrypt_xdmauth(unsigned char *keydata, unsigned char *blk, int len) +{ + DESContext dc; + des_keysetup_xdmauth(keydata, &dc); + des_cbc_encrypt(blk, 24, &dc); +} + +void des_decrypt_xdmauth(unsigned char *keydata, unsigned char *blk, int len) +{ + DESContext dc; + des_keysetup_xdmauth(keydata, &dc); + des_cbc_decrypt(blk, 24, &dc); } static const struct ssh2_cipher ssh_3des_ssh2 = { des3_make_context, des3_free_context, des3_iv, des3_key, des3_ssh2_encrypt_blk, des3_ssh2_decrypt_blk, "3des-cbc", - 8, 168, "triple-DES" + 8, 168, SSH_CIPHER_IS_CBC, "triple-DES CBC" +}; + +static const struct ssh2_cipher ssh_3des_ssh2_ctr = { + des3_make_context, des3_free_context, des3_iv, des3_key, + des3_ssh2_sdctr, des3_ssh2_sdctr, + "3des-ctr", + 8, 168, 0, "triple-DES SDCTR" }; /* - * Single DES in ssh2. It isn't clear that "des-cbc" is an official - * cipher name, but ssh.com support it and apparently aren't the - * only people to do so, so we sigh and implement it anyway. + * Single DES in SSH-2. "des-cbc" is marked as HISTORIC in + * RFC 4250, referring to + * FIPS-46-3. ("Single DES (i.e., DES) will be permitted + * for legacy systems only.") , but ssh.com support it and + * apparently aren't the only people to do so, so we sigh + * and implement it anyway. */ static const struct ssh2_cipher ssh_des_ssh2 = { des_make_context, des3_free_context, des3_iv, des_key, des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, "des-cbc", - 8, 56, "single-DES" + 8, 56, SSH_CIPHER_IS_CBC, "single-DES CBC" +}; + +static const struct ssh2_cipher ssh_des_sshcom_ssh2 = { + des_make_context, des3_free_context, des3_iv, des_key, + des_ssh2_encrypt_blk, des_ssh2_decrypt_blk, + "des-cbc@ssh.com", + 8, 56, SSH_CIPHER_IS_CBC, "single-DES CBC" }; static const struct ssh2_cipher *const des3_list[] = { + &ssh_3des_ssh2_ctr, &ssh_3des_ssh2 }; @@ -926,18 +990,19 @@ const struct ssh2_ciphers ssh2_3des = { }; static const struct ssh2_cipher *const des_list[] = { - &ssh_des_ssh2 + &ssh_des_ssh2, + &ssh_des_sshcom_ssh2 }; const struct ssh2_ciphers ssh2_des = { - sizeof(des3_list) / sizeof(*des_list), + sizeof(des_list) / sizeof(*des_list), des_list }; const struct ssh_cipher ssh_3des = { des3_ssh1_make_context, des3_free_context, des3_sesskey, des3_encrypt_blk, des3_decrypt_blk, - 8, "triple-DES" + 8, "triple-DES inner-CBC" }; static void des_sesskey(void *handle, unsigned char *key) @@ -950,17 +1015,17 @@ static void des_sesskey(void *handle, unsigned char *key) static void des_encrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_cbc_encrypt(blk, blk, len, keys); + des_cbc_encrypt(blk, len, keys); } static void des_decrypt_blk(void *handle, unsigned char *blk, int len) { DESContext *keys = (DESContext *) handle; - des_cbc_decrypt(blk, blk, len, keys+1); + des_cbc_decrypt(blk, len, keys+1); } const struct ssh_cipher ssh_des = { des_ssh1_make_context, des3_free_context, des_sesskey, des_encrypt_blk, des_decrypt_blk, - 8, "single-DES" + 8, "single-DES CBC" };