Pārlūkot izejas kodu

Merge branch 'thirdparty_dev' into dev

# Conflicts:
#	source/putty/ssh.h
#	source/putty/sshcommon.c
#	source/putty/sshdss.c
#	source/putty/sshrsa.c

Source commit: 279be49445e0e6c35b59ad864f1a547d85e652e4
Martin Prikryl 6 gadi atpakaļ
vecāks
revīzija
55b817908e

+ 8 - 15
source/putty/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;
-
-    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);
-    }
+    ptrlen key = ptrlen_from_asciz(passwd);
+    unsigned char md5buf[16];
 
-    hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response);
-    hmacmd5_free_context(hmacmd5_ctx);
+    if (key.len > 64) {
+        hash_simple(&ssh_md5, key, md5buf);
+        key = make_ptrlen(md5buf, 16);
+    }
+    mac_simple(&ssh_hmac_md5, key, make_ptrlen(challenge, challen), response);
+    smemclr(md5buf, sizeof(md5buf));
 }
 
 void proxy_socks5_offerencryptedauth(BinarySink *bs)

+ 56 - 73
source/putty/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));
     }
 

+ 9 - 66
source/putty/ssh.h

@@ -568,29 +568,6 @@ struct ssh_cipher {
 };
 
 #ifndef WINSCP_VS
-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);
 
 #ifdef MPEXT
@@ -603,50 +580,8 @@ bool supports_sha_ni(void);
 #define SHA512_Final putty_SHA512_Final
 #endif
 
-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);
 #endif // WINSCP_VS
-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;
 #ifndef WINSCP_VS
-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);
-
 #endif
 
 struct ssh_cipheralg {
@@ -731,11 +666,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;
@@ -756,6 +697,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;

+ 4 - 5
source/putty/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(

+ 23 - 7
source/putty/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"
@@ -154,3 +154,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);
+}

+ 5 - 7
source/putty/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

+ 5 - 6
source/putty/sshcommon.c

@@ -1041,16 +1041,15 @@ 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);
     size_t i; // WINSCP
 
-    MD5Init(&md5c);
     for (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 (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);
 }
 
 /* ----------------------------------------------------------------------

+ 16 - 18
source/putty/sshdss.c

@@ -149,7 +149,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);
     { // WINSCP
     mp_int *sha = mp_from_bytes_be(make_ptrlen(hash, 20));
     mp_int *u1 = mp_modmul(sha, w, dss->q);
@@ -214,7 +214,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;
 
@@ -235,11 +234,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;
@@ -387,24 +386,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
@@ -420,7 +419,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;
@@ -434,7 +432,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);
 
     { // WINSCP
     mp_int *k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x,

+ 1 - 1
source/putty/sshecc.c

@@ -1161,7 +1161,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));

+ 12 - 0
source/putty/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.
  */

+ 41 - 51
source/putty/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)
@@ -1271,7 +1276,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;
@@ -1302,7 +1306,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);
@@ -1310,7 +1314,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";
 
@@ -1321,37 +1324,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);
@@ -1527,7 +1517,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_md5 + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
 

+ 4 - 6
source/putty/sshrsa.c

@@ -241,7 +241,6 @@ char *rsastr_fmt(RSAKey *key)
  */
 char *rsa_ssh1_fingerprint(RSAKey *key)
 {
-    struct MD5Context md5c;
     unsigned char digest[16];
     strbuf *out;
     int i;
@@ -254,15 +253,15 @@ char *rsa_ssh1_fingerprint(RSAKey *key)
      * between them.
      */
 
-    MD5Init(&md5c);
+    ssh_hash *hash = ssh_hash_new(&ssh_md5);
     { // WINSCP
     size_t i; // WINSCP
     for (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 (i = (mp_get_nbits(key->exponent) + 7) / 8; i-- > 0 ;)
-        put_byte(&md5c, mp_get_byte(key->exponent, i));
+        put_byte(hash, mp_get_byte(key->exponent, i));
     } // WINSCP
-    MD5Final(digest, &md5c);
+    ssh_hash_final(hash, digest);
 
     out = strbuf_new();
     strbuf_catf(out, "%d ", mp_get_nbits(key->modulus));
@@ -703,7 +702,6 @@ static void rsa2_sign(ssh_key *key, ptrlen data,
 
     put_stringz(bs, sign_alg_name);
     nbytes = (mp_get_nbits(out) + 7) / 8;
-
     put_uint32(bs, nbytes);
     { // WINSCP
     size_t i; // WINSCP

+ 10 - 1
source/putty/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);
 
 #ifndef WINSCP_VS
 

+ 8 - 0
source/putty/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.

+ 9 - 0
source/putty/sshsha.c

@@ -9,6 +9,15 @@
 
 #include <assert.h>
 
+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.
  */