mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Stop using mp_int in sshprng.c.
We keep an internal 128-bit counter that's used as part of the hash preimages. There's no real need to import all the mp_int machinery in order to implement that: we can do it by hand using a small fixed-size array and a trivial use of BignumADC. This is another inter-module dependency that's easy to remove and useful to spinoff programs. This changes the hash preimage calculation in the PRNG, because we're now formatting our 128-bit integer in the fixed-length representation of 16 little-endian bytes instead of as an SSH-2 mpint. This is harmless (perhaps even mildly beneficial, due to the length now not depending on how long the PRNG has been running), but means I have to update the PRNG tests as well.
This commit is contained in:
parent
a058054253
commit
7003b43963
16
sshprng.c
16
sshprng.c
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "putty.h"
|
#include "putty.h"
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "mpint.h"
|
#include "mpint_i.h"
|
||||||
|
|
||||||
#ifdef PRNG_DIAGNOSTICS
|
#ifdef PRNG_DIAGNOSTICS
|
||||||
#define prngdebug debug
|
#define prngdebug debug
|
||||||
@ -57,7 +57,7 @@ struct prng_impl {
|
|||||||
* calling ssh_hash_final.
|
* calling ssh_hash_final.
|
||||||
*/
|
*/
|
||||||
ssh_hash *generator;
|
ssh_hash *generator;
|
||||||
mp_int *counter;
|
BignumInt counter[128 / BIGNUM_INT_BITS];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When re-seeding the generator, you call prng_seed_begin(),
|
* When re-seeding the generator, you call prng_seed_begin(),
|
||||||
@ -113,7 +113,7 @@ prng *prng_new(const ssh_hashalg *hashalg)
|
|||||||
pi->hashalg = hashalg;
|
pi->hashalg = hashalg;
|
||||||
pi->keymaker = NULL;
|
pi->keymaker = NULL;
|
||||||
pi->generator = NULL;
|
pi->generator = NULL;
|
||||||
pi->counter = mp_new(128);
|
memset(pi->counter, 0, sizeof(pi->counter));
|
||||||
for (size_t i = 0; i < NCOLLECTORS; i++)
|
for (size_t i = 0; i < NCOLLECTORS; i++)
|
||||||
pi->collectors[i] = ssh_hash_new(pi->hashalg);
|
pi->collectors[i] = ssh_hash_new(pi->hashalg);
|
||||||
pi->until_reseed = 0;
|
pi->until_reseed = 0;
|
||||||
@ -128,7 +128,7 @@ void prng_free(prng *pr)
|
|||||||
{
|
{
|
||||||
prng_impl *pi = container_of(pr, prng_impl, Prng);
|
prng_impl *pi = container_of(pr, prng_impl, Prng);
|
||||||
|
|
||||||
mp_free(pi->counter);
|
smemclr(pi->counter, sizeof(pi->counter));
|
||||||
for (size_t i = 0; i < NCOLLECTORS; i++)
|
for (size_t i = 0; i < NCOLLECTORS; i++)
|
||||||
ssh_hash_free(pi->collectors[i]);
|
ssh_hash_free(pi->collectors[i]);
|
||||||
if (pi->generator)
|
if (pi->generator)
|
||||||
@ -204,10 +204,12 @@ static inline void prng_generate(prng_impl *pi, void *outbuf)
|
|||||||
ssh_hash *h = ssh_hash_copy(pi->generator);
|
ssh_hash *h = ssh_hash_copy(pi->generator);
|
||||||
|
|
||||||
prngdebug("prng_generate\n");
|
prngdebug("prng_generate\n");
|
||||||
|
|
||||||
put_byte(h, 'G');
|
put_byte(h, 'G');
|
||||||
put_mp_ssh2(h, pi->counter);
|
for (unsigned i = 0; i < 128; i += 8)
|
||||||
mp_add_integer_into(pi->counter, pi->counter, 1);
|
put_byte(h, pi->counter[i/BIGNUM_INT_BITS] >> (i%BIGNUM_INT_BITS));
|
||||||
|
BignumCarry c = 1;
|
||||||
|
for (unsigned i = 0; i < lenof(pi->counter); i++)
|
||||||
|
BignumADC(pi->counter[i], c, pi->counter[i], 0, c);
|
||||||
ssh_hash_final(h, outbuf);
|
ssh_hash_final(h, outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,10 @@ def last(iterable):
|
|||||||
pass
|
pass
|
||||||
return toret
|
return toret
|
||||||
|
|
||||||
|
def le_integer(x, nbits):
|
||||||
|
assert nbits % 8 == 0
|
||||||
|
return bytes([0xFF & (x >> (8*n)) for n in range(nbits//8)])
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def queued_random_data(nbytes, seed):
|
def queued_random_data(nbytes, seed):
|
||||||
hashsize = 512 // 8
|
hashsize = 512 // 8
|
||||||
@ -1627,23 +1631,25 @@ class crypt(MyTestBase):
|
|||||||
prng_add_entropy(pr, 0, entropy) # forces a reseed
|
prng_add_entropy(pr, 0, entropy) # forces a reseed
|
||||||
data3 = prng_read(pr, 128)
|
data3 = prng_read(pr, 128)
|
||||||
|
|
||||||
|
le128 = lambda x: le_integer(x, 128)
|
||||||
|
|
||||||
key1 = hash_str(hashalg, b'R' + seed)
|
key1 = hash_str(hashalg, b'R' + seed)
|
||||||
expected_data1 = b''.join(
|
expected_data1 = b''.join(
|
||||||
hash_str(hashalg, key1 + b'G' + ssh2_mpint(counter))
|
hash_str(hashalg, key1 + b'G' + le128(counter))
|
||||||
for counter in range(4))
|
for counter in range(4))
|
||||||
# After prng_read finishes, we expect the PRNG to have
|
# After prng_read finishes, we expect the PRNG to have
|
||||||
# automatically reseeded itself, so that if its internal state
|
# automatically reseeded itself, so that if its internal state
|
||||||
# is revealed then the previous output can't be reconstructed.
|
# is revealed then the previous output can't be reconstructed.
|
||||||
key2 = hash_str(hashalg, key1 + b'R')
|
key2 = hash_str(hashalg, key1 + b'R')
|
||||||
expected_data2 = b''.join(
|
expected_data2 = b''.join(
|
||||||
hash_str(hashalg, key2 + b'G' + ssh2_mpint(counter))
|
hash_str(hashalg, key2 + b'G' + le128(counter))
|
||||||
for counter in range(4,8))
|
for counter in range(4,8))
|
||||||
# There will have been another reseed after the second
|
# There will have been another reseed after the second
|
||||||
# prng_read, and then another due to the entropy.
|
# prng_read, and then another due to the entropy.
|
||||||
key3 = hash_str(hashalg, key2 + b'R')
|
key3 = hash_str(hashalg, key2 + b'R')
|
||||||
key4 = hash_str(hashalg, key3 + b'R' + hash_str(hashalg, entropy))
|
key4 = hash_str(hashalg, key3 + b'R' + hash_str(hashalg, entropy))
|
||||||
expected_data3 = b''.join(
|
expected_data3 = b''.join(
|
||||||
hash_str(hashalg, key4 + b'G' + ssh2_mpint(counter))
|
hash_str(hashalg, key4 + b'G' + le128(counter))
|
||||||
for counter in range(8,12))
|
for counter in range(8,12))
|
||||||
|
|
||||||
self.assertEqualBin(data1, expected_data1)
|
self.assertEqualBin(data1, expected_data1)
|
||||||
|
Loading…
Reference in New Issue
Block a user