unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
random.c (12826B)
1 /************************************************************************ 2 * IRC - Internet Relay Chat, random.c 3 * (C) 2004-2019 Bram Matthys (Syzop) and the UnrealIRCd Team 4 * 5 * See file AUTHORS in IRC package for additional names of 6 * the programmers. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 1, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 * 22 */ 23 24 #include "unrealircd.h" 25 26 #ifndef HAVE_ARC4RANDOM 27 28 #define KEYSTREAM_ONLY 29 30 /* chacha_private.h from openssh/openssh-portable 31 * "chacha-merged.c version 20080118 32 * D. J. Bernstein 33 * Public domain." 34 */ 35 36 /* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ 37 38 typedef unsigned char u8; 39 typedef unsigned int u32; 40 41 typedef struct 42 { 43 u32 input[16]; /* could be compressed */ 44 } chacha_ctx; 45 46 #define U8C(v) (v##U) 47 #define U32C(v) (v##U) 48 49 #define U8V(v) ((u8)(v) & U8C(0xFF)) 50 #define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 51 52 #define ROTL32(v, n) \ 53 (U32V((v) << (n)) | ((v) >> (32 - (n)))) 54 55 #define U8TO32_LITTLE(p) \ 56 (((u32)((p)[0]) ) | \ 57 ((u32)((p)[1]) << 8) | \ 58 ((u32)((p)[2]) << 16) | \ 59 ((u32)((p)[3]) << 24)) 60 61 #define U32TO8_LITTLE(p, v) \ 62 do { \ 63 (p)[0] = U8V((v) ); \ 64 (p)[1] = U8V((v) >> 8); \ 65 (p)[2] = U8V((v) >> 16); \ 66 (p)[3] = U8V((v) >> 24); \ 67 } while (0) 68 69 #define ROTATE(v,c) (ROTL32(v,c)) 70 #define XOR(v,w) ((v) ^ (w)) 71 #define PLUS(v,w) (U32V((v) + (w))) 72 #define PLUSONE(v) (PLUS((v),1)) 73 74 #define QUARTERROUND(a,b,c,d) \ 75 a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 76 c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 77 a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 78 c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 79 80 static const char sigma[16] = "expand 32-byte k"; 81 static const char tau[16] = "expand 16-byte k"; 82 83 static void 84 chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) 85 { 86 const char *constants; 87 88 x->input[4] = U8TO32_LITTLE(k + 0); 89 x->input[5] = U8TO32_LITTLE(k + 4); 90 x->input[6] = U8TO32_LITTLE(k + 8); 91 x->input[7] = U8TO32_LITTLE(k + 12); 92 if (kbits == 256) { /* recommended */ 93 k += 16; 94 constants = sigma; 95 } else { /* kbits == 128 */ 96 constants = tau; 97 } 98 x->input[8] = U8TO32_LITTLE(k + 0); 99 x->input[9] = U8TO32_LITTLE(k + 4); 100 x->input[10] = U8TO32_LITTLE(k + 8); 101 x->input[11] = U8TO32_LITTLE(k + 12); 102 x->input[0] = U8TO32_LITTLE(constants + 0); 103 x->input[1] = U8TO32_LITTLE(constants + 4); 104 x->input[2] = U8TO32_LITTLE(constants + 8); 105 x->input[3] = U8TO32_LITTLE(constants + 12); 106 } 107 108 static void 109 chacha_ivsetup(chacha_ctx *x,const u8 *iv) 110 { 111 x->input[12] = 0; 112 x->input[13] = 0; 113 x->input[14] = U8TO32_LITTLE(iv + 0); 114 x->input[15] = U8TO32_LITTLE(iv + 4); 115 } 116 117 static void 118 chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 119 { 120 u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 121 u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 122 u8 *ctarget = NULL; 123 u8 tmp[64]; 124 u_int i; 125 126 if (!bytes) return; 127 128 j0 = x->input[0]; 129 j1 = x->input[1]; 130 j2 = x->input[2]; 131 j3 = x->input[3]; 132 j4 = x->input[4]; 133 j5 = x->input[5]; 134 j6 = x->input[6]; 135 j7 = x->input[7]; 136 j8 = x->input[8]; 137 j9 = x->input[9]; 138 j10 = x->input[10]; 139 j11 = x->input[11]; 140 j12 = x->input[12]; 141 j13 = x->input[13]; 142 j14 = x->input[14]; 143 j15 = x->input[15]; 144 145 for (;;) { 146 if (bytes < 64) { 147 for (i = 0;i < bytes;++i) tmp[i] = m[i]; 148 m = tmp; 149 ctarget = c; 150 c = tmp; 151 } 152 x0 = j0; 153 x1 = j1; 154 x2 = j2; 155 x3 = j3; 156 x4 = j4; 157 x5 = j5; 158 x6 = j6; 159 x7 = j7; 160 x8 = j8; 161 x9 = j9; 162 x10 = j10; 163 x11 = j11; 164 x12 = j12; 165 x13 = j13; 166 x14 = j14; 167 x15 = j15; 168 for (i = 20;i > 0;i -= 2) { 169 QUARTERROUND( x0, x4, x8,x12) 170 QUARTERROUND( x1, x5, x9,x13) 171 QUARTERROUND( x2, x6,x10,x14) 172 QUARTERROUND( x3, x7,x11,x15) 173 QUARTERROUND( x0, x5,x10,x15) 174 QUARTERROUND( x1, x6,x11,x12) 175 QUARTERROUND( x2, x7, x8,x13) 176 QUARTERROUND( x3, x4, x9,x14) 177 } 178 x0 = PLUS(x0,j0); 179 x1 = PLUS(x1,j1); 180 x2 = PLUS(x2,j2); 181 x3 = PLUS(x3,j3); 182 x4 = PLUS(x4,j4); 183 x5 = PLUS(x5,j5); 184 x6 = PLUS(x6,j6); 185 x7 = PLUS(x7,j7); 186 x8 = PLUS(x8,j8); 187 x9 = PLUS(x9,j9); 188 x10 = PLUS(x10,j10); 189 x11 = PLUS(x11,j11); 190 x12 = PLUS(x12,j12); 191 x13 = PLUS(x13,j13); 192 x14 = PLUS(x14,j14); 193 x15 = PLUS(x15,j15); 194 195 #ifndef KEYSTREAM_ONLY 196 x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 197 x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 198 x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 199 x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 200 x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 201 x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 202 x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 203 x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 204 x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 205 x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 206 x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 207 x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 208 x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 209 x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 210 x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 211 x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 212 #endif 213 214 j12 = PLUSONE(j12); 215 if (!j12) { 216 j13 = PLUSONE(j13); 217 /* stopping at 2^70 bytes per nonce is user's responsibility */ 218 } 219 220 U32TO8_LITTLE(c + 0,x0); 221 U32TO8_LITTLE(c + 4,x1); 222 U32TO8_LITTLE(c + 8,x2); 223 U32TO8_LITTLE(c + 12,x3); 224 U32TO8_LITTLE(c + 16,x4); 225 U32TO8_LITTLE(c + 20,x5); 226 U32TO8_LITTLE(c + 24,x6); 227 U32TO8_LITTLE(c + 28,x7); 228 U32TO8_LITTLE(c + 32,x8); 229 U32TO8_LITTLE(c + 36,x9); 230 U32TO8_LITTLE(c + 40,x10); 231 U32TO8_LITTLE(c + 44,x11); 232 U32TO8_LITTLE(c + 48,x12); 233 U32TO8_LITTLE(c + 52,x13); 234 U32TO8_LITTLE(c + 56,x14); 235 U32TO8_LITTLE(c + 60,x15); 236 237 if (bytes <= 64) { 238 if (bytes < 64) { 239 for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 240 } 241 x->input[12] = j12; 242 x->input[13] = j13; 243 return; 244 } 245 bytes -= 64; 246 c += 64; 247 #ifndef KEYSTREAM_ONLY 248 m += 64; 249 #endif 250 } 251 } 252 253 /* The following is taken from arc4random.c 254 * from openssh/openssh-portable/, which has an ISC license, 255 * which is GPL compatible. 256 */ 257 258 /* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */ 259 /* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $ */ 260 /* 261 * Copyright (c) 1996, David Mazieres <dm@uun.org> 262 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> 263 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> 264 * 265 * Permission to use, copy, modify, and distribute this software for any 266 * purpose with or without fee is hereby granted, provided that the above 267 * copyright notice and this permission notice appear in all copies. 268 * 269 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 270 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 271 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 272 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 273 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 274 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 275 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 276 */ 277 278 /* Modified for UnrealIRCd by Bram Matthys ("Syzop") in 2019. 279 * Things like taking out #if (n)def's for openssl (which we always 280 * compile with), re-indenting, removing various stuff, etc. 281 */ 282 283 284 285 #define KEYSZ 32 286 #define IVSZ 8 287 #define BLOCKSZ 64 288 #define RSBUFSZ (16*BLOCKSZ) 289 static int rs_initialized; 290 static chacha_ctx rs; /* chacha context for random keystream */ 291 static u_char rs_buf[RSBUFSZ]; /* keystream blocks */ 292 static size_t rs_have; /* valid bytes at end of rs_buf */ 293 static size_t rs_count; /* bytes till reseed */ 294 295 static inline void _rs_rekey(u_char *dat, size_t datlen); 296 297 static inline void _rs_init(u_char *buf, size_t n) 298 { 299 if (n < KEYSZ + IVSZ) 300 return; 301 chacha_keysetup(&rs, buf, KEYSZ * 8, 0); 302 chacha_ivsetup(&rs, buf + KEYSZ); 303 } 304 305 static void _rs_stir(void) 306 { 307 u_char rnd[KEYSZ + IVSZ]; 308 309 if (RAND_bytes(rnd, sizeof(rnd)) <= 0) 310 { 311 unreal_log(ULOG_FATAL, "random", "RANDOM_OUT_OF_BYTES", NULL, 312 "Could not obtain random bytes, error $tls_error_code", 313 log_data_integer("tls_error_code", ERR_get_error())); 314 abort(); 315 } 316 317 if (!rs_initialized) { 318 rs_initialized = 1; 319 _rs_init(rnd, sizeof(rnd)); 320 } else 321 _rs_rekey(rnd, sizeof(rnd)); 322 #ifdef HAVE_EXPLICIT_BZERO 323 explicit_bzero(rnd, sizeof(rnd)); 324 #else 325 /* Not terribly important in this case */ 326 memset(rnd, 0, sizeof(rnd)); 327 #endif 328 /* invalidate rs_buf */ 329 rs_have = 0; 330 memset(rs_buf, 0, RSBUFSZ); 331 332 rs_count = 1600000; 333 } 334 335 static inline void _rs_stir_if_needed(size_t len) 336 { 337 if (rs_count <= len || !rs_initialized) { 338 _rs_stir(); 339 } else 340 rs_count -= len; 341 } 342 343 static inline void _rs_rekey(u_char *dat, size_t datlen) 344 { 345 #ifndef KEYSTREAM_ONLY 346 memset(rs_buf, 0,RSBUFSZ); 347 #endif 348 /* fill rs_buf with the keystream */ 349 chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ); 350 /* mix in optional user provided data */ 351 if (dat) { 352 size_t i, m; 353 354 m = MIN(datlen, KEYSZ + IVSZ); 355 for (i = 0; i < m; i++) 356 rs_buf[i] ^= dat[i]; 357 } 358 /* immediately reinit for backtracking resistance */ 359 _rs_init(rs_buf, KEYSZ + IVSZ); 360 memset(rs_buf, 0, KEYSZ + IVSZ); 361 rs_have = RSBUFSZ - KEYSZ - IVSZ; 362 } 363 364 static inline void _rs_random_buf(void *_buf, size_t n) 365 { 366 u_char *buf = (u_char *)_buf; 367 size_t m; 368 369 _rs_stir_if_needed(n); 370 while (n > 0) { 371 if (rs_have > 0) { 372 m = MIN(n, rs_have); 373 memcpy(buf, rs_buf + RSBUFSZ - rs_have, m); 374 memset(rs_buf + RSBUFSZ - rs_have, 0, m); 375 buf += m; 376 n -= m; 377 rs_have -= m; 378 } 379 if (rs_have == 0) 380 _rs_rekey(NULL, 0); 381 } 382 } 383 384 static inline void _rs_random_u32(uint32_t *val) 385 { 386 _rs_stir_if_needed(sizeof(*val)); 387 if (rs_have < sizeof(*val)) 388 _rs_rekey(NULL, 0); 389 memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val)); 390 memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val)); 391 rs_have -= sizeof(*val); 392 return; 393 } 394 395 void arc4random_stir(void) 396 { 397 _rs_stir(); 398 } 399 400 void arc4random_doaddrandom(u_char *dat, int datlen) 401 { 402 int m; 403 404 if (!rs_initialized) 405 _rs_stir(); 406 while (datlen > 0) { 407 m = MIN(datlen, KEYSZ + IVSZ); 408 _rs_rekey(dat, m); 409 dat += m; 410 datlen -= m; 411 } 412 } 413 414 #endif /* !HAVE_ARC4RANDOM */ 415 416 /* UnrealIRCd-specific functions follow */ 417 418 static void arc4_addrandom(void *dat, int datlen) 419 { 420 arc4random_doaddrandom((unsigned char *)dat, datlen); 421 return; 422 } 423 424 void add_entropy_configfile(struct stat *st, char *buf) 425 { 426 char sha256buf[SHA256_DIGEST_LENGTH]; 427 428 arc4_addrandom(&st->st_size, sizeof(st->st_size)); 429 arc4_addrandom(&st->st_mtime, sizeof(st->st_mtime)); 430 sha256hash_binary(sha256buf, buf, strlen(buf)); 431 arc4_addrandom(sha256buf, sizeof(sha256buf)); 432 } 433 434 /* 435 * init_random, written by Syzop. 436 * This function tries to initialize the arc4 random number generator securely. 437 */ 438 void init_random() 439 { 440 struct { 441 #ifndef _WIN32 442 struct timeval nowt; /* time */ 443 char rnd[32]; /* /dev/urandom */ 444 #else 445 struct _timeb nowt; /* time */ 446 MEMORYSTATUS mstat; /* memory status */ 447 #endif 448 } rdat; 449 450 #ifndef _WIN32 451 int fd; 452 #endif 453 454 _rs_stir(); 455 456 /* Grab OS specific "random" data */ 457 #ifndef _WIN32 458 gettimeofday(&rdat.nowt, NULL); 459 fd = open("/dev/urandom", O_RDONLY); 460 if (fd >= 0) 461 { 462 int n = read(fd, &rdat.rnd, sizeof(rdat.rnd)); 463 close(fd); 464 } 465 #else 466 _ftime(&rdat.nowt); 467 GlobalMemoryStatus (&rdat.mstat); 468 #endif 469 470 arc4_addrandom(&rdat, sizeof(rdat)); 471 472 /* NOTE: addtional entropy is added by add_entropy_* function(s) */ 473 } 474 475 uint32_t arc4random(void) 476 { 477 uint32_t val; 478 479 _rs_random_u32(&val); 480 return val; 481 } 482 483 /** Get 8 bits (1 byte) of randomness */ 484 u_char getrandom8() 485 { 486 return arc4random() & 0xff; 487 } 488 489 /** Get 16 bits (2 bytes) of randomness */ 490 uint16_t getrandom16() 491 { 492 return arc4random() & 0xffff; 493 } 494 495 /** Get 32 bits (4 bytes) of randomness */ 496 uint32_t getrandom32() 497 { 498 return arc4random(); 499 } 500 501 /** Generate an alphanumeric string (eg: XzHe5G). 502 * @param buf The buffer 503 * @param numbytes The number of random bytes. 504 * @note Note that numbytes+1 bytes are written to buf. 505 * In other words, numbytes does NOT include the NUL byte. 506 */ 507 void gen_random_alnum(char *buf, int numbytes) 508 { 509 for (; numbytes > 0; numbytes--) 510 { 511 unsigned char v = getrandom8() % (26+26+10); 512 if (v < 26) 513 *buf++ = 'a'+v; 514 else if (v < 52) 515 *buf++ = 'A'+(v-26); 516 else 517 *buf++ = '0'+(v-52); 518 } 519 *buf = '\0'; 520 }