VeraCrypt/src/Crypto/chachaRng.c

121 lines
3.6 KiB
C

/* $OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $ */
/*
* Copyright (c) 1996, David Mazieres <dm@uun.org>
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
* Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* ChaCha based random number generator for OpenBSD.
*/
/*
* Adapted for VeraCrypt
*/
#include "chachaRng.h"
#include "cpu.h"
#include "misc.h"
#include <string.h>
static VC_INLINE void ChaCha20RngReKey (ChaCha20RngCtx* pCtx, int useCallBack)
{
/* fill rs_buf with the keystream */
if (pCtx->m_rs_have)
memset(pCtx->m_rs_buf + sizeof(pCtx->m_rs_buf) - pCtx->m_rs_have, 0, pCtx->m_rs_have);
ChaCha256Encrypt(&pCtx->m_chachaCtx, pCtx->m_rs_buf, sizeof (pCtx->m_rs_buf),
pCtx->m_rs_buf);
/* mix in optional user provided data */
if (pCtx->m_getRandSeedCallback && useCallBack) {
unsigned char dat[CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ];
size_t i;
pCtx->m_getRandSeedCallback (dat, sizeof (dat));
for (i = 0; i < (CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ); i++)
pCtx->m_rs_buf[i] ^= dat[i];
burn (dat, sizeof(dat));
}
/* immediately reinit for backtracking resistance */
ChaCha256Init (&pCtx->m_chachaCtx, pCtx->m_rs_buf, pCtx->m_rs_buf + CHACHA20RNG_KEYSZ, 20);
memset(pCtx->m_rs_buf, 0, CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ);
pCtx->m_rs_have = sizeof (pCtx->m_rs_buf) - CHACHA20RNG_KEYSZ - CHACHA20RNG_IVSZ;
}
static VC_INLINE void ChaCha20RngStir(ChaCha20RngCtx* pCtx)
{
ChaCha20RngReKey (pCtx, 1);
/* invalidate rs_buf */
pCtx->m_rs_have = 0;
memset(pCtx->m_rs_buf, 0, CHACHA20RNG_RSBUFSZ);
pCtx->m_rs_count = 1600000;
}
static VC_INLINE void ChaCha20RngStirIfNeeded(ChaCha20RngCtx* pCtx, size_t len)
{
if (pCtx->m_rs_count <= len) {
ChaCha20RngStir(pCtx);
} else
pCtx->m_rs_count -= len;
}
void ChaCha20RngInit (ChaCha20RngCtx* pCtx, const unsigned char* key, GetRandSeedFn rngSeedCallback, size_t InitialBytesToSkip)
{
ChaCha256Init (&pCtx->m_chachaCtx, key, key + 32, 20);
pCtx->m_getRandSeedCallback = rngSeedCallback;
/* fill rs_buf with the keystream */
pCtx->m_rs_have = 0;
memset (pCtx->m_rs_buf, 0, sizeof (pCtx->m_rs_buf));
pCtx->m_rs_count = 1600000;
ChaCha20RngReKey(pCtx, 0);
if (InitialBytesToSkip)
ChaCha20RngGetBytes (pCtx, NULL, InitialBytesToSkip);
}
void ChaCha20RngGetBytes (ChaCha20RngCtx* pCtx, unsigned char* buffer, size_t bufferLen)
{
unsigned char *buf = (unsigned char*) buffer;
unsigned char* keystream;
size_t m;
ChaCha20RngStirIfNeeded(pCtx, bufferLen);
while (bufferLen > 0) {
if (pCtx->m_rs_have > 0) {
m = VC_MIN(bufferLen, pCtx->m_rs_have);
keystream = pCtx->m_rs_buf + sizeof(pCtx->m_rs_buf) - pCtx->m_rs_have;
if (buf)
{
memcpy(buf, keystream, m);
buf += m;
}
memset(keystream, 0, m);
bufferLen -= m;
pCtx->m_rs_have -= m;
}
if (pCtx->m_rs_have == 0)
ChaCha20RngReKey (pCtx, 0);
}
}