diff --git a/import.c b/import.c index c8786d52..2b4cea5a 100644 --- a/import.c +++ b/import.c @@ -988,7 +988,7 @@ static bool openssh_pem_write( */ if (passphrase) { unsigned char keybuf[32]; - int origlen, outlen, pad, i; + int origlen, outlen, pad; /* * Padding on OpenSSH keys is deterministic. The number of @@ -1015,7 +1015,7 @@ static bool openssh_pem_write( /* * Invent an iv, and derive the encryption key. */ - for (i = 0; i < 8; i++) iv[i] = random_byte(); + random_read(iv, 8); openssh_pem_derivekey(ptrlen_from_asciz(passphrase), iv, keybuf); @@ -1498,7 +1498,7 @@ static bool openssh_new_write( const Filename *filename, ssh2_userkey *key, const char *passphrase) { strbuf *pubblob, *privblob, *cblob; - int padvalue, i; + int padvalue; unsigned checkint; bool ret = false; unsigned char bcrypt_salt[16]; @@ -1530,8 +1530,7 @@ static bool openssh_new_write( } else { strbuf *substr; - for (i = 0; i < (int)sizeof(bcrypt_salt); i++) - bcrypt_salt[i] = random_byte(); + random_read(bcrypt_salt, sizeof(bcrypt_salt)); put_stringz(cblob, "aes256-ctr"); put_stringz(cblob, "bcrypt"); substr = strbuf_new(); @@ -1551,9 +1550,9 @@ static bool openssh_new_write( strbuf *cpblob = strbuf_new(); /* checkint. */ - checkint = 0; - for (i = 0; i < 4; i++) - checkint = (checkint << 8) + random_byte(); + uint8_t checkint_buf[4]; + random_read(checkint_buf, 4); + checkint = GET_32BIT_MSB_FIRST(checkint_buf); put_uint32(cpblob, checkint); put_uint32(cpblob, checkint); @@ -2279,8 +2278,9 @@ static bool sshcom_write( /* Pad encrypted blob to a multiple of cipher block size. */ if (passphrase) { int padding = -(outblob->len - (lenpos+4)) & 7; - while (padding--) - put_byte(outblob, random_byte()); + uint8_t padding_buf[8]; + random_read(padding_buf, padding); + put_data(outblob, padding_buf, padding); } ciphertext = outblob->s + lenpos + 4; cipherlen = outblob->len - (lenpos + 4); diff --git a/mpint.c b/mpint.c index 66216b74..cc4bc148 100644 --- a/mpint.c +++ b/mpint.c @@ -2302,21 +2302,20 @@ mp_int *monty_modsqrt(ModsqrtContext *sc, mp_int *x, unsigned *success) return toret; } -mp_int *mp_random_bits_fn(size_t bits, int (*gen_byte)(void)) +mp_int *mp_random_bits_fn(size_t bits, random_read_fn_t random_read) { size_t bytes = (bits + 7) / 8; - size_t words = (bits + BIGNUM_INT_BITS - 1) / BIGNUM_INT_BITS; - mp_int *x = mp_make_sized(words); - for (size_t i = 0; i < bytes; i++) { - BignumInt byte = gen_byte(); - unsigned mask = (1 << size_t_min(8, bits-i*8)) - 1; - x->w[i / BIGNUM_INT_BYTES] |= - (byte & mask) << (8*(i % BIGNUM_INT_BYTES)); - } - return x; + uint8_t *randbuf = snewn(bytes, uint8_t); + random_read(randbuf, bytes); + if (bytes) + randbuf[0] &= (2 << ((bits-1) & 7)) - 1; + mp_int *toret = mp_from_bytes_be(make_ptrlen(randbuf, bytes)); + smemclr(randbuf, bytes); + sfree(randbuf); + return toret; } -mp_int *mp_random_in_range_fn(mp_int *lo, mp_int *hi, int (*gen_byte)(void)) +mp_int *mp_random_in_range_fn(mp_int *lo, mp_int *hi, random_read_fn_t rf) { mp_int *n_outcomes = mp_sub(hi, lo); @@ -2329,8 +2328,7 @@ mp_int *mp_random_in_range_fn(mp_int *lo, mp_int *hi, int (*gen_byte)(void)) * is acceptable on the grounds that you'd have to examine so many * outputs to even detect it. */ - mp_int *unreduced = mp_random_bits_fn( - mp_max_bits(n_outcomes) + 128, gen_byte); + mp_int *unreduced = mp_random_bits_fn(mp_max_bits(n_outcomes) + 128, rf); mp_int *reduced = mp_mod(unreduced, n_outcomes); mp_add_into(reduced, reduced, lo); mp_free(unreduced); diff --git a/mpint.h b/mpint.h index c27331ab..22f3eefe 100644 --- a/mpint.h +++ b/mpint.h @@ -364,9 +364,9 @@ mp_int *mp_rshift_fixed(mp_int *x, size_t shift); /* * Generate a random mp_int. * - * The _function_ definitions here will expect to be given a gen_byte + * The _function_ definitions here will expect to be given a gen_data * function that provides random data. Normally you'd use this using - * random_byte() from random.c, and the macro wrappers automate that. + * random_read() from random.c, and the macro wrappers automate that. * * (This is a bit of a dodge to avoid mpint.c having a link-time * dependency on random.c, so that programs can link against one but @@ -376,10 +376,11 @@ mp_int *mp_rshift_fixed(mp_int *x, size_t shift); * mp_random_bits[_fn] returns an integer 0 <= n < 2^bits. * mp_random_in_range[_fn](lo,hi) returns an integer lo <= n < hi. */ -mp_int *mp_random_bits_fn(size_t bits, int (*gen_byte)(void)); +typedef void (*random_read_fn_t)(void *, size_t); +mp_int *mp_random_bits_fn(size_t bits, random_read_fn_t randfn); mp_int *mp_random_in_range_fn( - mp_int *lo_inclusive, mp_int *hi_exclusive, int (*gen_byte)(void)); -#define mp_random_bits(bits) mp_random_bits_fn(bits, random_byte) -#define mp_random_in_range(lo, hi) mp_random_in_range_fn(lo, hi, random_byte) + mp_int *lo_inclusive, mp_int *hi_exclusive, random_read_fn_t randfn); +#define mp_random_bits(bits) mp_random_bits_fn(bits, random_read) +#define mp_random_in_range(lo, hi) mp_random_in_range_fn(lo, hi, random_read) #endif /* PUTTY_MPINT_H */ diff --git a/pageant.c b/pageant.c index 5767855a..be2dd01d 100644 --- a/pageant.c +++ b/pageant.c @@ -21,11 +21,9 @@ * won't generate true random numbers. So we must scream, panic, * and exit immediately if that should happen. */ -int random_byte(void) +void random_read(void *buf, size_t size) { modalfatalbox("Internal error: attempt to use random numbers in Pageant"); - exit(0); - return 0; /* unreachable, but placate optimiser */ } static bool pageant_local = false; diff --git a/putty.h b/putty.h index 544e54da..4d6a3c5b 100644 --- a/putty.h +++ b/putty.h @@ -1674,7 +1674,7 @@ void luni_send(Ldisc *, const wchar_t * widebuf, int len, bool interactive); */ void random_add_noise(void *noise, int length); -int random_byte(void); +void random_read(void *buf, size_t size); void random_get_savedata(void **data, int *len); extern int random_active; /* The random number subsystem is activated if at least one other entity diff --git a/ssh.h b/ssh.h index 7b256cd1..9b3d37d7 100644 --- a/ssh.h +++ b/ssh.h @@ -892,7 +892,7 @@ void SHATransform(uint32_t *digest, uint32_t *data); # undef COMPILER_SUPPORTS_SHA_NI #endif -int random_byte(void); +void random_read(void *out, size_t size); void random_add_noise(void *noise, int length); void random_add_heavynoise(void *noise, int length); diff --git a/ssh1bpp.c b/ssh1bpp.c index 727d9e3c..52610489 100644 --- a/ssh1bpp.c +++ b/ssh1bpp.c @@ -295,7 +295,7 @@ static PktOut *ssh1_bpp_new_pktout(int pkt_type) static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt) { - int pad, biglen, i, pktoffs; + int pad, biglen, pktoffs; uint32_t crc; int len; @@ -329,8 +329,7 @@ static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt) pktoffs = 8 - pad; biglen = len + pad; /* len(padding+type+data+CRC) */ - for (i = pktoffs; i < 4+8; i++) - pkt->data[i] = random_byte(); + random_read(pkt->data + pktoffs, 4+8 - pktoffs); crc = crc32_ssh1( make_ptrlen(pkt->data + pktoffs + 4, biglen - 4)); /* all ex len */ PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc); diff --git a/ssh1login-server.c b/ssh1login-server.c index d2e12800..d4920ad0 100644 --- a/ssh1login-server.c +++ b/ssh1login-server.c @@ -158,8 +158,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) if (s->ap_methods & AUTHMETHOD_CRYPTOCARD) s->supported_auths_mask |= (1U << SSH1_AUTH_CCARD); - for (i = 0; i < 8; i++) - s->cookie[i] = random_byte(); + random_read(s->cookie, 8); pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_SMSG_PUBLIC_KEY); put_data(pktout, s->cookie, 8); @@ -307,8 +306,7 @@ static void ssh1_login_server_process_queue(PacketProtocolLayer *ppl) unsigned char *rsabuf = snewn(s->authkey->bytes, unsigned char); - for (i = 0; i < 32; i++) - rsabuf[i] = random_byte(); + random_read(rsabuf, 32); { ssh_hash *h = ssh_hash_new(&ssh_md5); diff --git a/ssh1login.c b/ssh1login.c index 9a40641b..4f24a208 100644 --- a/ssh1login.c +++ b/ssh1login.c @@ -201,8 +201,7 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ssh1_compute_session_id(s->session_id, s->cookie, &s->hostkey, &s->servkey); - for (i = 0; i < 32; i++) - s->session_key[i] = random_byte(); + random_read(s->session_key, 32); /* * Verify that the `bits' and `bytes' parameters match. @@ -986,10 +985,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) put_stringz(pkt, s->cur_prompt->prompts[0]->result); pq_push(s->ppl.out_pq, pkt); } else { - int j; strbuf *random_data = strbuf_new(); - for (j = 0; j < i; j++) - put_byte(random_data, random_byte()); + random_read(strbuf_append(random_data, i), i); pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_MSG_IGNORE); put_stringsb(pkt, random_data); @@ -1009,9 +1006,8 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) ppl_logevent("Sending length-padded password"); pkt = ssh_bpp_new_pktout(s->ppl.bpp, s->pwpkt_type); put_asciz(padded_pw, s->cur_prompt->prompts[0]->result); - do { - put_byte(padded_pw, random_byte()); - } while (padded_pw->len % 64 != 0); + size_t pad = 63 & -padded_pw->len; + random_read(strbuf_append(padded_pw, pad), pad); put_stringsb(pkt, padded_pw); pq_push(s->ppl.out_pq, pkt); } else { diff --git a/ssh2bpp.c b/ssh2bpp.c index d6ae6a41..4563034a 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -726,7 +726,8 @@ static void ssh2_bpp_format_packet_inner(struct ssh2_bpp_state *s, PktOut *pkt) maclen = s->out.mac ? ssh2_mac_alg(s->out.mac)->len : 0; origlen = pkt->length; for (i = 0; i < padding; i++) - put_byte(pkt, random_byte()); + put_byte(pkt, 0); /* make space for random padding */ + random_read(pkt->data + origlen, padding); pkt->data[4] = padding; PUT_32BIT(pkt->data, origlen + padding - 4); @@ -820,8 +821,10 @@ static void ssh2_bpp_format_packet(struct ssh2_bpp_state *s, PktOut *pkt) ignore_pkt = ssh2_bpp_new_pktout(SSH2_MSG_IGNORE); put_uint32(ignore_pkt, length); - while (length-- > 0) - put_byte(ignore_pkt, random_byte()); + size_t origlen = ignore_pkt->length; + for (size_t i = 0; i < length; i++) + put_byte(ignore_pkt, 0); /* make space for random padding */ + random_read(ignore_pkt->data + origlen, length); ssh2_bpp_format_packet_inner(s, ignore_pkt); bufchain_add(s->bpp.out_raw, ignore_pkt->data, ignore_pkt->length); ssh_free_pktout(ignore_pkt); diff --git a/ssh2kex-client.c b/ssh2kex-client.c index 15ab9eb7..a5e48e00 100644 --- a/ssh2kex-client.c +++ b/ssh2kex-client.c @@ -556,17 +556,12 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted) { int klen = ssh_rsakex_klen(s->rsa_kex_key); int nbits = klen - (2*s->kex_alg->hash->hlen*8 + 49); - int i, byte = 0; strbuf *buf, *outstr; + mp_int *tmp = mp_random_bits(nbits - 1); s->K = mp_power_2(nbits - 1); - - for (i = 0; i < nbits; i++) { - if ((i & 7) == 0) { - byte = random_byte(); - } - mp_set_bit(s->K, i, (byte >> (i & 7)) & 1); - } + mp_add_into(s->K, s->K, tmp); + mp_free(tmp); /* * Encode this as an mpint. diff --git a/ssh2transport.c b/ssh2transport.c index 3953e3e1..98c5a892 100644 --- a/ssh2transport.c +++ b/ssh2transport.c @@ -1048,11 +1048,7 @@ static void ssh2_transport_process_queue(PacketProtocolLayer *ppl) */ s->client_kexinit->len = 0; put_byte(s->outgoing_kexinit, SSH2_MSG_KEXINIT); - { - int i; - for (i = 0; i < 16; i++) - put_byte(s->outgoing_kexinit, (unsigned char) random_byte()); - } + random_read(strbuf_append(s->outgoing_kexinit, 16), 16); ssh2_write_kexinit_lists( BinarySink_UPCAST(s->outgoing_kexinit), s->kexlists, s->conf, s->ppl.remote_bugs, diff --git a/sshecc.c b/sshecc.c index d5dafb59..15775ad4 100644 --- a/sshecc.c +++ b/sshecc.c @@ -1269,8 +1269,8 @@ static void ssh_ecdhkex_w_setup(ecdh_key *dh) static void ssh_ecdhkex_m_setup(ecdh_key *dh) { strbuf *bytes = strbuf_new(); - for (size_t i = 0; i < dh->curve->fieldBytes; ++i) - put_byte(bytes, random_byte()); + random_read(strbuf_append(bytes, dh->curve->fieldBytes), + dh->curve->fieldBytes); bytes->u[0] &= 0xF8; bytes->u[bytes->len-1] &= 0x7F; diff --git a/sshprime.c b/sshprime.c index 65380e0e..8f54d271 100644 --- a/sshprime.c +++ b/sshprime.c @@ -387,7 +387,9 @@ void invent_firstbits(unsigned *one, unsigned *two) * i.e. the ones we actually invented. */ do { - *one = 0x100 | random_byte(); - *two = 0x100 | random_byte(); + uint8_t bytes[2]; + random_read(bytes, 2); + *one = 0x100 | bytes[0]; + *two = 0x100 | bytes[1]; } while (*one * *two < 0x20000); } diff --git a/sshpubk.c b/sshpubk.c index 596b0175..720387a2 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -333,12 +333,10 @@ bool rsa_ssh1_savekey(const Filename *filename, RSAKey *key, * Two bytes, then the same two bytes repeated. */ { - unsigned char b0 = random_byte(); - unsigned char b1 = random_byte(); - put_byte(buf, b0); - put_byte(buf, b1); - put_byte(buf, b0); - put_byte(buf, b1); + uint8_t bytes[2]; + random_read(bytes, 2); + put_data(buf, bytes, 2); + put_data(buf, bytes, 2); } /* diff --git a/sshrand.c b/sshrand.c index d3ca45c8..bcf6982d 100644 --- a/sshrand.c +++ b/sshrand.c @@ -52,9 +52,10 @@ void random_add_noise(void *noise, int length) { } void random_add_heavynoise(void *noise, int length) { } void random_ref(void) { } void random_unref(void) { } -int random_byte(void) +void random_read(void *out, size_t size) { return 0x45; /* Chosen by eight fair coin tosses */ + memset(out, 0x45, size); /* Chosen by eight fair coin tosses */ } void random_get_savedata(void **data, int *len) { } #else /* !FUZZING */ @@ -319,14 +320,17 @@ void random_unref(void) random_active--; } -int random_byte(void) +void random_read(void *vout, size_t size) { assert(random_active); - if (pool.poolpos >= POOLSIZE) - random_stir(); + uint8_t *out = (uint8_t *)vout; + while (size-- > 0) { + if (pool.poolpos >= POOLSIZE) + random_stir(); - return pool.pool[pool.poolpos++]; + *out++ = pool.pool[pool.poolpos++]; + } } void random_get_savedata(void **data, int *len) diff --git a/sshrsa.c b/sshrsa.c index a7419393..b845b46c 100644 --- a/sshrsa.c +++ b/sshrsa.c @@ -56,11 +56,37 @@ bool rsa_ssh1_encrypt(unsigned char *data, int length, RSAKey *key) data[0] = 0; data[1] = 2; + size_t npad = key->bytes - length - 3; + /* + * Generate a sequence of nonzero padding bytes. We do this in a + * reasonably uniform way and without having to loop round + * retrying the random number generation, by first generating an + * integer in [0,2^n) for an appropriately large n; then we + * repeatedly multiply by 255 to give an integer in [0,255*2^n), + * extract the top 8 bits to give an integer in [0,255), and mask + * those bits off before multiplying up again for the next digit. + * This gives us a sequence of numbers in [0,255), and of course + * adding 1 to each of them gives numbers in [1,256) as we wanted. + * + * (You could imagine this being a sort of fixed-point operation: + * given a uniformly random binary _fraction_, multiplying it by k + * and subtracting off the integer part will yield you a sequence + * of integers each in [0,k). I'm just doing that scaled up by a + * power of 2 to avoid the fractions.) + */ + size_t random_bits = (npad + 16) * 8; + mp_int *randval = mp_new(random_bits + 8); + mp_int *tmp = mp_random_bits(random_bits); + mp_copy_into(randval, tmp); + mp_free(tmp); for (i = 2; i < key->bytes - length - 1; i++) { - do { - data[i] = random_byte(); - } while (data[i] == 0); + mp_mul_integer_into(randval, randval, 255); + uint8_t byte = mp_get_byte(randval, random_bits / 8); + assert(byte != 255); + data[i] = byte + 1; + mp_reduce_mod_2to(randval, random_bits); } + mp_free(randval); data[key->bytes - length - 1] = 0; b1 = mp_from_bytes_be(make_ptrlen(data, key->bytes)); @@ -804,8 +830,7 @@ strbuf *ssh_rsakex_encrypt(RSAKey *rsa, const ssh_hashalg *h, ptrlen in) /* Leading byte zero. */ out[0] = 0; /* At position 1, the seed: HLEN bytes of random data. */ - for (i = 0; i < HLEN; i++) - out[i + 1] = random_byte(); + random_read(out + 1, HLEN); /* At position 1+HLEN, the data block DB, consisting of: */ /* The hash of the label (we only support an empty label here) */ { diff --git a/testcrypt.c b/testcrypt.c index 7afec38d..d278daa8 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -49,13 +49,10 @@ static NORETURN void fatal_error(const char *p, ...) void out_of_memory(void) { fatal_error("out of memory"); } static bufchain random_data_queue; -int random_byte(void) +void random_read(void *buf, size_t size) { - unsigned char u; - if (bufchain_try_fetch_consume(&random_data_queue, &u, 1)) - return u; - fatal_error("No random data in queue"); - return 0; + if (!bufchain_try_fetch_consume(&random_data_queue, buf, size)) + fatal_error("No random data in queue"); } #define VALUE_TYPES(X) \ diff --git a/unix/uxsftpserver.c b/unix/uxsftpserver.c index 81214c4c..17ab8c0b 100644 --- a/unix/uxsftpserver.c +++ b/unix/uxsftpserver.c @@ -58,7 +58,6 @@ static int uss_dirhandle_cmp(void *av, void *bv) static SftpServer *uss_new(const SftpServerVtable *vt) { - int i; UnixSftpServer *uss = snew(UnixSftpServer); memset(uss, 0, sizeof(UnixSftpServer)); @@ -66,8 +65,7 @@ static SftpServer *uss_new(const SftpServerVtable *vt) uss->dirhandles = newtree234(uss_dirhandle_cmp); uss->srv.vt = vt; - for (i = 0; i < lenof(uss->handlekey); i++) - uss->handlekey[i] = random_byte(); + random_read(uss->handlekey, sizeof(uss->handlekey)); return &uss->srv; } diff --git a/unix/uxshare.c b/unix/uxshare.c index b610eb53..2de65b52 100644 --- a/unix/uxshare.c +++ b/unix/uxshare.c @@ -116,9 +116,7 @@ static char *make_dirname(const char *pi_name, char **logtext) /* * Invent some random data. */ - for (i = 0; i < SALT_SIZE; i++) { - saltbuf[i] = random_byte(); - } + random_read(saltbuf, SALT_SIZE); ret = write(saltfd, saltbuf, SALT_SIZE); /* POSIX atomicity guarantee: because we wrote less than * PIPE_BUF bytes, the write either completed in full or diff --git a/x11fwd.c b/x11fwd.c index 8f8e3972..b52cf004 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -93,8 +93,7 @@ struct X11FakeAuth *x11_invent_fake_auth(tree234 *authtree, int authtype) auth->xa1_firstblock = NULL; while (1) { - for (i = 0; i < auth->datalen; i++) - auth->data[i] = random_byte(); + random_read(auth->data, auth->datalen); if (add234(authtree, auth) == auth) break; } @@ -111,8 +110,10 @@ struct X11FakeAuth *x11_invent_fake_auth(tree234 *authtree, int authtype) memset(auth->xa1_firstblock, 0, 8); while (1) { - for (i = 0; i < auth->datalen; i++) - auth->data[i] = (i == 8 ? 0 : random_byte()); + random_read(auth->data, 15); + auth->data[15] = auth->data[8]; + auth->data[8] = 0; + memcpy(auth->xa1_firstblock, auth->data, 8); des_encrypt_xdmauth(auth->data + 9, auth->xa1_firstblock, 8); if (add234(authtree, auth) == auth)