1 /* 2 * prng.c 3 * 4 * pseudorandom source 5 * 6 * David A. McGrew 7 * Cisco Systems, Inc. 8 */ 9 /* 10 * 11 * Copyright(c) 2001-2006 Cisco Systems, Inc. 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 18 * Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 21 * Redistributions in binary form must reproduce the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer in the documentation and/or other materials provided 24 * with the distribution. 25 * 26 * Neither the name of the Cisco Systems, Inc. nor the names of its 27 * contributors may be used to endorse or promote products derived 28 * from this software without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 41 * OF THE POSSIBILITY OF SUCH DAMAGE. 42 * 43 */ 44 45 46 #include "prng.h" 47 48 /* single, global prng structure */ 49 50 x917_prng_t x917_prng; 51 52 err_status_t 53 x917_prng_init(rand_source_func_t random_source) { 54 v128_t tmp_key; 55 err_status_t status; 56 57 /* initialize output count to zero */ 58 x917_prng.octet_count = 0; 59 60 /* set random source */ 61 x917_prng.rand = random_source; 62 63 /* initialize secret key from random source */ 64 status = random_source((uint8_t *)&tmp_key, 16); 65 if (status) 66 return status; 67 68 /* expand aes key */ 69 aes_expand_encryption_key(&tmp_key, x917_prng.key); 70 71 /* initialize prng state from random source */ 72 status = x917_prng.rand((uint8_t *)&x917_prng.state, 16); 73 if (status) 74 return status; 75 76 return err_status_ok; 77 } 78 79 err_status_t 80 x917_prng_get_octet_string(uint8_t *dest, uint32_t len) { 81 uint32_t t; 82 v128_t buffer; 83 uint32_t i, tail_len; 84 err_status_t status; 85 86 /* 87 * if we need to re-initialize the prng, do so now 88 * 89 * avoid overflows by subtracting instead of adding 90 */ 91 if (x917_prng.octet_count > MAX_PRNG_OUT_LEN - len) { 92 status = x917_prng_init(x917_prng.rand); 93 if (status) 94 return status; 95 } 96 x917_prng.octet_count += len; 97 98 /* find out the time */ 99 t = (uint32_t)time(NULL); 100 101 /* loop until we have output enough data */ 102 for (i=0; i < len/16; i++) { 103 104 /* exor time into state */ 105 x917_prng.state.v32[0] ^= t; 106 107 /* copy state into buffer */ 108 v128_copy(&buffer, &x917_prng.state); 109 110 /* apply aes to buffer */ 111 aes_encrypt(&buffer, x917_prng.key); 112 113 /* write data to output */ 114 *dest++ = buffer.v8[0]; 115 *dest++ = buffer.v8[1]; 116 *dest++ = buffer.v8[2]; 117 *dest++ = buffer.v8[3]; 118 *dest++ = buffer.v8[4]; 119 *dest++ = buffer.v8[5]; 120 *dest++ = buffer.v8[6]; 121 *dest++ = buffer.v8[7]; 122 *dest++ = buffer.v8[8]; 123 *dest++ = buffer.v8[9]; 124 *dest++ = buffer.v8[10]; 125 *dest++ = buffer.v8[11]; 126 *dest++ = buffer.v8[12]; 127 *dest++ = buffer.v8[13]; 128 *dest++ = buffer.v8[14]; 129 *dest++ = buffer.v8[15]; 130 131 /* exor time into buffer */ 132 buffer.v32[0] ^= t; 133 134 /* encrypt buffer */ 135 aes_encrypt(&buffer, x917_prng.key); 136 137 /* copy buffer into state */ 138 v128_copy(&x917_prng.state, &buffer); 139 140 } 141 142 /* if we need to output any more octets, we'll do so now */ 143 tail_len = len % 16; 144 if (tail_len) { 145 146 /* exor time into state */ 147 x917_prng.state.v32[0] ^= t; 148 149 /* copy value into buffer */ 150 v128_copy(&buffer, &x917_prng.state); 151 152 /* apply aes to buffer */ 153 aes_encrypt(&buffer, x917_prng.key); 154 155 /* write data to output */ 156 for (i=0; i < tail_len; i++) { 157 *dest++ = buffer.v8[i]; 158 } 159 160 /* now update the state one more time */ 161 162 /* exor time into buffer */ 163 buffer.v32[0] ^= t; 164 165 /* encrypt buffer */ 166 aes_encrypt(&buffer, x917_prng.key); 167 168 /* copy buffer into state */ 169 v128_copy(&x917_prng.state, &buffer); 170 171 } 172 173 return err_status_ok; 174 } 175 176 err_status_t 177 x917_prng_deinit(void) { 178 179 return err_status_ok; 180 } 181