mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-08 08:58: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 "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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user