diff options
Diffstat (limited to 'src/Crypto/chachaRng.c')
-rw-r--r-- | src/Crypto/chachaRng.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/src/Crypto/chachaRng.c b/src/Crypto/chachaRng.c new file mode 100644 index 00000000..b3d92039 --- /dev/null +++ b/src/Crypto/chachaRng.c @@ -0,0 +1,120 @@ +/* $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); + } +} |