diff --git a/cproxy.c b/cproxy.c index 0fd4a8ec..5825f32e 100644 --- a/cproxy.c +++ b/cproxy.c @@ -18,22 +18,15 @@ static void hmacmd5_chap(const unsigned char *challenge, int challen, const char *passwd, unsigned char *response) { - struct hmacmd5_context *hmacmd5_ctx; - int pwlen; + ptrlen key = ptrlen_from_asciz(passwd); + unsigned char md5buf[16]; - hmacmd5_ctx = hmacmd5_make_context(); - - pwlen = strlen(passwd); - if (pwlen>64) { - unsigned char md5buf[16]; - MD5Simple(passwd, pwlen, md5buf); - hmacmd5_key(hmacmd5_ctx, md5buf, 16); - } else { - hmacmd5_key(hmacmd5_ctx, passwd, pwlen); + if (key.len > 64) { + hash_simple(&ssh_md5, key, md5buf); + key = make_ptrlen(md5buf, 16); } - - hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response); - hmacmd5_free_context(hmacmd5_ctx); + mac_simple(&ssh_hmac_md5, key, make_ptrlen(challenge, challen), response); + smemclr(md5buf, sizeof(md5buf)); } void proxy_socks5_offerencryptedauth(BinarySink *bs) diff --git a/import.c b/import.c index a62e6cb9..c8786d52 100644 --- a/import.c +++ b/import.c @@ -495,6 +495,36 @@ static bool openssh_pem_encrypted(const Filename *filename) return ret; } +static void openssh_pem_derivekey( + ptrlen passphrase, const void *iv, uint8_t *keybuf) +{ + /* + * Derive the encryption key for a PEM key file from the + * passphrase and iv/salt: + * + * - let block A equal MD5(passphrase || iv) + * - let block B equal MD5(A || passphrase || iv) + * - block C would be MD5(B || passphrase || iv) and so on + * - encryption key is the first N bytes of A || B + * + * (Note that only 8 bytes of the iv are used for key + * derivation, even when the key is encrypted with AES and + * hence there are 16 bytes available.) + */ + ssh_hash *h; + + h = ssh_hash_new(&ssh_md5); + put_datapl(h, passphrase); + put_data(h, iv, 8); + ssh_hash_final(h, keybuf); + + h = ssh_hash_new(&ssh_md5); + put_data(h, keybuf, 16); + put_datapl(h, passphrase); + put_data(h, iv, 8); + ssh_hash_final(h, keybuf + 16); +} + static ssh2_userkey *openssh_pem_read( const Filename *filename, const char *passphrase, const char **errmsg_p) { @@ -514,34 +544,11 @@ static ssh2_userkey *openssh_pem_read( return NULL; if (key->encrypted) { - /* - * Derive encryption key from passphrase and iv/salt: - * - * - let block A equal MD5(passphrase || iv) - * - let block B equal MD5(A || passphrase || iv) - * - block C would be MD5(B || passphrase || iv) and so on - * - encryption key is the first N bytes of A || B - * - * (Note that only 8 bytes of the iv are used for key - * derivation, even when the key is encrypted with AES and - * hence there are 16 bytes available.) - */ - struct MD5Context md5c; unsigned char keybuf[32]; - - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - put_data(&md5c, key->iv, 8); - MD5Final(keybuf, &md5c); - - MD5Init(&md5c); - put_data(&md5c, keybuf, 16); - put_data(&md5c, passphrase, strlen(passphrase)); - put_data(&md5c, key->iv, 8); - MD5Final(keybuf+16, &md5c); + openssh_pem_derivekey(ptrlen_from_asciz(passphrase), key->iv, keybuf); /* - * Now decrypt the key blob. + * Decrypt the key blob. */ if (key->encryption == OP_E_3DES) des3_decrypt_pubkey_ossh(keybuf, key->iv, @@ -554,7 +561,6 @@ static ssh2_userkey *openssh_pem_read( ssh_cipher_free(cipher); } - smemclr(&md5c, sizeof(md5c)); smemclr(keybuf, sizeof(keybuf)); } @@ -981,7 +987,6 @@ static bool openssh_pem_write( * old-style 3DES. */ if (passphrase) { - struct MD5Context md5c; unsigned char keybuf[32]; int origlen, outlen, pad, i; @@ -1008,26 +1013,11 @@ static bool openssh_pem_write( put_padding(outblob, pad, pad); /* - * Invent an iv. Then derive encryption key from passphrase - * and iv/salt: - * - * - let block A equal MD5(passphrase || iv) - * - let block B equal MD5(A || passphrase || iv) - * - block C would be MD5(B || passphrase || iv) and so on - * - encryption key is the first N bytes of A || B + * Invent an iv, and derive the encryption key. */ for (i = 0; i < 8; i++) iv[i] = random_byte(); - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - put_data(&md5c, iv, 8); - MD5Final(keybuf, &md5c); - - MD5Init(&md5c); - put_data(&md5c, keybuf, 16); - put_data(&md5c, passphrase, strlen(passphrase)); - put_data(&md5c, iv, 8); - MD5Final(keybuf+16, &md5c); + openssh_pem_derivekey(ptrlen_from_asciz(passphrase), iv, keybuf); /* * Now encrypt the key blob. @@ -1035,7 +1025,6 @@ static bool openssh_pem_write( des3_encrypt_pubkey_ossh(keybuf, iv, outblob->u, outlen); - smemclr(&md5c, sizeof(md5c)); smemclr(keybuf, sizeof(keybuf)); } @@ -1959,6 +1948,26 @@ static ptrlen BinarySource_get_mp_sshcom_as_string(BinarySource *src) #define get_mp_sshcom_as_string(bs) \ BinarySource_get_mp_sshcom_as_string(BinarySource_UPCAST(bs)) +static void sshcom_derivekey(ptrlen passphrase, uint8_t *keybuf) +{ + /* + * Derive the encryption key for an ssh.com key file from the + * passphrase and iv/salt: + * + * - let block A equal MD5(passphrase) + * - let block B equal MD5(passphrase || A) + * - block C would be MD5(passphrase || A || B) and so on + * - encryption key is the first N bytes of A || B + */ + ssh_hash *h; + + h = ssh_hash_new(&ssh_md5); + put_datapl(h, passphrase); + ssh_hash_final(ssh_hash_copy(h), keybuf); + put_data(h, keybuf, 16); + ssh_hash_final(h, keybuf + 16); +} + static ssh2_userkey *sshcom_read( const Filename *filename, const char *passphrase, const char **errmsg_p) { @@ -2035,7 +2044,6 @@ static ssh2_userkey *sshcom_read( * - block C would be MD5(passphrase || A || B) and so on * - encryption key is the first N bytes of A || B */ - struct MD5Context md5c; unsigned char keybuf[32], iv[8]; if (ciphertext.len % 8 != 0) { @@ -2044,14 +2052,7 @@ static ssh2_userkey *sshcom_read( goto error; } - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - MD5Final(keybuf, &md5c); - - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - put_data(&md5c, keybuf, 16); - MD5Final(keybuf+16, &md5c); + sshcom_derivekey(ptrlen_from_asciz(passphrase), keybuf); /* * Now decrypt the key blob in place (casting away const from @@ -2061,7 +2062,6 @@ static ssh2_userkey *sshcom_read( des3_decrypt_pubkey_ossh(keybuf, iv, (char *)ciphertext.ptr, ciphertext.len); - smemclr(&md5c, sizeof(md5c)); smemclr(keybuf, sizeof(keybuf)); /* @@ -2294,25 +2294,9 @@ static bool sshcom_write( * Encrypt the key. */ if (passphrase) { - /* - * Derive encryption key from passphrase and iv/salt: - * - * - let block A equal MD5(passphrase) - * - let block B equal MD5(passphrase || A) - * - block C would be MD5(passphrase || A || B) and so on - * - encryption key is the first N bytes of A || B - */ - struct MD5Context md5c; unsigned char keybuf[32], iv[8]; - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - MD5Final(keybuf, &md5c); - - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - put_data(&md5c, keybuf, 16); - MD5Final(keybuf+16, &md5c); + sshcom_derivekey(ptrlen_from_asciz(passphrase), keybuf); /* * Now decrypt the key blob. @@ -2320,7 +2304,6 @@ static bool sshcom_write( memset(iv, 0, sizeof(iv)); des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen); - smemclr(&md5c, sizeof(md5c)); smemclr(keybuf, sizeof(keybuf)); } diff --git a/pageant.c b/pageant.c index 83b85686..5767855a 100644 --- a/pageant.c +++ b/pageant.c @@ -228,7 +228,6 @@ void pageant_handle_msg(BinarySink *bs, ptrlen session_id; unsigned response_type; unsigned char response_md5[16]; - struct MD5Context md5c; int i; plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE"); @@ -266,11 +265,13 @@ void pageant_handle_msg(BinarySink *bs, } response = rsa_ssh1_decrypt(challenge, key); - MD5Init(&md5c); - for (i = 0; i < 32; i++) - put_byte(&md5c, mp_get_byte(response, 31 - i)); - put_datapl(&md5c, session_id); - MD5Final(response_md5, &md5c); + { + ssh_hash *h = ssh_hash_new(&ssh_md5); + for (i = 0; i < 32; i++) + put_byte(h, mp_get_byte(response, 31 - i)); + put_datapl(h, session_id); + ssh_hash_final(h, response_md5); + } put_byte(bs, SSH1_AGENT_RSA_RESPONSE); put_data(bs, response_md5, 16); diff --git a/ssh.h b/ssh.h index 8597e8e0..4054694a 100644 --- a/ssh.h +++ b/ssh.h @@ -558,73 +558,8 @@ struct ssh_cipher { const ssh_cipheralg *vt; }; -typedef struct { - uint32_t h[4]; -} MD5_Core_State; - -struct MD5Context { - MD5_Core_State core; - unsigned char block[64]; - int blkused; - uint64_t len; - BinarySink_IMPLEMENTATION; -}; - -void MD5Init(struct MD5Context *context); -void MD5Final(unsigned char digest[16], struct MD5Context *context); -void MD5Simple(void const *p, unsigned len, unsigned char output[16]); - -struct hmacmd5_context; -struct hmacmd5_context *hmacmd5_make_context(void); -void hmacmd5_free_context(struct hmacmd5_context *ctx); -void hmacmd5_key(struct hmacmd5_context *ctx, void const *key, int len); -void hmacmd5_do_hmac(struct hmacmd5_context *ctx, - const void *blk, int len, unsigned char *hmac); - bool supports_sha_ni(void); -typedef struct SHA_State { - uint32_t h[5]; - unsigned char block[64]; - int blkused; - uint64_t len; - void (*sha1)(struct SHA_State * s, const unsigned char *p, int len); - BinarySink_IMPLEMENTATION; -} SHA_State; -void SHA_Init(SHA_State * s); -void SHA_Final(SHA_State * s, unsigned char *output); -void SHA_Simple(const void *p, int len, unsigned char *output); - -void hmac_sha1_simple(const void *key, int keylen, - const void *data, int datalen, - unsigned char *output); -typedef struct SHA256_State { - uint32_t h[8]; - unsigned char block[64]; - int blkused; - uint64_t len; - void (*sha256)(struct SHA256_State * s, const unsigned char *p, int len); - BinarySink_IMPLEMENTATION; -} SHA256_State; -void SHA256_Init(SHA256_State * s); -void SHA256_Final(SHA256_State * s, unsigned char *output); -void SHA256_Simple(const void *p, int len, unsigned char *output); - -typedef struct { - uint64_t h[8]; - unsigned char block[128]; - int blkused; - uint64_t lenhi, lenlo; - BinarySink_IMPLEMENTATION; -} SHA512_State; -#define SHA384_State SHA512_State -void SHA512_Init(SHA512_State * s); -void SHA512_Final(SHA512_State * s, unsigned char *output); -void SHA512_Simple(const void *p, int len, unsigned char *output); -void SHA384_Init(SHA384_State * s); -void SHA384_Final(SHA384_State * s, unsigned char *output); -void SHA384_Simple(const void *p, int len, unsigned char *output); - struct ssh_cipheralg { ssh_cipher *(*new)(const ssh_cipheralg *alg); void (*free)(ssh_cipher *); @@ -704,11 +639,17 @@ struct ssh2_macalg { #define ssh2_mac_genresult(ctx, out) ((ctx)->vt->genresult(ctx, out)) #define ssh2_mac_alg(ctx) ((ctx)->vt) -/* Centralised 'methods' for ssh2_mac, defined in sshmac.c */ +/* Centralised 'methods' for ssh2_mac, defined in sshmac.c. These run + * the MAC in a specifically SSH-2 style, i.e. taking account of a + * packet sequence number as well as the data to be authenticated. */ bool ssh2_mac_verresult(ssh2_mac *, const void *); void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq); bool ssh2_mac_verify(ssh2_mac *, const void *, int, unsigned long seq); +/* Use a MAC in its raw form, outside SSH-2 context, to MAC a given + * string with a given key in the most obvious way. */ +void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output); + struct ssh_hash { const ssh_hashalg *vt; BinarySink_DELEGATE_IMPLEMENTATION; @@ -729,6 +670,8 @@ struct ssh_hashalg { #define ssh_hash_free(ctx) ((ctx)->vt->free(ctx)) #define ssh_hash_alg(ctx) ((ctx)->vt) +void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output); + struct ssh_kex { const char *name, *groupname; enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type; diff --git a/ssh1login-server.c b/ssh1login-server.c index 4a8bc175..d2e12800 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -306,15 +306,16 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) { unsigned char *rsabuf = snewn(s->authkey->bytes, unsigned char); - struct MD5Context md5c; for (i = 0; i < 32; i++) rsabuf[i] = random_byte(); - MD5Init(&md5c); - put_data(&md5c, rsabuf, 32); - put_data(&md5c, s->session_id, 16); - MD5Final(s->auth_rsa_expected_response, &md5c); + { + ssh_hash *h = ssh_hash_new(&ssh_md5); + put_data(h, rsabuf, 32); + put_data(h, s->session_id, 16); + ssh_hash_final(h, s->auth_rsa_expected_response); + } if (!rsa_ssh1_encrypt(rsabuf, 32, s->authkey)) { sfree(rsabuf); diff --git a/ssh1login.c b/ssh1login.c index 945f0c3a..7a0968be 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -737,11 +737,10 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) } { - struct MD5Context md5c; - MD5Init(&md5c); - put_data(&md5c, buffer, 32); - put_data(&md5c, s->session_id, 16); - MD5Final(buffer, &md5c); + ssh_hash *h = ssh_hash_new(&ssh_md5); + put_data(h, buffer, 32); + put_data(h, s->session_id, 16); + ssh_hash_final(h, buffer); } pkt = ssh_bpp_new_pktout( diff --git a/sshauxcrypt.c b/sshauxcrypt.c index fae26207..c1da04a8 100644 --- a/sshauxcrypt.c +++ b/sshauxcrypt.c @@ -1,12 +1,12 @@ /* - * sshauxcrypt.c: wrapper functions on ciphers for use in other - * contexts than the main SSH packet protocol, such as encrypting - * private key files and performing XDM-AUTHORIZATION-1. + * sshauxcrypt.c: wrapper functions on crypto primitives for use in + * other contexts than the main SSH packet protocol, such as + * encrypting private key files and performing XDM-AUTHORIZATION-1. * - * These all work through the standard cipher APIs, so they don't need - * to live in the same actual source files as the ciphers they wrap, - * and I think it keeps things tidier to have them out of the way here - * instead. + * These all work through the standard cipher/hash/MAC APIs, so they + * don't need to live in the same actual source files as the ciphers + * they wrap, and I think it keeps things tidier to have them out of + * the way here instead. */ #include "ssh.h" @@ -150,3 +150,19 @@ void des_decrypt_xdmauth(const void *keydata, void *blk, int len) ssh_cipher_free(c); } +void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output) +{ + ssh_hash *hash = ssh_hash_new(alg); + put_datapl(hash, data); + ssh_hash_final(hash, output); +} + +void mac_simple(const ssh2_macalg *alg, ptrlen key, ptrlen data, void *output) +{ + ssh2_mac *mac = ssh2_mac_new(alg, NULL); + ssh2_mac_setkey(mac, key); + ssh2_mac_start(mac); + put_datapl(mac, data); + ssh2_mac_genresult(mac, output); + ssh2_mac_free(mac); +} diff --git a/sshbcrypt.c b/sshbcrypt.c index c4584618..7cdd44ed 100644 --- a/sshbcrypt.c +++ b/sshbcrypt.c @@ -54,20 +54,18 @@ void bcrypt_genblock(int counter, const unsigned char *salt, int saltbytes, unsigned char output[32]) { - SHA512_State shastate; unsigned char hashed_salt[64]; /* Hash the input salt with the counter value optionally suffixed * to get our real 32-byte salt */ - SHA512_Init(&shastate); - put_data(&shastate, salt, saltbytes); + ssh_hash *h = ssh_hash_new(&ssh_sha512); + put_data(h, salt, saltbytes); if (counter) - put_uint32(&shastate, counter); - SHA512_Final(&shastate, hashed_salt); + put_uint32(h, counter); + ssh_hash_final(h, hashed_salt); bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output); - smemclr(&shastate, sizeof(shastate)); smemclr(&hashed_salt, sizeof(hashed_salt)); } @@ -82,7 +80,7 @@ void openssh_bcrypt(const char *passphrase, int modulus, residue, i, j, round; /* Hash the passphrase to get the bcrypt key material */ - SHA512_Simple(passphrase, strlen(passphrase), hashed_passphrase); + hash_simple(&ssh_sha512, ptrlen_from_asciz(passphrase), hashed_passphrase); /* We output key bytes in a scattered fashion to meld all output * key blocks into all parts of the output. To do this, we pick a diff --git a/sshcommon.c b/sshcommon.c index 42f74da7..89763e8e 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -1008,15 +1008,14 @@ void ssh1_compute_session_id( unsigned char *session_id, const unsigned char *cookie, RSAKey *hostkey, RSAKey *servkey) { - struct MD5Context md5c; + ssh_hash *hash = ssh_hash_new(&ssh_md5); - MD5Init(&md5c); for (size_t i = (mp_get_nbits(hostkey->modulus) + 7) / 8; i-- ;) - put_byte(&md5c, mp_get_byte(hostkey->modulus, i)); + put_byte(hash, mp_get_byte(hostkey->modulus, i)); for (size_t i = (mp_get_nbits(servkey->modulus) + 7) / 8; i-- ;) - put_byte(&md5c, mp_get_byte(servkey->modulus, i)); - put_data(&md5c, cookie, 8); - MD5Final(session_id, &md5c); + put_byte(hash, mp_get_byte(servkey->modulus, i)); + put_data(hash, cookie, 8); + ssh_hash_final(hash, session_id); } /* ---------------------------------------------------------------------- diff --git a/sshdss.c b/sshdss.c index 439ef701..cb7a7a80 100644 --- a/sshdss.c +++ b/sshdss.c @@ -145,7 +145,7 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data) /* * Step 2. u1 <- SHA(message) * w mod q. */ - SHA_Simple(data.ptr, data.len, hash); + hash_simple(&ssh_sha1, data, hash); mp_int *sha = mp_from_bytes_be(make_ptrlen(hash, 20)); mp_int *u1 = mp_modmul(sha, w, dss->q); @@ -206,7 +206,6 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) ssh_key *sshk; struct dss_key *dss; ptrlen hash; - SHA_State s; unsigned char digest[20]; mp_int *ytest; @@ -227,11 +226,11 @@ static ssh_key *dss_new_priv(const ssh_keyalg *self, ptrlen pub, ptrlen priv) */ hash = get_string(src); if (hash.len == 20) { - SHA_Init(&s); - put_mp_ssh2(&s, dss->p); - put_mp_ssh2(&s, dss->q); - put_mp_ssh2(&s, dss->g); - SHA_Final(&s, digest); + ssh_hash *h = ssh_hash_new(&ssh_sha1); + put_mp_ssh2(h, dss->p); + put_mp_ssh2(h, dss->q); + put_mp_ssh2(h, dss->g); + ssh_hash_final(h, digest); if (!smemeq(hash.ptr, digest, 20)) { dss_freekey(&dss->sshk); return NULL; @@ -379,24 +378,24 @@ mp_int *dss_gen_k(const char *id_string, mp_int *modulus, * Computer Security Group for helping to argue out all the * fine details. */ - SHA512_State ss; + ssh_hash *h; unsigned char digest512[64]; /* * Hash some identifying text plus x. */ - SHA512_Init(&ss); - put_asciz(&ss, id_string); - put_mp_ssh2(&ss, private_key); - SHA512_Final(&ss, digest512); + h = ssh_hash_new(&ssh_sha512); + put_asciz(h, id_string); + put_mp_ssh2(h, private_key); + ssh_hash_final(h, digest512); /* * Now hash that digest plus the message hash. */ - SHA512_Init(&ss); - put_data(&ss, digest512, sizeof(digest512)); - put_data(&ss, digest, digest_len); - SHA512_Final(&ss, digest512); + h = ssh_hash_new(&ssh_sha512); + put_data(h, digest512, sizeof(digest512)); + put_data(h, digest, digest_len); + ssh_hash_final(h, digest512); /* * Now convert the result into a bignum, and coerce it to the @@ -410,7 +409,6 @@ mp_int *dss_gen_k(const char *id_string, mp_int *modulus, mp_free(modminus2); mp_add_integer_into(k, k, 2); - smemclr(&ss, sizeof(ss)); smemclr(digest512, sizeof(digest512)); return k; @@ -422,7 +420,7 @@ static void dss_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs) unsigned char digest[20]; int i; - SHA_Simple(data.ptr, data.len, digest); + hash_simple(&ssh_sha1, data, digest); mp_int *k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x, digest, sizeof(digest)); diff --git a/sshecc.c b/sshecc.c index f18a4b37..d5dafb59 100644 --- a/sshecc.c +++ b/sshecc.c @@ -994,7 +994,7 @@ static void ecdsa_sign(ssh_key *key, ptrlen data, mp_int *k; { unsigned char digest[20]; - SHA_Simple(data.ptr, data.len, digest); + hash_simple(&ssh_sha1, data, digest); k = dss_gen_k( "ECDSA deterministic k generator", ek->curve->w.G_order, ek->privateKey, digest, sizeof(digest)); diff --git a/sshmd5.c b/sshmd5.c index 5935a8a4..36b4c89e 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -6,6 +6,18 @@ * Simon Tatham. */ +typedef struct { + uint32_t h[4]; +} MD5_Core_State; + +struct MD5Context { + MD5_Core_State core; + unsigned char block[64]; + int blkused; + uint64_t len; + BinarySink_IMPLEMENTATION; +}; + /* ---------------------------------------------------------------------- * Core MD5 algorithm: processes 16-word blocks into a message digest. */ diff --git a/sshpubk.c b/sshpubk.c index 17c1b4da..1bd3fc59 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -31,7 +31,6 @@ static int rsa_ssh1_load_main(FILE * fp, RSAKey *key, bool pub_only, strbuf *buf; int ciphertype; int ret = 0; - struct MD5Context md5c; ptrlen comment; BinarySource src[1]; @@ -96,9 +95,7 @@ static int rsa_ssh1_load_main(FILE * fp, RSAKey *key, bool pub_only, if (enclen & 7) goto end; - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - MD5Final(keybuf, &md5c); + hash_simple(&ssh_md5, ptrlen_from_asciz(passphrase), keybuf); des3_decrypt_pubkey(keybuf, buf->u + src->pos, enclen); smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ } @@ -363,12 +360,11 @@ bool rsa_ssh1_savekey(const Filename *filename, RSAKey *key, * Now encrypt the encrypted portion. */ if (passphrase) { - struct MD5Context md5c; unsigned char keybuf[16]; - MD5Init(&md5c); - put_data(&md5c, passphrase, strlen(passphrase)); - MD5Final(keybuf, &md5c); + ssh_hash *h = ssh_hash_new(&ssh_md5); + put_data(h, passphrase, strlen(passphrase)); + ssh_hash_final(h, keybuf); des3_encrypt_pubkey(keybuf, buf->u + estart, buf->len - estart); smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ } @@ -588,6 +584,19 @@ const ssh_keyalg *find_pubkey_alg(const char *name) return find_pubkey_alg_len(ptrlen_from_asciz(name)); } +static void ssh2_ppk_derivekey(ptrlen passphrase, uint8_t *key) +{ + ssh_hash *h; + h = ssh_hash_new(&ssh_sha1); + put_uint32(h, 0); + put_datapl(h, passphrase); + ssh_hash_final(h, key + 0); + h = ssh_hash_new(&ssh_sha1); + put_uint32(h, 1); + put_datapl(h, passphrase); + ssh_hash_final(h, key + 20); +} + ssh2_userkey *ssh2_load_userkey( const Filename *filename, const char *passphrase, const char **errorstr) { @@ -708,21 +717,13 @@ ssh2_userkey *ssh2_load_userkey( */ if (cipher) { unsigned char key[40]; - SHA_State s; if (!passphrase) goto error; if (private_blob->len % cipherblk) goto error; - SHA_Init(&s); - put_uint32(&s, 0); - put_data(&s, passphrase, passlen); - SHA_Final(&s, key + 0); - SHA_Init(&s); - put_uint32(&s, 1); - put_data(&s, passphrase, passlen); - SHA_Final(&s, key + 20); + ssh2_ppk_derivekey(ptrlen_from_asciz(passphrase), key); aes256_decrypt_pubkey(key, private_blob->u, private_blob->len); } @@ -752,23 +753,27 @@ ssh2_userkey *ssh2_load_userkey( } if (is_mac) { - SHA_State s; + ssh_hash *hash; + ssh2_mac *mac; unsigned char mackey[20]; char header[] = "putty-private-key-file-mac-key"; - SHA_Init(&s); - put_data(&s, header, sizeof(header)-1); + hash = ssh_hash_new(&ssh_sha1); + put_data(hash, header, sizeof(header)-1); if (cipher && passphrase) - put_data(&s, passphrase, passlen); - SHA_Final(&s, mackey); + put_data(hash, passphrase, passlen); + ssh_hash_final(hash, mackey); - hmac_sha1_simple(mackey, 20, macdata->s, - macdata->len, binary); + mac = ssh2_mac_new(&ssh_hmac_sha1, NULL); + ssh2_mac_setkey(mac, make_ptrlen(mackey, 20)); + ssh2_mac_start(mac); + put_data(mac, macdata->s, macdata->len); + ssh2_mac_genresult(mac, binary); + ssh2_mac_free(mac); smemclr(mackey, sizeof(mackey)); - smemclr(&s, sizeof(s)); } else { - SHA_Simple(macdata->s, macdata->len, binary); + hash_simple(&ssh_sha1, ptrlen_from_strbuf(macdata), binary); } if (free_macdata) @@ -1241,7 +1246,6 @@ bool ssh2_save_userkey( strbuf *pub_blob, *priv_blob; unsigned char *priv_blob_encrypted; int priv_encrypted_len; - int passlen; int cipherblk; int i; const char *cipherstr; @@ -1272,7 +1276,7 @@ bool ssh2_save_userkey( memcpy(priv_blob_encrypted, priv_blob->u, priv_blob->len); /* Create padding based on the SHA hash of the unpadded blob. This prevents * too easy a known-plaintext attack on the last block. */ - SHA_Simple(priv_blob->u, priv_blob->len, priv_mac); + hash_simple(&ssh_sha1, ptrlen_from_strbuf(priv_blob), priv_mac); assert(priv_encrypted_len - priv_blob->len < 20); memcpy(priv_blob_encrypted + priv_blob->len, priv_mac, priv_encrypted_len - priv_blob->len); @@ -1280,7 +1284,6 @@ bool ssh2_save_userkey( /* Now create the MAC. */ { strbuf *macdata; - SHA_State s; unsigned char mackey[20]; char header[] = "putty-private-key-file-mac-key"; @@ -1291,37 +1294,24 @@ bool ssh2_save_userkey( put_string(macdata, pub_blob->s, pub_blob->len); put_string(macdata, priv_blob_encrypted, priv_encrypted_len); - SHA_Init(&s); - put_data(&s, header, sizeof(header)-1); + ssh_hash *h = ssh_hash_new(&ssh_sha1); + put_data(h, header, sizeof(header)-1); if (passphrase) - put_data(&s, passphrase, strlen(passphrase)); - SHA_Final(&s, mackey); - hmac_sha1_simple(mackey, 20, macdata->s, - macdata->len, priv_mac); + put_data(h, passphrase, strlen(passphrase)); + ssh_hash_final(h, mackey); + mac_simple(&ssh_hmac_sha1, make_ptrlen(mackey, 20), + ptrlen_from_strbuf(macdata), priv_mac); strbuf_free(macdata); smemclr(mackey, sizeof(mackey)); - smemclr(&s, sizeof(s)); } if (passphrase) { unsigned char key[40]; - SHA_State s; - passlen = strlen(passphrase); - - SHA_Init(&s); - put_uint32(&s, 0); - put_data(&s, passphrase, passlen); - SHA_Final(&s, key + 0); - SHA_Init(&s); - put_uint32(&s, 1); - put_data(&s, passphrase, passlen); - SHA_Final(&s, key + 20); - aes256_encrypt_pubkey(key, priv_blob_encrypted, - priv_encrypted_len); + ssh2_ppk_derivekey(ptrlen_from_asciz(passphrase), key); + aes256_encrypt_pubkey(key, priv_blob_encrypted, priv_encrypted_len); smemclr(key, sizeof(key)); - smemclr(&s, sizeof(s)); } fp = f_open(filename, "w", true); @@ -1496,7 +1486,7 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen) /* * The fingerprint hash itself is always just the MD5 of the blob. */ - MD5Simple(blob, bloblen, digest); + hash_simple(&ssh_md5, make_ptrlen(blob, bloblen), digest); for (i = 0; i < 16; i++) sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":"); diff --git a/sshrsa.c b/sshrsa.c index fac01faf..a7419393 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -232,7 +232,6 @@ char *rsastr_fmt(RSAKey *key) */ char *rsa_ssh1_fingerprint(RSAKey *key) { - struct MD5Context md5c; unsigned char digest[16]; strbuf *out; int i; @@ -245,12 +244,12 @@ char *rsa_ssh1_fingerprint(RSAKey *key) * between them. */ - MD5Init(&md5c); + ssh_hash *hash = ssh_hash_new(&ssh_md5); for (size_t i = (mp_get_nbits(key->modulus) + 7) / 8; i-- > 0 ;) - put_byte(&md5c, mp_get_byte(key->modulus, i)); + put_byte(hash, mp_get_byte(key->modulus, i)); for (size_t i = (mp_get_nbits(key->exponent) + 7) / 8; i-- > 0 ;) - put_byte(&md5c, mp_get_byte(key->exponent, i)); - MD5Final(digest, &md5c); + put_byte(hash, mp_get_byte(key->exponent, i)); + ssh_hash_final(hash, digest); out = strbuf_new(); strbuf_catf(out, "%d ", mp_get_nbits(key->modulus)); diff --git a/sshsh256.c b/sshsh256.c index 8081d772..f9fd4e0a 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -20,8 +20,17 @@ #define smallsigma0(x) ( ror((x),7) ^ ror((x),18) ^ shr((x),3) ) #define smallsigma1(x) ( ror((x),17) ^ ror((x),19) ^ shr((x),10) ) +typedef struct SHA256_State { + uint32_t h[8]; + unsigned char block[64]; + int blkused; + uint64_t len; + void (*sha256)(struct SHA256_State * s, const unsigned char *p, int len); + BinarySink_IMPLEMENTATION; +} SHA256_State; + static void SHA256_sw(SHA256_State *s, const unsigned char *q, int len); -static void SHA256_ni(SHA256_State * s, const unsigned char *q, int len); +static void SHA256_ni(SHA256_State *s, const unsigned char *q, int len); void SHA256_Core_Init(SHA256_State *s) { s->h[0] = 0x6a09e667; diff --git a/sshsh512.c b/sshsh512.c index 04174c62..7e27d738 100644 --- a/sshsh512.c +++ b/sshsh512.c @@ -11,6 +11,14 @@ #define BLKSIZE 128 +typedef struct { + uint64_t h[8]; + unsigned char block[128]; + int blkused; + uint64_t lenhi, lenlo; + BinarySink_IMPLEMENTATION; +} SHA512_State; + /* * Arithmetic implementations. Note that AND, XOR and NOT can * overlap destination with one source, but the others can't. diff --git a/sshsha.c b/sshsha.c index 573a9096..f41740f7 100644 --- a/sshsha.c +++ b/sshsha.c @@ -9,6 +9,15 @@ #include +typedef struct SHA_State { + uint32_t h[5]; + unsigned char block[64]; + int blkused; + uint64_t len; + void (*sha1)(struct SHA_State * s, const unsigned char *p, int len); + BinarySink_IMPLEMENTATION; +} SHA_State; + /* ---------------------------------------------------------------------- * Core SHA algorithm: processes 16-word blocks into a message digest. */ diff --git a/unix/uxshare.c b/unix/uxshare.c index d11d6bb8..b610eb53 100644 --- a/unix/uxshare.c +++ b/unix/uxshare.c @@ -211,14 +211,13 @@ static char *make_dirname(const char *pi_name, char **logtext) * identifier to produce our actual socket name. */ { - SHA256_State sha; unsigned char digest[32]; char retbuf[65]; - SHA256_Init(&sha); - put_string(&sha, saltbuf, SALT_SIZE); - put_stringz(&sha, pi_name); - SHA256_Final(&sha, digest); + ssh_hash *h = ssh_hash_new(&ssh_sha256); + put_string(h, saltbuf, SALT_SIZE); + put_stringz(h, pi_name); + ssh_hash_final(h, digest); /* * And make it printable. diff --git a/windows/winshare.c b/windows/winshare.c index 6498cc4e..7f4af869 100644 --- a/windows/winshare.c +++ b/windows/winshare.c @@ -47,7 +47,6 @@ static char *obfuscate_name(const char *realname) */ char *cryptdata; int cryptlen; - SHA256_State sha; unsigned char digest[32]; char retbuf[65]; int i; @@ -87,9 +86,11 @@ static char *obfuscate_name(const char *realname) * We don't want to give away the length of the hostname either, * so having got it back out of CryptProtectMemory we now hash it. */ - SHA256_Init(&sha); - put_string(&sha, cryptdata, cryptlen); - SHA256_Final(&sha, digest); + { + ssh_hash *h = ssh_hash_new(&ssh_sha256); + put_string(h, cryptdata, cryptlen); + ssh_hash_final(h, digest); + } sfree(cryptdata);