det_rng.c (3992B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "blapi.h" 6 #include "blapit.h" 7 #include "Hacl_Chacha20.h" 8 #include "nssilock.h" 9 #include "seccomon.h" 10 #include "secerr.h" 11 #include "prinit.h" 12 13 #define GLOBAL_BYTES_SIZE 100 14 static PRUint8 globalBytes[GLOBAL_BYTES_SIZE]; 15 static unsigned long globalNumCalls = 0; 16 static PZLock *rng_lock = NULL; 17 static PRCallOnceType coRNGInit; 18 static const PRCallOnceType pristineCallOnce; 19 20 static PRStatus 21 rng_init(void) 22 { 23 rng_lock = PZ_NewLock(nssILockOther); 24 if (!rng_lock) { 25 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 26 return PR_FAILURE; 27 } 28 /* --- LOCKED --- */ 29 PZ_Lock(rng_lock); 30 memset(globalBytes, 0, GLOBAL_BYTES_SIZE); 31 PZ_Unlock(rng_lock); 32 /* --- UNLOCKED --- */ 33 34 return PR_SUCCESS; 35 } 36 37 SECStatus 38 RNG_RNGInit(void) 39 { 40 /* Allow only one call to initialize the context */ 41 if (PR_CallOnce(&coRNGInit, rng_init) != PR_SUCCESS) { 42 return SECFailure; 43 } 44 45 return SECSuccess; 46 } 47 48 /* Take min(size, GLOBAL_BYTES_SIZE) bytes from data and use as seed and reset 49 * the rng state. */ 50 SECStatus 51 RNG_RandomUpdate(const void *data, size_t bytes) 52 { 53 /* Check for a valid RNG lock. */ 54 PORT_Assert(rng_lock != NULL); 55 if (rng_lock == NULL) { 56 PORT_SetError(SEC_ERROR_INVALID_ARGS); 57 return SECFailure; 58 } 59 60 /* --- LOCKED --- */ 61 PZ_Lock(rng_lock); 62 memset(globalBytes, 0, GLOBAL_BYTES_SIZE); 63 globalNumCalls = 0; 64 if (data) { 65 memcpy(globalBytes, (PRUint8 *)data, PR_MIN(bytes, GLOBAL_BYTES_SIZE)); 66 } 67 PZ_Unlock(rng_lock); 68 /* --- UNLOCKED --- */ 69 70 return SECSuccess; 71 } 72 73 SECStatus 74 RNG_GenerateGlobalRandomBytes(void *dest, size_t len) 75 { 76 static const uint8_t key[32] = { 0 }; 77 uint8_t nonce[12] = { 0 }; 78 79 /* Check for a valid RNG lock. */ 80 PORT_Assert(rng_lock != NULL); 81 if (rng_lock == NULL) { 82 PORT_SetError(SEC_ERROR_INVALID_ARGS); 83 return SECFailure; 84 } 85 86 /* --- LOCKED --- */ 87 PZ_Lock(rng_lock); 88 89 memcpy(nonce, &globalNumCalls, sizeof(globalNumCalls)); 90 globalNumCalls++; 91 92 ChaCha20Poly1305Context *cx = 93 ChaCha20Poly1305_CreateContext(key, sizeof(key), 16); 94 if (!cx) { 95 PORT_SetError(SEC_ERROR_NO_MEMORY); 96 PZ_Unlock(rng_lock); 97 return SECFailure; 98 } 99 100 memset(dest, 0, len); 101 memcpy(dest, globalBytes, PR_MIN(len, GLOBAL_BYTES_SIZE)); 102 Hacl_Chacha20_chacha20_encrypt(len, (uint8_t *)dest, (uint8_t *)dest, 103 (uint8_t *)key, nonce, 0); 104 ChaCha20Poly1305_DestroyContext(cx, PR_TRUE); 105 106 PZ_Unlock(rng_lock); 107 /* --- UNLOCKED --- */ 108 109 return SECSuccess; 110 } 111 112 void 113 RNG_RNGShutdown(void) 114 { 115 if (rng_lock) { 116 PZ_DestroyLock(rng_lock); 117 rng_lock = NULL; 118 } 119 coRNGInit = pristineCallOnce; 120 } 121 122 /* Test functions are not implemented! */ 123 SECStatus 124 PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, 125 const PRUint8 *nonce, unsigned int nonce_len, 126 const PRUint8 *personal_string, unsigned int ps_len) 127 { 128 return SECFailure; 129 } 130 131 SECStatus 132 PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, 133 const PRUint8 *additional, unsigned int additional_len) 134 { 135 return SECFailure; 136 } 137 138 SECStatus 139 PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, 140 const PRUint8 *additional, unsigned int additional_len) 141 { 142 return SECFailure; 143 } 144 145 SECStatus 146 PRNGTEST_Uninstantiate() 147 { 148 return SECFailure; 149 } 150 151 SECStatus 152 PRNGTEST_RunHealthTests() 153 { 154 return SECFailure; 155 } 156 157 SECStatus 158 PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len, 159 const PRUint8 *nonce, unsigned int nonce_len, 160 const PRUint8 *personal_string, unsigned int ps_len) 161 { 162 return SECFailure; 163 }