diff --git a/sshprng.c b/sshprng.c index 9145f892..58df9945 100644 --- a/sshprng.c +++ b/sshprng.c @@ -7,7 +7,7 @@ #include "putty.h" #include "ssh.h" -#include "mpint.h" +#include "mpint_i.h" #ifdef PRNG_DIAGNOSTICS #define prngdebug debug @@ -57,7 +57,7 @@ struct prng_impl { * calling ssh_hash_final. */ ssh_hash *generator; - mp_int *counter; + BignumInt counter[128 / BIGNUM_INT_BITS]; /* * 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->keymaker = NULL; pi->generator = NULL; - pi->counter = mp_new(128); + memset(pi->counter, 0, sizeof(pi->counter)); for (size_t i = 0; i < NCOLLECTORS; i++) pi->collectors[i] = ssh_hash_new(pi->hashalg); pi->until_reseed = 0; @@ -128,7 +128,7 @@ void prng_free(prng *pr) { 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++) ssh_hash_free(pi->collectors[i]); 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); prngdebug("prng_generate\n"); - put_byte(h, 'G'); - put_mp_ssh2(h, pi->counter); - mp_add_integer_into(pi->counter, pi->counter, 1); + for (unsigned i = 0; i < 128; i += 8) + 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); } diff --git a/test/cryptsuite.py b/test/cryptsuite.py index b5a3d542..5a4ae07e 100755 --- a/test/cryptsuite.py +++ b/test/cryptsuite.py @@ -89,6 +89,10 @@ def last(iterable): pass 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 def queued_random_data(nbytes, seed): hashsize = 512 // 8 @@ -1627,23 +1631,25 @@ class crypt(MyTestBase): prng_add_entropy(pr, 0, entropy) # forces a reseed data3 = prng_read(pr, 128) + le128 = lambda x: le_integer(x, 128) + key1 = hash_str(hashalg, b'R' + seed) 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)) # After prng_read finishes, we expect the PRNG to have # automatically reseeded itself, so that if its internal state # is revealed then the previous output can't be reconstructed. key2 = hash_str(hashalg, key1 + b'R') 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)) # There will have been another reseed after the second # prng_read, and then another due to the entropy. key3 = hash_str(hashalg, key2 + b'R') key4 = hash_str(hashalg, key3 + b'R' + hash_str(hashalg, entropy)) 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)) self.assertEqualBin(data1, expected_data1)