Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blapi.h"
#include "blapit.h"
#include "Hacl_Chacha20.h"
#include "nssilock.h"
#include "seccomon.h"
#include "secerr.h"
#include "prinit.h"
#define GLOBAL_BYTES_SIZE 100
static PRUint8 globalBytes[GLOBAL_BYTES_SIZE];
static unsigned long globalNumCalls = 0;
static PZLock *rng_lock = NULL;
static PRCallOnceType coRNGInit;
static const PRCallOnceType pristineCallOnce;
static PRStatus
rng_init(void)
{
rng_lock = PZ_NewLock(nssILockOther);
if (!rng_lock) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return PR_FAILURE;
}
/* --- LOCKED --- */
PZ_Lock(rng_lock);
memset(globalBytes, 0, GLOBAL_BYTES_SIZE);
PZ_Unlock(rng_lock);
/* --- UNLOCKED --- */
return PR_SUCCESS;
}
SECStatus
RNG_RNGInit(void)
{
/* Allow only one call to initialize the context */
if (PR_CallOnce(&coRNGInit, rng_init) != PR_SUCCESS) {
return SECFailure;
}
return SECSuccess;
}
/* Take min(size, GLOBAL_BYTES_SIZE) bytes from data and use as seed and reset
* the rng state. */
SECStatus
RNG_RandomUpdate(const void *data, size_t bytes)
{
/* Check for a valid RNG lock. */
PORT_Assert(rng_lock != NULL);
if (rng_lock == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* --- LOCKED --- */
PZ_Lock(rng_lock);
memset(globalBytes, 0, GLOBAL_BYTES_SIZE);
globalNumCalls = 0;
if (data) {
memcpy(globalBytes, (PRUint8 *)data, PR_MIN(bytes, GLOBAL_BYTES_SIZE));
}
PZ_Unlock(rng_lock);
/* --- UNLOCKED --- */
return SECSuccess;
}
SECStatus
RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
{
static const uint8_t key[32] = { 0 };
uint8_t nonce[12] = { 0 };
/* Check for a valid RNG lock. */
PORT_Assert(rng_lock != NULL);
if (rng_lock == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* --- LOCKED --- */
PZ_Lock(rng_lock);
memcpy(nonce, &globalNumCalls, sizeof(globalNumCalls));
globalNumCalls++;
ChaCha20Poly1305Context *cx =
ChaCha20Poly1305_CreateContext(key, sizeof(key), 16);
if (!cx) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
PZ_Unlock(rng_lock);
return SECFailure;
}
memset(dest, 0, len);
memcpy(dest, globalBytes, PR_MIN(len, GLOBAL_BYTES_SIZE));
Hacl_Chacha20_chacha20_encrypt(len, (uint8_t *)dest, (uint8_t *)dest,
(uint8_t *)key, nonce, 0);
ChaCha20Poly1305_DestroyContext(cx, PR_TRUE);
PZ_Unlock(rng_lock);
/* --- UNLOCKED --- */
return SECSuccess;
}
void
RNG_RNGShutdown(void)
{
if (rng_lock) {
PZ_DestroyLock(rng_lock);
rng_lock = NULL;
}
coRNGInit = pristineCallOnce;
}
/* Test functions are not implemented! */
SECStatus
PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *nonce, unsigned int nonce_len,
const PRUint8 *personal_string, unsigned int ps_len)
{
return SECFailure;
}
SECStatus
PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *additional, unsigned int additional_len)
{
return SECFailure;
}
SECStatus
PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len,
const PRUint8 *additional, unsigned int additional_len)
{
return SECFailure;
}
SECStatus
PRNGTEST_Uninstantiate()
{
return SECFailure;
}
SECStatus
PRNGTEST_RunHealthTests()
{
return SECFailure;
}
SECStatus
PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len,
const PRUint8 *nonce, unsigned int nonce_len,
const PRUint8 *personal_string, unsigned int ps_len)
{
return SECFailure;
}