16ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org/* 26ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * prng.c 36ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 46ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * pseudorandom source 56ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 66ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * David A. McGrew 76ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * Cisco Systems, Inc. 86ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org */ 96ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org/* 106ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 116ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * Copyright(c) 2001-2006 Cisco Systems, Inc. 126ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * All rights reserved. 136ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 146ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * Redistribution and use in source and binary forms, with or without 156ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * modification, are permitted provided that the following conditions 166ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * are met: 176ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 186ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * Redistributions of source code must retain the above copyright 196ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * notice, this list of conditions and the following disclaimer. 206ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 216ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * Redistributions in binary form must reproduce the above 226ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * copyright notice, this list of conditions and the following 236ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * disclaimer in the documentation and/or other materials provided 246ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * with the distribution. 256ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 266ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * Neither the name of the Cisco Systems, Inc. nor the names of its 276ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * contributors may be used to endorse or promote products derived 286ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * from this software without specific prior written permission. 296ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 306ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 316ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 326ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 336ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 346ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 356ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 366ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 376ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 386ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 396ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 406ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 416ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * OF THE POSSIBILITY OF SUCH DAMAGE. 426ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 436ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org */ 446ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 456ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 466ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org#include "prng.h" 476ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 486ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org/* single, global prng structure */ 496ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 506ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgx917_prng_t x917_prng; 516ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 526ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgerr_status_t 536ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgx917_prng_init(rand_source_func_t random_source) { 546ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org uint8_t tmp_key[16]; 556ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org err_status_t status; 566ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 576ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* initialize output count to zero */ 586ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org x917_prng.octet_count = 0; 596ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 606ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* set random source */ 616ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org x917_prng.rand = random_source; 626ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 636ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* initialize secret key from random source */ 646ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org status = random_source(tmp_key, 16); 656ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org if (status) 666ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org return status; 676ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 686ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* expand aes key */ 696ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org aes_expand_encryption_key(tmp_key, 16, &x917_prng.key); 706ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 716ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* initialize prng state from random source */ 726ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org status = x917_prng.rand((uint8_t *)&x917_prng.state, 16); 736ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org if (status) 746ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org return status; 756ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 766ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org return err_status_ok; 776ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org} 786ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 796ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgerr_status_t 806ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgx917_prng_get_octet_string(uint8_t *dest, uint32_t len) { 816ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org uint32_t t; 826ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org v128_t buffer; 836ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org uint32_t i, tail_len; 846ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org err_status_t status; 856ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 866ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* 876ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * if we need to re-initialize the prng, do so now 886ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * 896ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org * avoid overflows by subtracting instead of adding 906ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org */ 916ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org if (x917_prng.octet_count > MAX_PRNG_OUT_LEN - len) { 926ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org status = x917_prng_init(x917_prng.rand); 936ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org if (status) 946ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org return status; 956ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org } 966ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org x917_prng.octet_count += len; 976ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 986ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* find out the time */ 996ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org t = (uint32_t)time(NULL); 1006ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1016ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* loop until we have output enough data */ 1026ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org for (i=0; i < len/16; i++) { 1036ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1046ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* exor time into state */ 1056ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org x917_prng.state.v32[0] ^= t; 1066ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1076ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* copy state into buffer */ 1086ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org v128_copy(&buffer, &x917_prng.state); 1096ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1106ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* apply aes to buffer */ 1116ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org aes_encrypt(&buffer, &x917_prng.key); 1126ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1136ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* write data to output */ 1146ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[0]; 1156ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[1]; 1166ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[2]; 1176ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[3]; 1186ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[4]; 1196ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[5]; 1206ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[6]; 1216ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[7]; 1226ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[8]; 1236ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[9]; 1246ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[10]; 1256ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[11]; 1266ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[12]; 1276ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[13]; 1286ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[14]; 1296ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[15]; 1306ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1316ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* exor time into buffer */ 1326ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org buffer.v32[0] ^= t; 1336ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1346ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* encrypt buffer */ 1356ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org aes_encrypt(&buffer, &x917_prng.key); 1366ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1376ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* copy buffer into state */ 1386ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org v128_copy(&x917_prng.state, &buffer); 1396ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1406ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org } 1416ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1426ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* if we need to output any more octets, we'll do so now */ 1436ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org tail_len = len % 16; 1446ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org if (tail_len) { 1456ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1466ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* exor time into state */ 1476ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org x917_prng.state.v32[0] ^= t; 1486ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1496ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* copy value into buffer */ 1506ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org v128_copy(&buffer, &x917_prng.state); 1516ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1526ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* apply aes to buffer */ 1536ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org aes_encrypt(&buffer, &x917_prng.key); 1546ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1556ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* write data to output */ 1566ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org for (i=0; i < tail_len; i++) { 1576ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org *dest++ = buffer.v8[i]; 1586ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org } 1596ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1606ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* now update the state one more time */ 1616ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1626ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* exor time into buffer */ 1636ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org buffer.v32[0] ^= t; 1646ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1656ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* encrypt buffer */ 1666ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org aes_encrypt(&buffer, &x917_prng.key); 1676ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1686ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org /* copy buffer into state */ 1696ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org v128_copy(&x917_prng.state, &buffer); 1706ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1716ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org } 1726ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1736ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org return err_status_ok; 1746ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org} 1756ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1766ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgerr_status_t 1776ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.orgx917_prng_deinit(void) { 1786ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org 1796ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org return err_status_ok; 1806ed0ee98e1c3d29a0ef79996f7d1abf174f39besergeyu@chromium.org} 181