| 1 |
/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */ |
| 2 |
|
| 3 |
/* $OpenBSD: arc4random.c,v 1.31 2014/05/31 10:32:12 jca Exp $ */ |
| 4 |
|
| 5 |
/* |
| 6 |
* Copyright (c) 1996, David Mazieres <dm@uun.org> |
| 7 |
* Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
| 8 |
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org> |
| 9 |
* |
| 10 |
* Permission to use, copy, modify, and distribute this software for any |
| 11 |
* purpose with or without fee is hereby granted, provided that the above |
| 12 |
* copyright notice and this permission notice appear in all copies. |
| 13 |
* |
| 14 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 15 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 16 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 17 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 18 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 19 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 20 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 21 |
*/ |
| 22 |
|
| 23 |
/* |
| 24 |
* ChaCha based random number generator for OpenBSD. |
| 25 |
* openssh-portable: openbsd-compat/arc4random.c |
| 26 |
*/ |
| 27 |
|
| 28 |
/* |
| 29 |
* with LibreSSL, use getentropy() instead of RAND_bytes(). |
| 30 |
* OpenBSD: lib/libcrypto/arc4random/getentropy_win.c |
| 31 |
* $OpenBSD: getentropy_win.c,v 1.6 2020/11/11 10:41:24 bcook Exp $ |
| 32 |
*/ |
| 33 |
|
| 34 |
|
| 35 |
#include <sys/types.h> |
| 36 |
|
| 37 |
#include <stdlib.h> |
| 38 |
#include <string.h> |
| 39 |
#include <process.h> |
| 40 |
|
| 41 |
#define KEYSTREAM_ONLY |
| 42 |
#include "ttxssh.h" |
| 43 |
|
| 44 |
/* |
| 45 |
* �����\�[�X�� OpenSSL �����������g������ |
| 46 |
* LibreSSL �������� libressl/crypto/compat/arc4random.c, |
| 47 |
* crypto/compat/getentropy_win.c ���g������ |
| 48 |
*/ |
| 49 |
#ifndef LIBRESSL_VERSION_NUMBER |
| 50 |
|
| 51 |
#include "arc4random.h" |
| 52 |
#include "chacha.h" |
| 53 |
|
| 54 |
#ifndef LIBRESSL_VERSION_NUMBER |
| 55 |
#include <openssl/rand.h> |
| 56 |
#include <openssl/err.h> |
| 57 |
#else |
| 58 |
#include <bcrypt.h> |
| 59 |
#endif |
| 60 |
|
| 61 |
/* OpenSSH isn't multithreaded */ |
| 62 |
#define _ARC4_LOCK() |
| 63 |
#define _ARC4_UNLOCK() |
| 64 |
|
| 65 |
#define KEYSZ 32 |
| 66 |
#define IVSZ 8 |
| 67 |
#define BLOCKSZ 64 |
| 68 |
#define RSBUFSZ (16*BLOCKSZ) |
| 69 |
static int rs_initialized; |
| 70 |
static int rs_stir_pid; |
| 71 |
static struct chacha_ctx rs; /* chacha context for random keystream */ |
| 72 |
static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ |
| 73 |
static size_t rs_have; /* valid bytes at end of rs_buf */ |
| 74 |
static size_t rs_count; /* bytes till reseed */ |
| 75 |
|
| 76 |
static void _rs_rekey(u_char *dat, size_t datlen); |
| 77 |
|
| 78 |
static void |
| 79 |
_rs_init(u_char *buf, size_t n) |
| 80 |
{ |
| 81 |
if (n < KEYSZ + IVSZ) |
| 82 |
return; |
| 83 |
chacha_keysetup(&rs, buf, KEYSZ * 8); |
| 84 |
chacha_ivsetup(&rs, buf + KEYSZ, NULL); |
| 85 |
} |
| 86 |
|
| 87 |
#ifdef LIBRESSL_VERSION_NUMBER |
| 88 |
/* |
| 89 |
* On Windows, BCryptGenRandom with BCRYPT_USE_SYSTEM_PREFERRED_RNG is supposed |
| 90 |
* to be a well-seeded, cryptographically strong random number generator. |
| 91 |
* https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom |
| 92 |
*/ |
| 93 |
static int |
| 94 |
getentropy(void *buf, size_t len) |
| 95 |
{ |
| 96 |
if (len > 256) { |
| 97 |
return (-1); |
| 98 |
} |
| 99 |
|
| 100 |
if (FAILED(BCryptGenRandom(NULL, buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { |
| 101 |
return (-1); |
| 102 |
} |
| 103 |
|
| 104 |
return (0); |
| 105 |
} |
| 106 |
#endif /* LIBRESSL_VERSION_NUMBER */ |
| 107 |
|
| 108 |
static void |
| 109 |
_rs_stir(void) |
| 110 |
{ |
| 111 |
u_char rnd[KEYSZ + IVSZ]; |
| 112 |
|
| 113 |
#ifndef LIBRESSL_VERSION_NUMBER |
| 114 |
if (RAND_bytes(rnd, sizeof(rnd)) <= 0) { |
| 115 |
return; |
| 116 |
} |
| 117 |
#else |
| 118 |
if (getentropy(rnd, sizeof(rnd)) == -1) { |
| 119 |
return; |
| 120 |
} |
| 121 |
#endif |
| 122 |
|
| 123 |
if (!rs_initialized) { |
| 124 |
rs_initialized = 1; |
| 125 |
_rs_init(rnd, sizeof(rnd)); |
| 126 |
} else |
| 127 |
_rs_rekey(rnd, sizeof(rnd)); |
| 128 |
SecureZeroMemory(rnd, sizeof(rnd)); |
| 129 |
|
| 130 |
/* invalidate rs_buf */ |
| 131 |
rs_have = 0; |
| 132 |
memset(rs_buf, 0, RSBUFSZ); |
| 133 |
|
| 134 |
rs_count = 1600000; |
| 135 |
} |
| 136 |
|
| 137 |
static void |
| 138 |
_rs_stir_if_needed(size_t len) |
| 139 |
{ |
| 140 |
int pid = _getpid(); |
| 141 |
|
| 142 |
if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) { |
| 143 |
rs_stir_pid = pid; |
| 144 |
_rs_stir(); |
| 145 |
} else |
| 146 |
rs_count -= len; |
| 147 |
} |
| 148 |
|
| 149 |
static void |
| 150 |
_rs_rekey(u_char *dat, size_t datlen) |
| 151 |
{ |
| 152 |
#ifndef KEYSTREAM_ONLY |
| 153 |
memset(rs_buf, 0,RSBUFSZ); |
| 154 |
#endif |
| 155 |
/* fill rs_buf with the keystream */ |
| 156 |
chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); |
| 157 |
/* mix in optional user provided data */ |
| 158 |
if (dat) { |
| 159 |
size_t i, m; |
| 160 |
|
| 161 |
m = MIN(datlen, KEYSZ + IVSZ); |
| 162 |
for (i = 0; i < m; i++) |
| 163 |
rs_buf[i] ^= dat[i]; |
| 164 |
} |
| 165 |
/* immediately reinit for backtracking resistance */ |
| 166 |
_rs_init(rs_buf, KEYSZ + IVSZ); |
| 167 |
memset(rs_buf, 0, KEYSZ + IVSZ); |
| 168 |
rs_have = RSBUFSZ - KEYSZ - IVSZ; |
| 169 |
} |
| 170 |
|
| 171 |
static void |
| 172 |
_rs_random_buf(void *_buf, size_t n) |
| 173 |
{ |
| 174 |
u_char *buf = (u_char *)_buf; |
| 175 |
size_t m; |
| 176 |
|
| 177 |
_rs_stir_if_needed(n); |
| 178 |
while (n > 0) { |
| 179 |
if (rs_have > 0) { |
| 180 |
m = MIN(n, rs_have); |
| 181 |
memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); |
| 182 |
memset(rs_buf + RSBUFSZ - rs_have, 0, m); |
| 183 |
buf += m; |
| 184 |
n -= m; |
| 185 |
rs_have -= m; |
| 186 |
} |
| 187 |
if (rs_have == 0) |
| 188 |
_rs_rekey(NULL, 0); |
| 189 |
} |
| 190 |
} |
| 191 |
|
| 192 |
static void |
| 193 |
_rs_random_u32(uint32 *val) |
| 194 |
{ |
| 195 |
_rs_stir_if_needed(sizeof(*val)); |
| 196 |
if (rs_have < sizeof(*val)) |
| 197 |
_rs_rekey(NULL, 0); |
| 198 |
memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); |
| 199 |
memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); |
| 200 |
rs_have -= sizeof(*val); |
| 201 |
} |
| 202 |
|
| 203 |
uint32 |
| 204 |
arc4random(void) |
| 205 |
{ |
| 206 |
uint32 val; |
| 207 |
|
| 208 |
_ARC4_LOCK(); |
| 209 |
_rs_random_u32(&val); |
| 210 |
_ARC4_UNLOCK(); |
| 211 |
return val; |
| 212 |
} |
| 213 |
|
| 214 |
/* |
| 215 |
* If we are providing arc4random, then we can provide a more efficient |
| 216 |
* arc4random_buf(). |
| 217 |
*/ |
| 218 |
void |
| 219 |
arc4random_buf(void *buf, size_t n) |
| 220 |
{ |
| 221 |
_ARC4_LOCK(); |
| 222 |
_rs_random_buf(buf, n); |
| 223 |
_ARC4_UNLOCK(); |
| 224 |
} |
| 225 |
|
| 226 |
#endif /* LIBRESSL_VERSION_NUMBER */ |