mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Expose openssh_bcrypt() to testcrypt, and test it.
I happened to notice in passing that this function doesn't have any tests (although it will have been at least somewhat tested by the cmdgen interop test system). This involved writing a wrapper that passes the passphrase and salt as ptrlens, and I decided it made more sense to make the same change to the original function too and adjust the call sites appropriately. I derived a test case by getting OpenSSH itself to make an encrypted key file, and then using the inputs and output from the password hash operation that decrypted it again.
This commit is contained in:
parent
c1ddacf78f
commit
831accb2a9
@ -69,8 +69,7 @@ void bcrypt_genblock(int counter,
|
||||
smemclr(&hashed_salt, sizeof(hashed_salt));
|
||||
}
|
||||
|
||||
void openssh_bcrypt(const char *passphrase,
|
||||
const unsigned char *salt, int saltbytes,
|
||||
void openssh_bcrypt(ptrlen passphrase, ptrlen salt,
|
||||
int rounds, unsigned char *out, int outbytes)
|
||||
{
|
||||
unsigned char hashed_passphrase[64];
|
||||
@ -80,7 +79,7 @@ void openssh_bcrypt(const char *passphrase,
|
||||
int modulus, residue, i, j, round;
|
||||
|
||||
/* Hash the passphrase to get the bcrypt key material */
|
||||
hash_simple(&ssh_sha512, ptrlen_from_asciz(passphrase), hashed_passphrase);
|
||||
hash_simple(&ssh_sha512, 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
|
||||
@ -97,8 +96,8 @@ void openssh_bcrypt(const char *passphrase,
|
||||
* by bcrypt in the following loop */
|
||||
memset(outblock, 0, sizeof(outblock));
|
||||
|
||||
thissalt = salt;
|
||||
thissaltbytes = saltbytes;
|
||||
thissalt = salt.ptr;
|
||||
thissaltbytes = salt.len;
|
||||
for (round = 0; round < rounds; round++) {
|
||||
bcrypt_genblock(round == 0 ? residue+1 : 0,
|
||||
hashed_passphrase,
|
||||
|
11
import.c
11
import.c
@ -1363,9 +1363,8 @@ static ssh2_userkey *openssh_new_read(
|
||||
memset(keybuf, 0, keysize);
|
||||
break;
|
||||
case ON_K_BCRYPT:
|
||||
openssh_bcrypt(passphrase,
|
||||
key->kdfopts.bcrypt.salt.ptr,
|
||||
key->kdfopts.bcrypt.salt.len,
|
||||
openssh_bcrypt(ptrlen_from_asciz(passphrase),
|
||||
key->kdfopts.bcrypt.salt,
|
||||
key->kdfopts.bcrypt.rounds,
|
||||
keybuf, keysize);
|
||||
break;
|
||||
@ -1583,9 +1582,9 @@ static bool openssh_new_write(
|
||||
unsigned char keybuf[48];
|
||||
ssh_cipher *cipher;
|
||||
|
||||
openssh_bcrypt(passphrase,
|
||||
bcrypt_salt, sizeof(bcrypt_salt), bcrypt_rounds,
|
||||
keybuf, sizeof(keybuf));
|
||||
openssh_bcrypt(ptrlen_from_asciz(passphrase),
|
||||
make_ptrlen(bcrypt_salt, sizeof(bcrypt_salt)),
|
||||
bcrypt_rounds, keybuf, sizeof(keybuf));
|
||||
|
||||
cipher = ssh_cipher_new(&ssh_aes256_sdctr);
|
||||
ssh_cipher_setkey(cipher, keybuf);
|
||||
|
3
ssh.h
3
ssh.h
@ -1413,8 +1413,7 @@ void aes256_decrypt_pubkey(const void *key, const void *iv,
|
||||
void des_encrypt_xdmauth(const void *key, void *blk, int len);
|
||||
void des_decrypt_xdmauth(const void *key, void *blk, int len);
|
||||
|
||||
void openssh_bcrypt(const char *passphrase,
|
||||
const unsigned char *salt, int saltbytes,
|
||||
void openssh_bcrypt(ptrlen passphrase, ptrlen salt,
|
||||
int rounds, unsigned char *out, int outbytes);
|
||||
|
||||
/*
|
||||
|
@ -2106,6 +2106,20 @@ culpa qui officia deserunt mollit anim id est laborum.
|
||||
"aeae2a21201eef5e347de22c922192e8f46274b0c9d33e965155a91e7686"
|
||||
"9d530e"))
|
||||
|
||||
def testOpenSSHBcrypt(self):
|
||||
# Test case created by making an OpenSSH private key file
|
||||
# using their own ssh-keygen, then decrypting it successfully
|
||||
# using PuTTYgen and printing the inputs and outputs to
|
||||
# openssh_bcrypt in the process. So this output key is known
|
||||
# to agree with OpenSSH's own answer.
|
||||
|
||||
self.assertEqualBin(
|
||||
openssh_bcrypt('test passphrase',
|
||||
unhex('d0c3b40ace4afeaf8c0f81202ae36718'),
|
||||
16, 48),
|
||||
unhex('d78ba86e7273de0e007ab0ba256646823d5c902bc44293ae'
|
||||
'78547e9a7f629be928cc78ff78a75a4feb7aa6f125079c7d'))
|
||||
|
||||
def testRSAVerify(self):
|
||||
def blobs(n, e, d, p, q, iqmp):
|
||||
pubblob = ssh_string(b"ssh-rsa") + ssh2_mpint(e) + ssh2_mpint(n)
|
||||
|
@ -447,6 +447,9 @@ FUNC_WRAPPED(val_string, argon2, ARG(argon2flavour, flavour), ARG(uint, mem),
|
||||
ARG(val_string_ptrlen, K), ARG(val_string_ptrlen, X))
|
||||
FUNC(val_string, argon2_long_hash, ARG(uint, length),
|
||||
ARG(val_string_ptrlen, data))
|
||||
FUNC_WRAPPED(val_string, openssh_bcrypt, ARG(val_string_ptrlen, passphrase),
|
||||
ARG(val_string_ptrlen, salt), ARG(uint, rounds),
|
||||
ARG(uint, outbytes))
|
||||
|
||||
/*
|
||||
* Key generation functions.
|
||||
|
@ -1087,6 +1087,15 @@ strbuf *argon2_wrapper(Argon2Flavour flavour, uint32_t mem, uint32_t passes,
|
||||
return out;
|
||||
}
|
||||
|
||||
strbuf *openssh_bcrypt_wrapper(ptrlen passphrase, ptrlen salt,
|
||||
unsigned rounds, unsigned outbytes)
|
||||
{
|
||||
strbuf *out = strbuf_new();
|
||||
openssh_bcrypt(passphrase, salt, rounds,
|
||||
strbuf_append(out, outbytes), outbytes);
|
||||
return out;
|
||||
}
|
||||
|
||||
strbuf *get_implementations_commasep(ptrlen alg)
|
||||
{
|
||||
strbuf *out = strbuf_new();
|
||||
|
Loading…
Reference in New Issue
Block a user