Return to rdrand_rng.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / rdrand |
1.1 misho 1: /* 2: * Copyright (C) 2012 Martin Willi 3: * Copyright (C) 2012 revosec AG 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "rdrand_rng.h" 17: 18: #include <unistd.h> 19: 20: typedef struct private_rdrand_rng_t private_rdrand_rng_t; 21: 22: /** 23: * Private data of an rdrand_rng_t object. 24: */ 25: struct private_rdrand_rng_t { 26: 27: /** 28: * Public rdrand_rng_t interface. 29: */ 30: rdrand_rng_t public; 31: 32: /** 33: * Quality we produce RNG data 34: */ 35: rng_quality_t quality; 36: }; 37: 38: /** 39: * Retries for failed RDRAND instructions 40: */ 41: #define MAX_TRIES 16 42: 43: /** 44: * After how many bytes should we reseed for RNG_STRONG 45: * (must be a power of two >= 8) 46: */ 47: #define FORCE_RESEED 16 48: 49: /** 50: * How many times we mix reseeded RDRAND output when using RNG_TRUE 51: */ 52: #define MIX_ROUNDS 32 53: 54: /** 55: * Get a two byte word using RDRAND 56: */ 57: static bool rdrand16(uint16_t *out) 58: { 59: u_char res; 60: int i; 61: 62: for (i = 0; i < MAX_TRIES; i++) 63: { 64: asm(".byte 0x66;.byte 0x0f;.byte 0xc7;.byte 0xf0; " /* rdrand */ 65: "setc %1;" 66: : "=a"(*out), "=qm"(res)); 67: 68: if (res) 69: { 70: return TRUE; 71: } 72: } 73: return FALSE; 74: } 75: 76: /** 77: * Get a four byte word using RDRAND 78: */ 79: static bool rdrand32(uint32_t *out) 80: { 81: u_char res; 82: int i; 83: 84: for (i = 0; i < MAX_TRIES; i++) 85: { 86: asm(".byte 0x0f;.byte 0xc7;.byte 0xf0;" /* rdrand */ 87: "setc %1;" 88: : "=a"(*out), "=qm"(res)); 89: 90: if (res) 91: { 92: return TRUE; 93: } 94: } 95: return FALSE; 96: } 97: 98: #ifdef __x86_64__ 99: /** 100: * Get a eight byte word using RDRAND 101: */ 102: static bool rdrand64(uint64_t *out) 103: { 104: u_char res; 105: int i; 106: 107: for (i = 0; i < MAX_TRIES; i++) 108: { 109: asm(".byte 0x48;.byte 0x0f;.byte 0xc7;.byte 0xf0;" /* rdrand */ 110: "setc %1;" 111: : "=a"(*out), "=qm"(res)); 112: 113: if (res) 114: { 115: return TRUE; 116: } 117: } 118: return FALSE; 119: } 120: #endif /* __x86_64__ */ 121: 122: /** 123: * Get a one byte word using RDRAND 124: */ 125: static bool rdrand8(uint8_t *out) 126: { 127: uint16_t u16; 128: 129: if (!rdrand16(&u16)) 130: { 131: return FALSE; 132: } 133: *out = u16; 134: return TRUE; 135: } 136: 137: /** 138: * Get a 16 byte word using RDRAND 139: */ 140: static bool rdrand128(void *out) 141: { 142: #ifdef __x86_64__ 143: if (!rdrand64(out) || 144: !rdrand64(out + sizeof(uint64_t))) 145: { 146: return FALSE; 147: } 148: #else /* __i386__ */ 149: if (!rdrand32(out) || 150: !rdrand32(out + 1 * sizeof(uint32_t)) || 151: !rdrand32(out + 2 * sizeof(uint32_t)) || 152: !rdrand32(out + 3 * sizeof(uint32_t))) 153: { 154: return FALSE; 155: } 156: #endif /* __x86_64__ / __i386__ */ 157: return TRUE; 158: } 159: 160: /** 161: * Enforce a DRNG reseed by reading 511 128-bit samples 162: */ 163: static bool reseed() 164: { 165: int i; 166: 167: #ifdef __x86_64__ 168: uint64_t tmp; 169: 170: for (i = 0; i < 511 * 16 / sizeof(uint64_t); i++) 171: { 172: if (!rdrand64(&tmp)) 173: { 174: return FALSE; 175: } 176: } 177: #else /* __i386__ */ 178: uint32_t tmp; 179: 180: for (i = 0; i < 511 * 16 / sizeof(uint32_t); i++) 181: { 182: if (!rdrand32(&tmp)) 183: { 184: return FALSE; 185: } 186: } 187: #endif /* __x86_64__ / __i386__ */ 188: return TRUE; 189: } 190: 191: /** 192: * Fill a preallocated chunk of data with random bytes 193: */ 194: static bool rdrand_chunk(private_rdrand_rng_t *this, chunk_t chunk) 195: { 196: if (this->quality == RNG_STRONG) 197: { 198: if (!reseed()) 199: { 200: return FALSE; 201: } 202: } 203: 204: /* align to 2 byte */ 205: if (chunk.len >= sizeof(uint8_t)) 206: { 207: if ((uintptr_t)chunk.ptr % 2) 208: { 209: if (!rdrand8((uint8_t*)chunk.ptr)) 210: { 211: return FALSE; 212: } 213: chunk = chunk_skip(chunk, sizeof(uint8_t)); 214: } 215: } 216: 217: /* align to 4 byte */ 218: if (chunk.len >= sizeof(uint16_t)) 219: { 220: if ((uintptr_t)chunk.ptr % 4) 221: { 222: if (!rdrand16((uint16_t*)chunk.ptr)) 223: { 224: return FALSE; 225: } 226: chunk = chunk_skip(chunk, sizeof(uint16_t)); 227: } 228: } 229: 230: #ifdef __x86_64__ 231: 232: /* align to 8 byte */ 233: if (chunk.len >= sizeof(uint32_t)) 234: { 235: if ((uintptr_t)chunk.ptr % 8) 236: { 237: if (!rdrand32((uint32_t*)chunk.ptr)) 238: { 239: return FALSE; 240: } 241: chunk = chunk_skip(chunk, sizeof(uint32_t)); 242: } 243: } 244: 245: /* fill with 8 byte words */ 246: while (chunk.len >= sizeof(uint64_t)) 247: { 248: if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED == 0) 249: { 250: if (!reseed()) 251: { 252: return FALSE; 253: } 254: } 255: if (!rdrand64((uint64_t*)chunk.ptr)) 256: { 257: return FALSE; 258: } 259: chunk = chunk_skip(chunk, sizeof(uint64_t)); 260: } 261: 262: /* append 4 byte word */ 263: if (chunk.len >= sizeof(uint32_t)) 264: { 265: if (!rdrand32((uint32_t*)chunk.ptr)) 266: { 267: return FALSE; 268: } 269: chunk = chunk_skip(chunk, sizeof(uint32_t)); 270: } 271: 272: #else /* __i386__ */ 273: 274: /* fill with 4 byte words */ 275: while (chunk.len >= sizeof(uint32_t)) 276: { 277: if (this->quality == RNG_STRONG && chunk.len % FORCE_RESEED == 0) 278: { 279: if (!reseed()) 280: { 281: return FALSE; 282: } 283: } 284: if (!rdrand32((uint32_t*)chunk.ptr)) 285: { 286: return FALSE; 287: } 288: chunk = chunk_skip(chunk, sizeof(uint32_t)); 289: } 290: 291: #endif /* __x86_64__ / __i386__ */ 292: 293: if (this->quality == RNG_STRONG) 294: { 295: if (!reseed()) 296: { 297: return FALSE; 298: } 299: } 300: 301: /* append 2 byte word */ 302: if (chunk.len >= sizeof(uint16_t)) 303: { 304: if (!rdrand16((uint16_t*)chunk.ptr)) 305: { 306: return FALSE; 307: } 308: chunk = chunk_skip(chunk, sizeof(uint16_t)); 309: } 310: 311: /* append 1 byte word */ 312: if (chunk.len >= sizeof(uint8_t)) 313: { 314: if (!rdrand8((uint8_t*)chunk.ptr)) 315: { 316: return FALSE; 317: } 318: chunk = chunk_skip(chunk, sizeof(uint8_t)); 319: } 320: 321: return TRUE; 322: } 323: 324: /** 325: * Stronger variant mixing reseeded results of rdrand output 326: * 327: * This is based on the Intel DRNG "Software Implementation Guide", using 328: * AES-CBC to mix several reseeded RDRAND outputs. 329: */ 330: static bool rdrand_mixed(private_rdrand_rng_t *this, chunk_t chunk) 331: { 332: u_char block[16], forward[16], key[16], iv[16]; 333: crypter_t *crypter; 334: int i, len; 335: 336: memset(iv, 0, sizeof(iv)); 337: crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, 16); 338: if (!crypter) 339: { 340: return FALSE; 341: } 342: for (i = 0; i < sizeof(key); i++) 343: { 344: key[i] = i; 345: } 346: if (!crypter->set_key(crypter, chunk_from_thing(key))) 347: { 348: crypter->destroy(crypter); 349: return FALSE; 350: } 351: while (chunk.len > 0) 352: { 353: memset(forward, 0, sizeof(forward)); 354: for (i = 0; i < MIX_ROUNDS; i++) 355: { 356: /* sleep to reseed PRNG */ 357: usleep(10); 358: if (!rdrand128(block)) 359: { 360: crypter->destroy(crypter); 361: return FALSE; 362: } 363: memxor(forward, block, sizeof(block)); 364: if (!crypter->encrypt(crypter, chunk_from_thing(forward), 365: chunk_from_thing(iv), NULL)) 366: { 367: crypter->destroy(crypter); 368: return FALSE; 369: } 370: } 371: len = min(chunk.len, sizeof(forward)); 372: memcpy(chunk.ptr, forward, len); 373: chunk = chunk_skip(chunk, len); 374: } 375: crypter->destroy(crypter); 376: 377: return TRUE; 378: } 379: 380: METHOD(rng_t, get_bytes, bool, 381: private_rdrand_rng_t *this, size_t bytes, uint8_t *buffer) 382: { 383: switch (this->quality) 384: { 385: case RNG_WEAK: 386: case RNG_STRONG: 387: return rdrand_chunk(this, chunk_create(buffer, bytes)); 388: case RNG_TRUE: 389: return rdrand_mixed(this, chunk_create(buffer, bytes)); 390: default: 391: return FALSE; 392: } 393: } 394: 395: METHOD(rng_t, allocate_bytes, bool, 396: private_rdrand_rng_t *this, size_t bytes, chunk_t *chunk) 397: { 398: *chunk = chunk_alloc(bytes); 399: if (get_bytes(this, bytes, chunk->ptr)) 400: { 401: return TRUE; 402: } 403: free(chunk->ptr); 404: return FALSE; 405: } 406: 407: METHOD(rng_t, destroy, void, 408: private_rdrand_rng_t *this) 409: { 410: free(this); 411: } 412: 413: /* 414: * Described in header. 415: */ 416: rdrand_rng_t *rdrand_rng_create(rng_quality_t quality) 417: { 418: private_rdrand_rng_t *this; 419: 420: switch (quality) 421: { 422: case RNG_WEAK: 423: case RNG_STRONG: 424: case RNG_TRUE: 425: break; 426: default: 427: return NULL; 428: } 429: 430: INIT(this, 431: .public = { 432: .rng = { 433: .get_bytes = _get_bytes, 434: .allocate_bytes = _allocate_bytes, 435: .destroy = _destroy, 436: }, 437: }, 438: .quality = quality, 439: ); 440: 441: return &this->public; 442: }