1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Access all hashes and MACs through the standard API.

All the hash-specific state structures, and the functions that
directly accessed them, are now local to the source files implementing
the hashes themselves. Everywhere we previously used those types or
functions, we're now using the standard ssh_hash or ssh2_mac API.

The 'simple' functions (hmacmd5_simple, SHA_Simple etc) are now a pair
of wrappers in sshauxcrypt.c, each of which takes an algorithm
structure and can do the same conceptual thing regardless of what it
is.
This commit is contained in:
Simon Tatham 2019-01-20 16:15:14 +00:00
parent acdcf2bfaa
commit 0d2d20aad0
19 changed files with 232 additions and 274 deletions

View File

@ -18,22 +18,15 @@
static void hmacmd5_chap(const unsigned char *challenge, int challen, static void hmacmd5_chap(const unsigned char *challenge, int challen,
const char *passwd, unsigned char *response) const char *passwd, unsigned char *response)
{ {
struct hmacmd5_context *hmacmd5_ctx; ptrlen key = ptrlen_from_asciz(passwd);
int pwlen; unsigned char md5buf[16];
hmacmd5_ctx = hmacmd5_make_context(); if (key.len > 64) {
hash_simple(&ssh_md5, key, md5buf);
pwlen = strlen(passwd); key = make_ptrlen(md5buf, 16);
if (pwlen>64) {
unsigned char md5buf[16];
MD5Simple(passwd, pwlen, md5buf);
hmacmd5_key(hmacmd5_ctx, md5buf, 16);
} else {
hmacmd5_key(hmacmd5_ctx, passwd, pwlen);
} }
mac_simple(&ssh_hmac_md5, key, make_ptrlen(challenge, challen), response);
hmacmd5_do_hmac(hmacmd5_ctx, challenge, challen, response); smemclr(md5buf, sizeof(md5buf));
hmacmd5_free_context(hmacmd5_ctx);
} }
void proxy_socks5_offerencryptedauth(BinarySink *bs) void proxy_socks5_offerencryptedauth(BinarySink *bs)

129
import.c
View File

@ -495,6 +495,36 @@ static bool openssh_pem_encrypted(const Filename *filename)
return ret; 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( static ssh2_userkey *openssh_pem_read(
const Filename *filename, const char *passphrase, const char **errmsg_p) const Filename *filename, const char *passphrase, const char **errmsg_p)
{ {
@ -514,34 +544,11 @@ static ssh2_userkey *openssh_pem_read(
return NULL; return NULL;
if (key->encrypted) { 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]; unsigned char keybuf[32];
openssh_pem_derivekey(ptrlen_from_asciz(passphrase), key->iv, keybuf);
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);
/* /*
* Now decrypt the key blob. * Decrypt the key blob.
*/ */
if (key->encryption == OP_E_3DES) if (key->encryption == OP_E_3DES)
des3_decrypt_pubkey_ossh(keybuf, key->iv, des3_decrypt_pubkey_ossh(keybuf, key->iv,
@ -554,7 +561,6 @@ static ssh2_userkey *openssh_pem_read(
ssh_cipher_free(cipher); ssh_cipher_free(cipher);
} }
smemclr(&md5c, sizeof(md5c));
smemclr(keybuf, sizeof(keybuf)); smemclr(keybuf, sizeof(keybuf));
} }
@ -981,7 +987,6 @@ static bool openssh_pem_write(
* old-style 3DES. * old-style 3DES.
*/ */
if (passphrase) { if (passphrase) {
struct MD5Context md5c;
unsigned char keybuf[32]; unsigned char keybuf[32];
int origlen, outlen, pad, i; int origlen, outlen, pad, i;
@ -1008,26 +1013,11 @@ static bool openssh_pem_write(
put_padding(outblob, pad, pad); put_padding(outblob, pad, pad);
/* /*
* Invent an iv. Then derive encryption key from passphrase * Invent an iv, and derive the encryption key.
* 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
*/ */
for (i = 0; i < 8; i++) iv[i] = random_byte(); for (i = 0; i < 8; i++) iv[i] = random_byte();
MD5Init(&md5c); openssh_pem_derivekey(ptrlen_from_asciz(passphrase), iv, keybuf);
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);
/* /*
* Now encrypt the key blob. * Now encrypt the key blob.
@ -1035,7 +1025,6 @@ static bool openssh_pem_write(
des3_encrypt_pubkey_ossh(keybuf, iv, des3_encrypt_pubkey_ossh(keybuf, iv,
outblob->u, outlen); outblob->u, outlen);
smemclr(&md5c, sizeof(md5c));
smemclr(keybuf, sizeof(keybuf)); 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) \ #define get_mp_sshcom_as_string(bs) \
BinarySource_get_mp_sshcom_as_string(BinarySource_UPCAST(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( static ssh2_userkey *sshcom_read(
const Filename *filename, const char *passphrase, const char **errmsg_p) 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 * - block C would be MD5(passphrase || A || B) and so on
* - encryption key is the first N bytes of A || B * - encryption key is the first N bytes of A || B
*/ */
struct MD5Context md5c;
unsigned char keybuf[32], iv[8]; unsigned char keybuf[32], iv[8];
if (ciphertext.len % 8 != 0) { if (ciphertext.len % 8 != 0) {
@ -2044,14 +2052,7 @@ static ssh2_userkey *sshcom_read(
goto error; goto error;
} }
MD5Init(&md5c); sshcom_derivekey(ptrlen_from_asciz(passphrase), keybuf);
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);
/* /*
* Now decrypt the key blob in place (casting away const from * 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, des3_decrypt_pubkey_ossh(keybuf, iv,
(char *)ciphertext.ptr, ciphertext.len); (char *)ciphertext.ptr, ciphertext.len);
smemclr(&md5c, sizeof(md5c));
smemclr(keybuf, sizeof(keybuf)); smemclr(keybuf, sizeof(keybuf));
/* /*
@ -2294,25 +2294,9 @@ static bool sshcom_write(
* Encrypt the key. * Encrypt the key.
*/ */
if (passphrase) { 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]; unsigned char keybuf[32], iv[8];
MD5Init(&md5c); sshcom_derivekey(ptrlen_from_asciz(passphrase), keybuf);
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);
/* /*
* Now decrypt the key blob. * Now decrypt the key blob.
@ -2320,7 +2304,6 @@ static bool sshcom_write(
memset(iv, 0, sizeof(iv)); memset(iv, 0, sizeof(iv));
des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen); des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
smemclr(&md5c, sizeof(md5c));
smemclr(keybuf, sizeof(keybuf)); smemclr(keybuf, sizeof(keybuf));
} }

View File

@ -228,7 +228,6 @@ void pageant_handle_msg(BinarySink *bs,
ptrlen session_id; ptrlen session_id;
unsigned response_type; unsigned response_type;
unsigned char response_md5[16]; unsigned char response_md5[16];
struct MD5Context md5c;
int i; int i;
plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE"); plog(logctx, logfn, "request: SSH1_AGENTC_RSA_CHALLENGE");
@ -266,11 +265,13 @@ void pageant_handle_msg(BinarySink *bs,
} }
response = rsa_ssh1_decrypt(challenge, key); response = rsa_ssh1_decrypt(challenge, key);
MD5Init(&md5c); {
for (i = 0; i < 32; i++) ssh_hash *h = ssh_hash_new(&ssh_md5);
put_byte(&md5c, mp_get_byte(response, 31 - i)); for (i = 0; i < 32; i++)
put_datapl(&md5c, session_id); put_byte(h, mp_get_byte(response, 31 - i));
MD5Final(response_md5, &md5c); put_datapl(h, session_id);
ssh_hash_final(h, response_md5);
}
put_byte(bs, SSH1_AGENT_RSA_RESPONSE); put_byte(bs, SSH1_AGENT_RSA_RESPONSE);
put_data(bs, response_md5, 16); put_data(bs, response_md5, 16);

75
ssh.h
View File

@ -558,73 +558,8 @@ struct ssh_cipher {
const ssh_cipheralg *vt; 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); 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 { struct ssh_cipheralg {
ssh_cipher *(*new)(const ssh_cipheralg *alg); ssh_cipher *(*new)(const ssh_cipheralg *alg);
void (*free)(ssh_cipher *); 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_genresult(ctx, out) ((ctx)->vt->genresult(ctx, out))
#define ssh2_mac_alg(ctx) ((ctx)->vt) #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 *); bool ssh2_mac_verresult(ssh2_mac *, const void *);
void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq); void ssh2_mac_generate(ssh2_mac *, void *, int, unsigned long seq);
bool ssh2_mac_verify(ssh2_mac *, const 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 { struct ssh_hash {
const ssh_hashalg *vt; const ssh_hashalg *vt;
BinarySink_DELEGATE_IMPLEMENTATION; BinarySink_DELEGATE_IMPLEMENTATION;
@ -729,6 +670,8 @@ struct ssh_hashalg {
#define ssh_hash_free(ctx) ((ctx)->vt->free(ctx)) #define ssh_hash_free(ctx) ((ctx)->vt->free(ctx))
#define ssh_hash_alg(ctx) ((ctx)->vt) #define ssh_hash_alg(ctx) ((ctx)->vt)
void hash_simple(const ssh_hashalg *alg, ptrlen data, void *output);
struct ssh_kex { struct ssh_kex {
const char *name, *groupname; const char *name, *groupname;
enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type; enum { KEXTYPE_DH, KEXTYPE_RSA, KEXTYPE_ECDH, KEXTYPE_GSS } main_type;

View File

@ -306,15 +306,16 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl)
{ {
unsigned char *rsabuf = unsigned char *rsabuf =
snewn(s->authkey->bytes, unsigned char); snewn(s->authkey->bytes, unsigned char);
struct MD5Context md5c;
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
rsabuf[i] = random_byte(); rsabuf[i] = random_byte();
MD5Init(&md5c); {
put_data(&md5c, rsabuf, 32); ssh_hash *h = ssh_hash_new(&ssh_md5);
put_data(&md5c, s->session_id, 16); put_data(h, rsabuf, 32);
MD5Final(s->auth_rsa_expected_response, &md5c); put_data(h, s->session_id, 16);
ssh_hash_final(h, s->auth_rsa_expected_response);
}
if (!rsa_ssh1_encrypt(rsabuf, 32, s->authkey)) { if (!rsa_ssh1_encrypt(rsabuf, 32, s->authkey)) {
sfree(rsabuf); sfree(rsabuf);

View File

@ -737,11 +737,10 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
} }
{ {
struct MD5Context md5c; ssh_hash *h = ssh_hash_new(&ssh_md5);
MD5Init(&md5c); put_data(h, buffer, 32);
put_data(&md5c, buffer, 32); put_data(h, s->session_id, 16);
put_data(&md5c, s->session_id, 16); ssh_hash_final(h, buffer);
MD5Final(buffer, &md5c);
} }
pkt = ssh_bpp_new_pktout( pkt = ssh_bpp_new_pktout(

View File

@ -1,12 +1,12 @@
/* /*
* sshauxcrypt.c: wrapper functions on ciphers for use in other * sshauxcrypt.c: wrapper functions on crypto primitives for use in
* contexts than the main SSH packet protocol, such as encrypting * other contexts than the main SSH packet protocol, such as
* private key files and performing XDM-AUTHORIZATION-1. * encrypting private key files and performing XDM-AUTHORIZATION-1.
* *
* These all work through the standard cipher APIs, so they don't need * These all work through the standard cipher/hash/MAC APIs, so they
* to live in the same actual source files as the ciphers they wrap, * don't need to live in the same actual source files as the ciphers
* and I think it keeps things tidier to have them out of the way here * they wrap, and I think it keeps things tidier to have them out of
* instead. * the way here instead.
*/ */
#include "ssh.h" #include "ssh.h"
@ -150,3 +150,19 @@ void des_decrypt_xdmauth(const void *keydata, void *blk, int len)
ssh_cipher_free(c); 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);
}

View File

@ -54,20 +54,18 @@ void bcrypt_genblock(int counter,
const unsigned char *salt, int saltbytes, const unsigned char *salt, int saltbytes,
unsigned char output[32]) unsigned char output[32])
{ {
SHA512_State shastate;
unsigned char hashed_salt[64]; unsigned char hashed_salt[64];
/* Hash the input salt with the counter value optionally suffixed /* Hash the input salt with the counter value optionally suffixed
* to get our real 32-byte salt */ * to get our real 32-byte salt */
SHA512_Init(&shastate); ssh_hash *h = ssh_hash_new(&ssh_sha512);
put_data(&shastate, salt, saltbytes); put_data(h, salt, saltbytes);
if (counter) if (counter)
put_uint32(&shastate, counter); put_uint32(h, counter);
SHA512_Final(&shastate, hashed_salt); ssh_hash_final(h, hashed_salt);
bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output); bcrypt_hash(hashed_passphrase, 64, hashed_salt, 64, output);
smemclr(&shastate, sizeof(shastate));
smemclr(&hashed_salt, sizeof(hashed_salt)); smemclr(&hashed_salt, sizeof(hashed_salt));
} }
@ -82,7 +80,7 @@ void openssh_bcrypt(const char *passphrase,
int modulus, residue, i, j, round; int modulus, residue, i, j, round;
/* Hash the passphrase to get the bcrypt key material */ /* 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 /* 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 * key blocks into all parts of the output. To do this, we pick a

View File

@ -1008,15 +1008,14 @@ void ssh1_compute_session_id(
unsigned char *session_id, const unsigned char *cookie, unsigned char *session_id, const unsigned char *cookie,
RSAKey *hostkey, RSAKey *servkey) 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-- ;) 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-- ;) for (size_t i = (mp_get_nbits(servkey->modulus) + 7) / 8; i-- ;)
put_byte(&md5c, mp_get_byte(servkey->modulus, i)); put_byte(hash, mp_get_byte(servkey->modulus, i));
put_data(&md5c, cookie, 8); put_data(hash, cookie, 8);
MD5Final(session_id, &md5c); ssh_hash_final(hash, session_id);
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -145,7 +145,7 @@ static bool dss_verify(ssh_key *key, ptrlen sig, ptrlen data)
/* /*
* Step 2. u1 <- SHA(message) * w mod q. * 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 *sha = mp_from_bytes_be(make_ptrlen(hash, 20));
mp_int *u1 = mp_modmul(sha, w, dss->q); 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; ssh_key *sshk;
struct dss_key *dss; struct dss_key *dss;
ptrlen hash; ptrlen hash;
SHA_State s;
unsigned char digest[20]; unsigned char digest[20];
mp_int *ytest; 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); hash = get_string(src);
if (hash.len == 20) { if (hash.len == 20) {
SHA_Init(&s); ssh_hash *h = ssh_hash_new(&ssh_sha1);
put_mp_ssh2(&s, dss->p); put_mp_ssh2(h, dss->p);
put_mp_ssh2(&s, dss->q); put_mp_ssh2(h, dss->q);
put_mp_ssh2(&s, dss->g); put_mp_ssh2(h, dss->g);
SHA_Final(&s, digest); ssh_hash_final(h, digest);
if (!smemeq(hash.ptr, digest, 20)) { if (!smemeq(hash.ptr, digest, 20)) {
dss_freekey(&dss->sshk); dss_freekey(&dss->sshk);
return NULL; 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 * Computer Security Group for helping to argue out all the
* fine details. * fine details.
*/ */
SHA512_State ss; ssh_hash *h;
unsigned char digest512[64]; unsigned char digest512[64];
/* /*
* Hash some identifying text plus x. * Hash some identifying text plus x.
*/ */
SHA512_Init(&ss); h = ssh_hash_new(&ssh_sha512);
put_asciz(&ss, id_string); put_asciz(h, id_string);
put_mp_ssh2(&ss, private_key); put_mp_ssh2(h, private_key);
SHA512_Final(&ss, digest512); ssh_hash_final(h, digest512);
/* /*
* Now hash that digest plus the message hash. * Now hash that digest plus the message hash.
*/ */
SHA512_Init(&ss); h = ssh_hash_new(&ssh_sha512);
put_data(&ss, digest512, sizeof(digest512)); put_data(h, digest512, sizeof(digest512));
put_data(&ss, digest, digest_len); put_data(h, digest, digest_len);
SHA512_Final(&ss, digest512); ssh_hash_final(h, digest512);
/* /*
* Now convert the result into a bignum, and coerce it to the * 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_free(modminus2);
mp_add_integer_into(k, k, 2); mp_add_integer_into(k, k, 2);
smemclr(&ss, sizeof(ss));
smemclr(digest512, sizeof(digest512)); smemclr(digest512, sizeof(digest512));
return k; return k;
@ -422,7 +420,7 @@ static void dss_sign(ssh_key *key, ptrlen data, unsigned flags, BinarySink *bs)
unsigned char digest[20]; unsigned char digest[20];
int i; 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, mp_int *k = dss_gen_k("DSA deterministic k generator", dss->q, dss->x,
digest, sizeof(digest)); digest, sizeof(digest));

View File

@ -994,7 +994,7 @@ static void ecdsa_sign(ssh_key *key, ptrlen data,
mp_int *k; mp_int *k;
{ {
unsigned char digest[20]; unsigned char digest[20];
SHA_Simple(data.ptr, data.len, digest); hash_simple(&ssh_sha1, data, digest);
k = dss_gen_k( k = dss_gen_k(
"ECDSA deterministic k generator", ek->curve->w.G_order, "ECDSA deterministic k generator", ek->curve->w.G_order,
ek->privateKey, digest, sizeof(digest)); ek->privateKey, digest, sizeof(digest));

View File

@ -6,6 +6,18 @@
* Simon Tatham. * 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. * Core MD5 algorithm: processes 16-word blocks into a message digest.
*/ */

View File

@ -31,7 +31,6 @@ static int rsa_ssh1_load_main(FILE * fp, RSAKey *key, bool pub_only,
strbuf *buf; strbuf *buf;
int ciphertype; int ciphertype;
int ret = 0; int ret = 0;
struct MD5Context md5c;
ptrlen comment; ptrlen comment;
BinarySource src[1]; BinarySource src[1];
@ -96,9 +95,7 @@ static int rsa_ssh1_load_main(FILE * fp, RSAKey *key, bool pub_only,
if (enclen & 7) if (enclen & 7)
goto end; goto end;
MD5Init(&md5c); hash_simple(&ssh_md5, ptrlen_from_asciz(passphrase), keybuf);
put_data(&md5c, passphrase, strlen(passphrase));
MD5Final(keybuf, &md5c);
des3_decrypt_pubkey(keybuf, buf->u + src->pos, enclen); des3_decrypt_pubkey(keybuf, buf->u + src->pos, enclen);
smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ 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. * Now encrypt the encrypted portion.
*/ */
if (passphrase) { if (passphrase) {
struct MD5Context md5c;
unsigned char keybuf[16]; unsigned char keybuf[16];
MD5Init(&md5c); ssh_hash *h = ssh_hash_new(&ssh_md5);
put_data(&md5c, passphrase, strlen(passphrase)); put_data(h, passphrase, strlen(passphrase));
MD5Final(keybuf, &md5c); ssh_hash_final(h, keybuf);
des3_encrypt_pubkey(keybuf, buf->u + estart, buf->len - estart); des3_encrypt_pubkey(keybuf, buf->u + estart, buf->len - estart);
smemclr(keybuf, sizeof(keybuf)); /* burn the evidence */ 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)); 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( ssh2_userkey *ssh2_load_userkey(
const Filename *filename, const char *passphrase, const char **errorstr) const Filename *filename, const char *passphrase, const char **errorstr)
{ {
@ -708,21 +717,13 @@ ssh2_userkey *ssh2_load_userkey(
*/ */
if (cipher) { if (cipher) {
unsigned char key[40]; unsigned char key[40];
SHA_State s;
if (!passphrase) if (!passphrase)
goto error; goto error;
if (private_blob->len % cipherblk) if (private_blob->len % cipherblk)
goto error; goto error;
SHA_Init(&s); ssh2_ppk_derivekey(ptrlen_from_asciz(passphrase), key);
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_decrypt_pubkey(key, private_blob->u, private_blob->len); aes256_decrypt_pubkey(key, private_blob->u, private_blob->len);
} }
@ -752,23 +753,27 @@ ssh2_userkey *ssh2_load_userkey(
} }
if (is_mac) { if (is_mac) {
SHA_State s; ssh_hash *hash;
ssh2_mac *mac;
unsigned char mackey[20]; unsigned char mackey[20];
char header[] = "putty-private-key-file-mac-key"; char header[] = "putty-private-key-file-mac-key";
SHA_Init(&s); hash = ssh_hash_new(&ssh_sha1);
put_data(&s, header, sizeof(header)-1); put_data(hash, header, sizeof(header)-1);
if (cipher && passphrase) if (cipher && passphrase)
put_data(&s, passphrase, passlen); put_data(hash, passphrase, passlen);
SHA_Final(&s, mackey); ssh_hash_final(hash, mackey);
hmac_sha1_simple(mackey, 20, macdata->s, mac = ssh2_mac_new(&ssh_hmac_sha1, NULL);
macdata->len, binary); 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(mackey, sizeof(mackey));
smemclr(&s, sizeof(s));
} else { } else {
SHA_Simple(macdata->s, macdata->len, binary); hash_simple(&ssh_sha1, ptrlen_from_strbuf(macdata), binary);
} }
if (free_macdata) if (free_macdata)
@ -1241,7 +1246,6 @@ bool ssh2_save_userkey(
strbuf *pub_blob, *priv_blob; strbuf *pub_blob, *priv_blob;
unsigned char *priv_blob_encrypted; unsigned char *priv_blob_encrypted;
int priv_encrypted_len; int priv_encrypted_len;
int passlen;
int cipherblk; int cipherblk;
int i; int i;
const char *cipherstr; const char *cipherstr;
@ -1272,7 +1276,7 @@ bool ssh2_save_userkey(
memcpy(priv_blob_encrypted, priv_blob->u, priv_blob->len); memcpy(priv_blob_encrypted, priv_blob->u, priv_blob->len);
/* Create padding based on the SHA hash of the unpadded blob. This prevents /* Create padding based on the SHA hash of the unpadded blob. This prevents
* too easy a known-plaintext attack on the last block. */ * 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); assert(priv_encrypted_len - priv_blob->len < 20);
memcpy(priv_blob_encrypted + priv_blob->len, priv_mac, memcpy(priv_blob_encrypted + priv_blob->len, priv_mac,
priv_encrypted_len - priv_blob->len); priv_encrypted_len - priv_blob->len);
@ -1280,7 +1284,6 @@ bool ssh2_save_userkey(
/* Now create the MAC. */ /* Now create the MAC. */
{ {
strbuf *macdata; strbuf *macdata;
SHA_State s;
unsigned char mackey[20]; unsigned char mackey[20];
char header[] = "putty-private-key-file-mac-key"; 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, pub_blob->s, pub_blob->len);
put_string(macdata, priv_blob_encrypted, priv_encrypted_len); put_string(macdata, priv_blob_encrypted, priv_encrypted_len);
SHA_Init(&s); ssh_hash *h = ssh_hash_new(&ssh_sha1);
put_data(&s, header, sizeof(header)-1); put_data(h, header, sizeof(header)-1);
if (passphrase) if (passphrase)
put_data(&s, passphrase, strlen(passphrase)); put_data(h, passphrase, strlen(passphrase));
SHA_Final(&s, mackey); ssh_hash_final(h, mackey);
hmac_sha1_simple(mackey, 20, macdata->s, mac_simple(&ssh_hmac_sha1, make_ptrlen(mackey, 20),
macdata->len, priv_mac); ptrlen_from_strbuf(macdata), priv_mac);
strbuf_free(macdata); strbuf_free(macdata);
smemclr(mackey, sizeof(mackey)); smemclr(mackey, sizeof(mackey));
smemclr(&s, sizeof(s));
} }
if (passphrase) { if (passphrase) {
unsigned char key[40]; unsigned char key[40];
SHA_State s;
passlen = strlen(passphrase); ssh2_ppk_derivekey(ptrlen_from_asciz(passphrase), key);
aes256_encrypt_pubkey(key, priv_blob_encrypted, priv_encrypted_len);
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);
smemclr(key, sizeof(key)); smemclr(key, sizeof(key));
smemclr(&s, sizeof(s));
} }
fp = f_open(filename, "w", true); 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. * 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++) for (i = 0; i < 16; i++)
sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":"); sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");

View File

@ -232,7 +232,6 @@ char *rsastr_fmt(RSAKey *key)
*/ */
char *rsa_ssh1_fingerprint(RSAKey *key) char *rsa_ssh1_fingerprint(RSAKey *key)
{ {
struct MD5Context md5c;
unsigned char digest[16]; unsigned char digest[16];
strbuf *out; strbuf *out;
int i; int i;
@ -245,12 +244,12 @@ char *rsa_ssh1_fingerprint(RSAKey *key)
* between them. * 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 ;) 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 ;) for (size_t 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));
MD5Final(digest, &md5c); ssh_hash_final(hash, digest);
out = strbuf_new(); out = strbuf_new();
strbuf_catf(out, "%d ", mp_get_nbits(key->modulus)); strbuf_catf(out, "%d ", mp_get_nbits(key->modulus));

View File

@ -20,8 +20,17 @@
#define smallsigma0(x) ( ror((x),7) ^ ror((x),18) ^ shr((x),3) ) #define smallsigma0(x) ( ror((x),7) ^ ror((x),18) ^ shr((x),3) )
#define smallsigma1(x) ( ror((x),17) ^ ror((x),19) ^ shr((x),10) ) #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_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) { void SHA256_Core_Init(SHA256_State *s) {
s->h[0] = 0x6a09e667; s->h[0] = 0x6a09e667;

View File

@ -11,6 +11,14 @@
#define BLKSIZE 128 #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 * Arithmetic implementations. Note that AND, XOR and NOT can
* overlap destination with one source, but the others can't. * overlap destination with one source, but the others can't.

View File

@ -9,6 +9,15 @@
#include <assert.h> #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. * Core SHA algorithm: processes 16-word blocks into a message digest.
*/ */

View File

@ -211,14 +211,13 @@ static char *make_dirname(const char *pi_name, char **logtext)
* identifier to produce our actual socket name. * identifier to produce our actual socket name.
*/ */
{ {
SHA256_State sha;
unsigned char digest[32]; unsigned char digest[32];
char retbuf[65]; char retbuf[65];
SHA256_Init(&sha); ssh_hash *h = ssh_hash_new(&ssh_sha256);
put_string(&sha, saltbuf, SALT_SIZE); put_string(h, saltbuf, SALT_SIZE);
put_stringz(&sha, pi_name); put_stringz(h, pi_name);
SHA256_Final(&sha, digest); ssh_hash_final(h, digest);
/* /*
* And make it printable. * And make it printable.

View File

@ -47,7 +47,6 @@ static char *obfuscate_name(const char *realname)
*/ */
char *cryptdata; char *cryptdata;
int cryptlen; int cryptlen;
SHA256_State sha;
unsigned char digest[32]; unsigned char digest[32];
char retbuf[65]; char retbuf[65];
int i; 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, * 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. * so having got it back out of CryptProtectMemory we now hash it.
*/ */
SHA256_Init(&sha); {
put_string(&sha, cryptdata, cryptlen); ssh_hash *h = ssh_hash_new(&ssh_sha256);
SHA256_Final(&sha, digest); put_string(h, cryptdata, cryptlen);
ssh_hash_final(h, digest);
}
sfree(cryptdata); sfree(cryptdata);