VeraCrypt
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2019-02-08 00:48:12 (GMT)
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2019-02-08 00:50:12 (GMT)
commitba5da0946c3abaa93d1161ca512c3c326cda3736 (patch)
tree128c238dea40ac0de0c7de8e0b02810eabc8e564
parente5b9cee8681dc45340321f759079b344a3b2676c (diff)
downloadVeraCrypt-ba5da0946c3abaa93d1161ca512c3c326cda3736.zip
VeraCrypt-ba5da0946c3abaa93d1161ca512c3c326cda3736.tar.gz
Windows: Add implementation of ChaCha20 based random generator. Use it for driver need of random bytes (currently only wipe bytes but more to come later).
-rw-r--r--src/Crypto/Crypto.vcxproj7
-rw-r--r--src/Crypto/Crypto.vcxproj.filters21
-rw-r--r--src/Crypto/Sources4
-rw-r--r--src/Crypto/chacha-xmm.c160
-rw-r--r--src/Crypto/chacha256.c219
-rw-r--r--src/Crypto/chacha256.h31
-rw-r--r--src/Crypto/chachaRng.c120
-rw-r--r--src/Crypto/chachaRng.h63
-rw-r--r--src/Crypto/chacha_u1.h102
-rw-r--r--src/Crypto/chacha_u4.h187
-rw-r--r--src/Crypto/config.h9
-rw-r--r--src/Crypto/cpu.h10
-rw-r--r--src/Driver/DriveFilter.c42
-rw-r--r--src/Driver/Driver.vcxproj4
-rw-r--r--src/Driver/Driver.vcxproj.filters12
-rw-r--r--src/Driver/Ntdriver.c60
-rw-r--r--src/Driver/Ntdriver.h1
17 files changed, 1015 insertions, 37 deletions
diff --git a/src/Crypto/Crypto.vcxproj b/src/Crypto/Crypto.vcxproj
index 43ac766..5fb52d9 100644
--- a/src/Crypto/Crypto.vcxproj
+++ b/src/Crypto/Crypto.vcxproj
@@ -215,6 +215,9 @@
<ClCompile Include="Aeskey.c" />
<ClCompile Include="Aestab.c" />
<ClCompile Include="Camellia.c" />
+ <ClCompile Include="chacha-xmm.c" />
+ <ClCompile Include="chacha256.c" />
+ <ClCompile Include="chachaRng.c" />
<ClCompile Include="cpu.c" />
<ClCompile Include="GostCipher.c" />
<ClCompile Include="kuznyechik.c" />
@@ -234,6 +237,10 @@
<ClInclude Include="Aesopt.h" />
<ClInclude Include="Aestab.h" />
<ClInclude Include="Camellia.h" />
+ <ClInclude Include="chacha256.h" />
+ <ClInclude Include="chachaRng.h" />
+ <ClInclude Include="chacha_u1.h" />
+ <ClInclude Include="chacha_u4.h" />
<ClInclude Include="config.h" />
<ClInclude Include="cpu.h" />
<ClInclude Include="GostCipher.h" />
diff --git a/src/Crypto/Crypto.vcxproj.filters b/src/Crypto/Crypto.vcxproj.filters
index c8d91b6..abf8165 100644
--- a/src/Crypto/Crypto.vcxproj.filters
+++ b/src/Crypto/Crypto.vcxproj.filters
@@ -60,6 +60,15 @@
<ClCompile Include="rdrand.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="chacha256.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="chacha-xmm.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="chachaRng.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Aes.h">
@@ -116,6 +125,18 @@
<ClInclude Include="rdrand.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="chacha_u1.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="chacha_u4.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="chacha256.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="chachaRng.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="Aes_hw_cpu.asm">
diff --git a/src/Crypto/Sources b/src/Crypto/Sources
index 271edca..5c44c37 100644
--- a/src/Crypto/Sources
+++ b/src/Crypto/Sources
@@ -6,7 +6,6 @@ INCLUDES = ..
NTTARGETFILES = \
"$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj" \
"$(OBJ_PATH)\$(O)\Aes_hw_cpu.obj" \
- "$(OBJ_PATH)\$(O)\rdrand.obj" \
"$(OBJ_PATH)\$(O)\rdrand_ml.obj" \
"$(OBJ_PATH)\$(O)\gost89_$(TC_ARCH).obj" \
"$(OBJ_PATH)\$(O)\Twofish_$(TC_ARCH).obj" \
@@ -28,6 +27,9 @@ SOURCES = \
rdrand_ml.asm \
Aeskey.c \
Aestab.c \
+ chacha-xmm.c \
+ chacha256.c \
+ chachaRng.c \
cpu.c \
rdrand.c \
Rmd160.c \
diff --git a/src/Crypto/chacha-xmm.c b/src/Crypto/chacha-xmm.c
new file mode 100644
index 0000000..198d0b5
--- /dev/null
+++ b/src/Crypto/chacha-xmm.c
@@ -0,0 +1,160 @@
+/*
+chacha.c version $Date: 2014/09/08 17:38:05 $
+D. J. Bernstein
+Romain Dolbeau
+Public domain.
+*/
+
+// Modified by kerukuro for use in cppcrypto.
+
+/* Adapted to VeraCrypt */
+
+#include "Common/Tcdefs.h"
+#include "config.h"
+#include "cpu.h"
+#include "misc.h"
+
+#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
+
+#ifndef _M_X64
+#ifdef _MSC_VER
+#if _MSC_VER < 1900
+__inline __m128i _mm_set_epi64x(int64 i0, int64 i1) {
+ union {
+ int64 q[2];
+ int32 r[4];
+ } u;
+ u.q[0] = i1; u.q[1] = i0;
+ // this is inefficient, but other solutions are worse
+ return _mm_setr_epi32(u.r[0], u.r[1], u.r[2], u.r[3]);
+}
+#pragma warning(disable:4799)
+__inline __m128i _mm_set1_epi64x(int64 a)
+{
+ union {
+ __m64 m;
+ long long ii;
+ } u;
+ u.ii = a;
+ return _mm_set1_epi64(u.m);
+}
+#pragma warning(default:4799)
+#endif
+#endif
+#endif
+
+#define uint8 byte
+
+#define U32V(v) (v)
+#define ROTL32(x,n) rotl32(x, n)
+#define U32TO8_LITTLE(p, v) (((uint32*)(p))[0] = (v))
+#define U8TO32_LITTLE(v) *((uint32*)(v))
+
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+ x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
+ x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
+ x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
+ x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
+
+static void salsa20_wordtobyte(uint8 output[64],const uint32 input[16], unsigned int r)
+{
+ uint32 x[16];
+ int i;
+
+ for (i = 0;i < 16;++i) x[i] = input[i];
+ for (i = r;i > 0;--i) {
+ QUARTERROUND( 0, 4, 8,12)
+ QUARTERROUND( 1, 5, 9,13)
+ QUARTERROUND( 2, 6,10,14)
+ QUARTERROUND( 3, 7,11,15)
+ QUARTERROUND( 0, 5,10,15)
+ QUARTERROUND( 1, 6,11,12)
+ QUARTERROUND( 2, 7, 8,13)
+ QUARTERROUND( 3, 4, 9,14)
+ }
+ for (i = 0;i < 16;++i) x[i] = PLUS(x[i],input[i]);
+ for (i = 0;i < 16;++i) U32TO8_LITTLE(output + 4 * i,x[i]);
+}
+
+void chacha_ECRYPT_init(void)
+{
+ return;
+}
+
+static const char sigma[17] = "expand 32-byte k";
+static const char tau[17] = "expand 16-byte k";
+
+void chacha_ECRYPT_keysetup(uint32* input,const uint8 *k,uint32 kbits,uint32 ivbits)
+{
+ const char *constants;
+
+ input[4] = U8TO32_LITTLE(k + 0);
+ input[5] = U8TO32_LITTLE(k + 4);
+ input[6] = U8TO32_LITTLE(k + 8);
+ input[7] = U8TO32_LITTLE(k + 12);
+ if (kbits == 256) { /* recommended */
+ k += 16;
+ constants = sigma;
+ } else { /* kbits == 128 */
+ constants = tau;
+ }
+ input[8] = U8TO32_LITTLE(k + 0);
+ input[9] = U8TO32_LITTLE(k + 4);
+ input[10] = U8TO32_LITTLE(k + 8);
+ input[11] = U8TO32_LITTLE(k + 12);
+ input[0] = U8TO32_LITTLE(constants + 0);
+ input[1] = U8TO32_LITTLE(constants + 4);
+ input[2] = U8TO32_LITTLE(constants + 8);
+ input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+void chacha_ECRYPT_ivsetup(uint32* input,const uint8 *iv)
+{
+ input[12] = 0;
+ input[13] = 0;
+ input[14] = U8TO32_LITTLE(iv + 0);
+ input[15] = U8TO32_LITTLE(iv + 4);
+}
+
+void chacha_ECRYPT_encrypt_bytes(size_t bytes, uint32* x, const uint8* m, uint8* out, uint8* output, unsigned int r)
+{
+ unsigned int i;
+
+#include "chacha_u4.h"
+
+#include "chacha_u1.h"
+
+#ifndef _M_X64
+#ifdef _MSC_VER
+#if _MSC_VER < 1900
+ _mm_empty();
+#endif
+#endif
+#endif
+
+ if (!bytes) return;
+ for (;;) {
+ salsa20_wordtobyte(output,x, r);
+ x[12] = PLUSONE(x[12]);
+ if (!x[12]) {
+ x[13] = PLUSONE(x[13]);
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+ if (bytes <= 64) {
+ for (i = 0;i < bytes;++i) out[i] = m[i] ^ output[i];
+ return;
+ }
+ for (i = 0;i < 64;++i) out[i] = m[i] ^ output[i];
+ bytes -= 64;
+ out += 64;
+ m += 64;
+ }
+}
+
+#endif
diff --git a/src/Crypto/chacha256.c b/src/Crypto/chacha256.c
new file mode 100644
index 0000000..f32e607
--- /dev/null
+++ b/src/Crypto/chacha256.c
@@ -0,0 +1,219 @@
+/*
+This code is written by kerukuro for cppcrypto library (http://cppcrypto.sourceforge.net/)
+and released into public domain.
+*/
+
+/* adapted for VeraCrypt */
+
+#include "chacha256.h"
+#include "cpu.h"
+#include "misc.h"
+
+
+
+#define rotater32(x,n) rotr32(x, n)
+#define rotatel32(x,n) rotl32(x, n)
+
+#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
+void chacha_ECRYPT_encrypt_bytes(size_t bytes, uint32* x, const unsigned char* m, unsigned char* out, unsigned char* output, unsigned int r);
+#endif
+
+static VC_INLINE void xor_block_512(const unsigned char* in, const unsigned char* prev, unsigned char* out)
+{
+#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE && !defined(_UEFI) && (!defined (TC_WINDOWS_DRIVER) || (!defined (DEBUG) && defined (_WIN64)))
+ if (HasSSE2())
+ {
+ __m128i b1 = _mm_loadu_si128((const __m128i*) in);
+ __m128i p1 = _mm_loadu_si128((const __m128i*) prev);
+ __m128i b2 = _mm_loadu_si128((const __m128i*) (in + 16));
+ __m128i p2 = _mm_loadu_si128((const __m128i*) (prev + 16));
+
+ _mm_storeu_si128((__m128i*) out, _mm_xor_si128(b1, p1));
+ _mm_storeu_si128((__m128i*) (out + 16), _mm_xor_si128(b2, p2));
+
+ b1 = _mm_loadu_si128((const __m128i*) (in + 32));
+ p1 = _mm_loadu_si128((const __m128i*) (prev + 32));
+ b2 = _mm_loadu_si128((const __m128i*) (in + 48));
+ p2 = _mm_loadu_si128((const __m128i*) (prev + 48));
+
+ _mm_storeu_si128((__m128i*) (out + 32), _mm_xor_si128(b1, p1));
+ _mm_storeu_si128((__m128i*) (out + 48), _mm_xor_si128(b2, p2));
+
+ }
+ else
+#endif
+ {
+ int i;
+ for (i = 0; i < 64; i++)
+ out[i] = in[i] ^ prev[i];
+ }
+
+}
+
+static VC_INLINE void chacha_core(uint32* x, int r)
+{
+ int i;
+ for (i = 0; i < r; i++)
+ {
+ x[0] += x[4];
+ x[12] = rotatel32(x[12] ^ x[0], 16);
+ x[8] += x[12];
+ x[4] = rotatel32(x[4] ^ x[8], 12);
+ x[0] += x[4];
+ x[12] = rotatel32(x[12] ^ x[0], 8);
+ x[8] += x[12];
+ x[4] = rotatel32(x[4] ^ x[8], 7);
+
+ x[1] += x[5];
+ x[13] = rotatel32(x[13] ^ x[1], 16);
+ x[9] += x[13];
+ x[5] = rotatel32(x[5] ^ x[9], 12);
+ x[1] += x[5];
+ x[13] = rotatel32(x[13] ^ x[1], 8);
+ x[9] += x[13];
+ x[5] = rotatel32(x[5] ^ x[9], 7);
+
+ x[2] += x[6];
+ x[14] = rotatel32(x[14] ^ x[2], 16);
+ x[10] += x[14];
+ x[6] = rotatel32(x[6] ^ x[10], 12);
+ x[2] += x[6];
+ x[14] = rotatel32(x[14] ^ x[2], 8);
+ x[10] += x[14];
+ x[6] = rotatel32(x[6] ^ x[10], 7);
+
+ x[3] += x[7];
+ x[15] = rotatel32(x[15] ^ x[3], 16);
+ x[11] += x[15];
+ x[7] = rotatel32(x[7] ^ x[11], 12);
+ x[3] += x[7];
+ x[15] = rotatel32(x[15] ^ x[3], 8);
+ x[11] += x[15];
+ x[7] = rotatel32(x[7] ^ x[11], 7);
+
+ x[0] += x[5];
+ x[15] = rotatel32(x[15] ^ x[0], 16);
+ x[10] += x[15];
+ x[5] = rotatel32(x[5] ^ x[10], 12);
+ x[0] += x[5];
+ x[15] = rotatel32(x[15] ^ x[0], 8);
+ x[10] += x[15];
+ x[5] = rotatel32(x[5] ^ x[10], 7);
+
+ x[1] += x[6];
+ x[12] = rotatel32(x[12] ^ x[1], 16);
+ x[11] += x[12];
+ x[6] = rotatel32(x[6] ^ x[11], 12);
+ x[1] += x[6];
+ x[12] = rotatel32(x[12] ^ x[1], 8);
+ x[11] += x[12];
+ x[6] = rotatel32(x[6] ^ x[11], 7);
+
+ x[2] += x[7];
+ x[13] = rotatel32(x[13] ^ x[2], 16);
+ x[8] += x[13];
+ x[7] = rotatel32(x[7] ^ x[8], 12);
+ x[2] += x[7];
+ x[13] = rotatel32(x[13] ^ x[2], 8);
+ x[8] += x[13];
+ x[7] = rotatel32(x[7] ^ x[8], 7);
+
+ x[3] += x[4];
+ x[14] = rotatel32(x[14] ^ x[3], 16);
+ x[9] += x[14];
+ x[4] = rotatel32(x[4] ^ x[9], 12);
+ x[3] += x[4];
+ x[14] = rotatel32(x[14] ^ x[3], 8);
+ x[9] += x[14];
+ x[4] = rotatel32(x[4] ^ x[9], 7);
+ }
+}
+
+static VC_INLINE void chacha_hash(const uint32* in, uint32* out, int r)
+{
+ uint32 x[16];
+ int i;
+ memcpy(x, in, 64);
+ chacha_core(x, r);
+ for (i = 0; i < 16; ++i)
+ out[i] = x[i] + in[i];
+}
+
+static VC_INLINE void incrementSalsaCounter(uint32* input, uint32* block, int r)
+{
+ chacha_hash(input, block, r);
+ if (!++input[12])
+ ++input[13];
+}
+
+static VC_INLINE void do_encrypt(const unsigned char* in, size_t len, unsigned char* out, int r, size_t* posPtr, uint32* input, uint32* block)
+{
+ size_t i = 0, pos = *posPtr;
+ if (pos)
+ {
+ while (pos < len && pos < 64)
+ {
+ out[i] = in[i] ^ ((unsigned char*)block)[pos++];
+ ++i;
+ }
+ len -= i;
+ }
+ if (len)
+ pos = 0;
+
+#if CRYPTOPP_SSSE3_AVAILABLE && !defined(_UEFI) && (!defined (TC_WINDOWS_DRIVER) || (!defined (DEBUG) && defined (_WIN64)))
+ if (HasSSSE3())
+ {
+ size_t fullblocks = len - len % 64;
+ if (fullblocks)
+ {
+ chacha_ECRYPT_encrypt_bytes(fullblocks, input, in + i, out + i, (unsigned char*)block, r);
+ i += fullblocks;
+ len -= fullblocks;
+ }
+ if (len)
+ {
+ chacha_ECRYPT_encrypt_bytes(len, input, in + i, out + i, (unsigned char*)block, r);
+ pos = len;
+ }
+ *posPtr = pos;
+ return;
+ }
+#endif
+
+ for (; len; len -= VC_MIN(64, len))
+ {
+ incrementSalsaCounter(input, block, r);
+ if (len >= 64)
+ {
+ xor_block_512(in + i, (unsigned char*)block, out + i);
+ i += 64;
+ }
+ else
+ {
+ for (; pos < len; pos++, i++)
+ out[i] = in[i] ^ ((unsigned char*)block)[pos];
+ }
+ }
+ *posPtr = pos;
+}
+
+void ChaCha256Init(ChaCha256Ctx* ctx, const unsigned char* key, const unsigned char* iv, int rounds)
+{
+ ctx->internalRounds = rounds / 2;
+ ctx->pos = 0;
+
+ ctx->input_[12] = 0;
+ ctx->input_[13] = 0;
+ memcpy(ctx->input_ + 4, key, 32);
+ memcpy(ctx->input_ + 14, iv, 8);
+ ctx->input_[0] = 0x61707865;
+ ctx->input_[1] = 0x3320646E;
+ ctx->input_[2] = 0x79622D32;
+ ctx->input_[3] = 0x6B206574;
+}
+
+void ChaCha256Encrypt(ChaCha256Ctx* ctx, const unsigned char* in, size_t len, unsigned char* out)
+{
+ do_encrypt(in, len, out, ctx->internalRounds, &ctx->pos, ctx->input_, ctx->block_);
+}
diff --git a/src/Crypto/chacha256.h b/src/Crypto/chacha256.h
new file mode 100644
index 0000000..e9533a3
--- /dev/null
+++ b/src/Crypto/chacha256.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_Crypto_ChaCha256
+#define HEADER_Crypto_ChaCha256
+
+#include "Common/Tcdefs.h"
+#include "config.h"
+
+typedef struct
+{
+ CRYPTOPP_ALIGN_DATA(16) uint32 block_[16];
+ CRYPTOPP_ALIGN_DATA(16) uint32 input_[16];
+ size_t pos;
+ int internalRounds;
+} ChaCha256Ctx;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * key must be 32 bytes long and iv must be 8 bytes long
+ */
+void ChaCha256Init(ChaCha256Ctx* ctx, const unsigned char* key, const unsigned char* iv, int rounds);
+void ChaCha256Encrypt(ChaCha256Ctx* ctx, const unsigned char* in, size_t len, unsigned char* out);
+#define ChaCha256Decrypt ChaCha256Encrypt
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // HEADER_Crypto_ChaCha
+
diff --git a/src/Crypto/chachaRng.c b/src/Crypto/chachaRng.c
new file mode 100644
index 0000000..b3d9203
--- /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);
+ }
+}
diff --git a/src/Crypto/chachaRng.h b/src/Crypto/chachaRng.h
new file mode 100644
index 0000000..a2cb4ce
--- /dev/null
+++ b/src/Crypto/chachaRng.h
@@ -0,0 +1,63 @@
+/* $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
+ */
+
+#ifndef HEADER_Crypto_ChaChaRng
+#define HEADER_Crypto_ChaChaRng
+
+#include "chacha256.h"
+
+#define CHACHA20RNG_KEYSZ 32
+#define CHACHA20RNG_IVSZ 8
+#define CHACHA20RNG_BLOCKSZ 64
+#define CHACHA20RNG_RSBUFSZ (16*CHACHA20RNG_BLOCKSZ)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*GetRandSeedFn)(unsigned char* pbRandSeed, size_t cbRandSeed);
+
+typedef struct
+{
+ ChaCha256Ctx m_chachaCtx; /* ChaCha20 context */
+ unsigned char m_rs_buf[CHACHA20RNG_RSBUFSZ]; /* keystream blocks */
+ size_t m_rs_have; /* valid bytes at end of rs_buf */
+ size_t m_rs_count; /* bytes till reseed */
+ GetRandSeedFn m_getRandSeedCallback;
+} ChaCha20RngCtx;
+
+/* key length must be equal to 40 bytes (CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ) */
+void ChaCha20RngInit (ChaCha20RngCtx* pCtx, const unsigned char* key, GetRandSeedFn rngCallback, size_t InitialBytesToSkip);
+void ChaCha20RngGetBytes (ChaCha20RngCtx* pCtx, unsigned char* buffer, size_t bufferLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Crypto/chacha_u1.h b/src/Crypto/chacha_u1.h
new file mode 100644
index 0000000..e77bc1e
--- /dev/null
+++ b/src/Crypto/chacha_u1.h
@@ -0,0 +1,102 @@
+/*
+u1.h version $Date: 2014/09/08 17:44:28 $
+D. J. Bernstein
+Romain Dolbeau
+Public domain.
+*/
+
+// Modified by kerukuro for use in cppcrypto.
+
+// if (!bytes) return;
+ while (bytes >=64) {
+ __m128i x_0, x_1, x_2, x_3;
+ __m128i t_1;
+ const __m128i rot16 = _mm_set_epi8(13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2);
+ const __m128i rot8 = _mm_set_epi8(14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3);
+ uint32 in12, in13;
+
+ x_0 = _mm_load_si128((__m128i*)(x + 0));
+ x_1 = _mm_load_si128((__m128i*)(x + 4));
+ x_2 = _mm_load_si128((__m128i*)(x + 8));
+ x_3 = _mm_load_si128((__m128i*)(x + 12));
+
+ for (i = 0 ; i < r ; ++i) {
+ x_0 = _mm_add_epi32(x_0, x_1);
+ x_3 = _mm_xor_si128(x_3, x_0);
+ x_3 = _mm_shuffle_epi8(x_3, rot16);
+
+ x_2 = _mm_add_epi32(x_2, x_3);
+ x_1 = _mm_xor_si128(x_1, x_2);
+
+ t_1 = x_1;
+ x_1 = _mm_slli_epi32(x_1, 12);
+ t_1 = _mm_srli_epi32(t_1, 20);
+ x_1 = _mm_xor_si128(x_1, t_1);
+
+ x_0 = _mm_add_epi32(x_0, x_1);
+ x_3 = _mm_xor_si128(x_3, x_0);
+ x_0 = _mm_shuffle_epi32(x_0, 0x93);
+ x_3 = _mm_shuffle_epi8(x_3, rot8);
+
+ x_2 = _mm_add_epi32(x_2, x_3);
+ x_3 = _mm_shuffle_epi32(x_3, 0x4e);
+ x_1 = _mm_xor_si128(x_1, x_2);
+ x_2 = _mm_shuffle_epi32(x_2, 0x39);
+
+ t_1 = x_1;
+ x_1 = _mm_slli_epi32(x_1, 7);
+ t_1 = _mm_srli_epi32(t_1, 25);
+ x_1 = _mm_xor_si128(x_1, t_1);
+
+ x_0 = _mm_add_epi32(x_0, x_1);
+ x_3 = _mm_xor_si128(x_3, x_0);
+ x_3 = _mm_shuffle_epi8(x_3, rot16);
+
+ x_2 = _mm_add_epi32(x_2, x_3);
+ x_1 = _mm_xor_si128(x_1, x_2);
+
+ t_1 = x_1;
+ x_1 = _mm_slli_epi32(x_1, 12);
+ t_1 = _mm_srli_epi32(t_1, 20);
+ x_1 = _mm_xor_si128(x_1, t_1);
+
+ x_0 = _mm_add_epi32(x_0, x_1);
+ x_3 = _mm_xor_si128(x_3, x_0);
+ x_0 = _mm_shuffle_epi32(x_0, 0x39);
+ x_3 = _mm_shuffle_epi8(x_3, rot8);
+
+ x_2 = _mm_add_epi32(x_2, x_3);
+ x_3 = _mm_shuffle_epi32(x_3, 0x4e);
+ x_1 = _mm_xor_si128(x_1, x_2);
+ x_2 = _mm_shuffle_epi32(x_2, 0x93);
+
+ t_1 = x_1;
+ x_1 = _mm_slli_epi32(x_1, 7);
+ t_1 = _mm_srli_epi32(t_1, 25);
+ x_1 = _mm_xor_si128(x_1, t_1);
+ }
+ x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((__m128i*)(x + 0)));
+ x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((__m128i*)(x + 4)));
+ x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((__m128i*)(x + 8)));
+ x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((__m128i*)(x + 12)));
+ x_0 = _mm_xor_si128(x_0, _mm_loadu_si128((__m128i*)(m + 0)));
+ x_1 = _mm_xor_si128(x_1, _mm_loadu_si128((__m128i*)(m + 16)));
+ x_2 = _mm_xor_si128(x_2, _mm_loadu_si128((__m128i*)(m + 32)));
+ x_3 = _mm_xor_si128(x_3, _mm_loadu_si128((__m128i*)(m + 48)));
+ _mm_storeu_si128((__m128i*)(out + 0), x_0);
+ _mm_storeu_si128((__m128i*)(out + 16), x_1);
+ _mm_storeu_si128((__m128i*)(out + 32), x_2);
+ _mm_storeu_si128((__m128i*)(out + 48), x_3);
+
+ in12 = x[12];
+ in13 = x[13];
+ in12 ++;
+ if (in12 == 0)
+ in13 ++;
+ x[12] = in12;
+ x[13] = in13;
+
+ bytes -= 64;
+ out += 64;
+ m += 64;
+ }
diff --git a/src/Crypto/chacha_u4.h b/src/Crypto/chacha_u4.h
new file mode 100644
index 0000000..8eef5dc
--- /dev/null
+++ b/src/Crypto/chacha_u4.h
@@ -0,0 +1,187 @@
+/*
+u4.h version $Date: 2014/11/11 10:46:58 $
+D. J. Bernstein
+Romain Dolbeau
+Public domain.
+*/
+
+// Modified by kerukuro for use in cppcrypto.
+
+#define VEC4_ROT(a,imm) _mm_or_si128(_mm_slli_epi32(a,imm),_mm_srli_epi32(a,(32-imm)))
+
+/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & 16) (better) */
+#define VEC4_QUARTERROUND_SHUFFLE(a,b,c,d) \
+ x_##a = _mm_add_epi32(x_##a, x_##b); t_##a = _mm_xor_si128(x_##d, x_##a); x_##d = _mm_shuffle_epi8(t_##a, rot16); \
+ x_##c = _mm_add_epi32(x_##c, x_##d); t_##c = _mm_xor_si128(x_##b, x_##c); x_##b = VEC4_ROT(t_##c, 12); \
+ x_##a = _mm_add_epi32(x_##a, x_##b); t_##a = _mm_xor_si128(x_##d, x_##a); x_##d = _mm_shuffle_epi8(t_##a, rot8); \
+ x_##c = _mm_add_epi32(x_##c, x_##d); t_##c = _mm_xor_si128(x_##b, x_##c); x_##b = VEC4_ROT(t_##c, 7)
+
+#define VEC4_QUARTERROUND(a,b,c,d) VEC4_QUARTERROUND_SHUFFLE(a,b,c,d)
+
+
+// if (!bytes) return;
+if (bytes>=256) {
+ /* constant for shuffling bytes (replacing multiple-of-8 rotates) */
+ __m128i rot16 = _mm_set_epi8(13,12,15,14,9,8,11,10,5,4,7,6,1,0,3,2);
+ __m128i rot8 = _mm_set_epi8(14,13,12,15,10,9,8,11,6,5,4,7,2,1,0,3);
+ uint32 in12, in13;
+ __m128i x_0 = _mm_set1_epi32(x[0]);
+ __m128i x_1 = _mm_set1_epi32(x[1]);
+ __m128i x_2 = _mm_set1_epi32(x[2]);
+ __m128i x_3 = _mm_set1_epi32(x[3]);
+ __m128i x_4 = _mm_set1_epi32(x[4]);
+ __m128i x_5 = _mm_set1_epi32(x[5]);
+ __m128i x_6 = _mm_set1_epi32(x[6]);
+ __m128i x_7 = _mm_set1_epi32(x[7]);
+ __m128i x_8 = _mm_set1_epi32(x[8]);
+ __m128i x_9 = _mm_set1_epi32(x[9]);
+ __m128i x_10 = _mm_set1_epi32(x[10]);
+ __m128i x_11 = _mm_set1_epi32(x[11]);
+ __m128i x_12;// = _mm_set1_epi32(x[12]); /* useless */
+ __m128i x_13;// = _mm_set1_epi32(x[13]); /* useless */
+ __m128i x_14 = _mm_set1_epi32(x[14]);
+ __m128i x_15 = _mm_set1_epi32(x[15]);
+ __m128i orig0 = x_0;
+ __m128i orig1 = x_1;
+ __m128i orig2 = x_2;
+ __m128i orig3 = x_3;
+ __m128i orig4 = x_4;
+ __m128i orig5 = x_5;
+ __m128i orig6 = x_6;
+ __m128i orig7 = x_7;
+ __m128i orig8 = x_8;
+ __m128i orig9 = x_9;
+ __m128i orig10 = x_10;
+ __m128i orig11 = x_11;
+ __m128i orig12;// = x_12; /* useless */
+ __m128i orig13;// = x_13; /* useless */
+ __m128i orig14 = x_14;
+ __m128i orig15 = x_15;
+ __m128i t_0;
+ __m128i t_1;
+ __m128i t_2;
+ __m128i t_3;
+ __m128i t_4;
+ __m128i t_5;
+ __m128i t_6;
+ __m128i t_7;
+ __m128i t_8;
+ __m128i t_9;
+ __m128i t_10;
+ __m128i t_11;
+ __m128i t_12;
+ __m128i t_13;
+ __m128i t_14;
+ __m128i t_15;
+
+ while (bytes >= 256) {
+ const __m128i addv12 = _mm_set_epi64x(1,0);
+ const __m128i addv13 = _mm_set_epi64x(3,2);
+ __m128i t12, t13;
+ uint64 in1213;
+
+ x_0 = orig0;
+ x_1 = orig1;
+ x_2 = orig2;
+ x_3 = orig3;
+ x_4 = orig4;
+ x_5 = orig5;
+ x_6 = orig6;
+ x_7 = orig7;
+ x_8 = orig8;
+ x_9 = orig9;
+ x_10 = orig10;
+ x_11 = orig11;
+ //x_12 = orig12; /* useless */
+ //x_13 = orig13; /* useless */
+ x_14 = orig14;
+ x_15 = orig15;
+
+
+
+
+ in12 = x[12];
+ in13 = x[13];
+ in1213 = ((uint64)in12) | (((uint64)in13) << 32);
+ t12 = _mm_set1_epi64x(in1213);
+ t13 = _mm_set1_epi64x(in1213);
+
+ x_12 = _mm_add_epi64(addv12, t12);
+ x_13 = _mm_add_epi64(addv13, t13);
+
+ t12 = _mm_unpacklo_epi32(x_12, x_13);
+ t13 = _mm_unpackhi_epi32(x_12, x_13);
+
+ x_12 = _mm_unpacklo_epi32(t12, t13);
+ x_13 = _mm_unpackhi_epi32(t12, t13);
+
+ orig12 = x_12;
+ orig13 = x_13;
+
+ in1213 += 4;
+
+ x[12] = in1213 & 0xFFFFFFFF;
+ x[13] = (in1213>>32)&0xFFFFFFFF;
+
+ for (i = 0 ; i < r ; ++i) {
+ VEC4_QUARTERROUND( 0, 4, 8,12);
+ VEC4_QUARTERROUND( 1, 5, 9,13);
+ VEC4_QUARTERROUND( 2, 6,10,14);
+ VEC4_QUARTERROUND( 3, 7,11,15);
+ VEC4_QUARTERROUND( 0, 5,10,15);
+ VEC4_QUARTERROUND( 1, 6,11,12);
+ VEC4_QUARTERROUND( 2, 7, 8,13);
+ VEC4_QUARTERROUND( 3, 4, 9,14);
+ }
+
+#define ONEQUAD_TRANSPOSE(a,b,c,d) \
+ { \
+ __m128i t0, t1, t2, t3; \
+ x_##a = _mm_add_epi32(x_##a, orig##a); \
+ x_##b = _mm_add_epi32(x_##b, orig##b); \
+ x_##c = _mm_add_epi32(x_##c, orig##c); \
+ x_##d = _mm_add_epi32(x_##d, orig##d); \
+ t_##a = _mm_unpacklo_epi32(x_##a, x_##b); \
+ t_##b = _mm_unpacklo_epi32(x_##c, x_##d); \
+ t_##c = _mm_unpackhi_epi32(x_##a, x_##b); \
+ t_##d = _mm_unpackhi_epi32(x_##c, x_##d); \
+ x_##a = _mm_unpacklo_epi64(t_##a, t_##b); \
+ x_##b = _mm_unpackhi_epi64(t_##a, t_##b); \
+ x_##c = _mm_unpacklo_epi64(t_##c, t_##d); \
+ x_##d = _mm_unpackhi_epi64(t_##c, t_##d); \
+ t0 = _mm_xor_si128(x_##a, _mm_loadu_si128((__m128i*)(m+0))); \
+ _mm_storeu_si128((__m128i*)(out+0),t0); \
+ t1 = _mm_xor_si128(x_##b, _mm_loadu_si128((__m128i*)(m+64))); \
+ _mm_storeu_si128((__m128i*)(out+64),t1); \
+ t2 = _mm_xor_si128(x_##c, _mm_loadu_si128((__m128i*)(m+128))); \
+ _mm_storeu_si128((__m128i*)(out+128),t2); \
+ t3 = _mm_xor_si128(x_##d, _mm_loadu_si128((__m128i*)(m+192))); \
+ _mm_storeu_si128((__m128i*)(out+192),t3); \
+ }
+
+#define ONEQUAD(a,b,c,d) ONEQUAD_TRANSPOSE(a,b,c,d)
+
+ ONEQUAD(0,1,2,3);
+ m+=16;
+ out+=16;
+ ONEQUAD(4,5,6,7);
+ m+=16;
+ out+=16;
+ ONEQUAD(8,9,10,11);
+ m+=16;
+ out+=16;
+ ONEQUAD(12,13,14,15);
+ m-=48;
+ out-=48;
+
+#undef ONEQUAD
+#undef ONEQUAD_TRANSPOSE
+
+ bytes -= 256;
+ out += 256;
+ m += 256;
+ }
+ }
+#undef VEC4_ROT
+#undef VEC4_QUARTERROUND
+#undef VEC4_QUARTERROUND_SHUFFLE
diff --git a/src/Crypto/config.h b/src/Crypto/config.h
index 396be93..cf6f3dc 100644
--- a/src/Crypto/config.h
+++ b/src/Crypto/config.h
@@ -119,6 +119,15 @@
#define CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE 0
#endif
+#if !defined(CRYPTOPP_DISABLE_ASM) && !defined(CRYPTOPP_DISABLE_SSSE3) && ( \
+ defined(__SSSE3__) || (_MSC_VER >= 1500) || \
+ (CRYPTOPP_GCC_VERSION >= 40300) || (__INTEL_COMPILER >= 1000) || (__SUNPRO_CC >= 0x5110) || \
+ (CRYPTOPP_LLVM_CLANG_VERSION >= 20300) || (CRYPTOPP_APPLE_CLANG_VERSION >= 40000))
+ #define CRYPTOPP_SSSE3_AVAILABLE 1
+#else
+ #define CRYPTOPP_SSSE3_AVAILABLE 0
+# endif
+
#if !defined(CRYPTOPP_DISABLE_SSSE3) && !defined(CRYPTOPP_DISABLE_AESNI) && CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE && (CRYPTOPP_GCC_VERSION >= 40400 || _MSC_FULL_VER >= 150030729 || __INTEL_COMPILER >= 1110 || defined(__AES__))
#define CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE 1
#else
diff --git a/src/Crypto/cpu.h b/src/Crypto/cpu.h
index 4dd5d88..9fac453 100644
--- a/src/Crypto/cpu.h
+++ b/src/Crypto/cpu.h
@@ -89,8 +89,10 @@ extern __m128i _mm_unpacklo_epi64(__m128i _A, __m128i _B);
extern void _mm_store_si128(__m128i *_P, __m128i _B);
extern __m64 _m_pxor(__m64 _MM1, __m64 _MM2);
extern __m128i _mm_set_epi64(__m64 _Q1, __m64 _Q0);
+extern __m128i _mm_set1_epi64(__m64 q);
extern __m128i _mm_setr_epi32(int _I0, int _I1, int _I2, int _I3);
extern __m128i _mm_loadu_si128(__m128i const*_P);
+extern __m128i _mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9, char b8, char b7, char b6, char b5, char b4, char b3, char b2, char b1, char b0);
extern __m128i _mm_set_epi32(int _I3, int _I2, int _I1, int _I0);
extern __m128i _mm_set1_epi32(int _I);
extern void _mm_storeu_si128(__m128i *_P, __m128i _B);
@@ -99,6 +101,7 @@ extern __m128i _mm_slli_epi32(__m128i _A, int _Count);
extern __m128i _mm_srli_epi32(__m128i _A, int _Count);
extern __m128i _mm_add_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_sub_epi32(__m128i _A, __m128i _B);
+extern __m128i _mm_add_epi64 (__m128i a, __m128i b);
extern __m128i _mm_or_si128(__m128i _A, __m128i _B);
extern __m128i _mm_and_si128(__m128i _A, __m128i _B);
extern __m128i _mm_andnot_si128(__m128i _A, __m128i _B);
@@ -109,6 +112,9 @@ extern __m128i _mm_unpackhi_epi32(__m128i _A, __m128i _B);
extern __m128i _mm_unpackhi_epi64(__m128i _A, __m128i _B);
extern __m128i _mm_srli_epi16(__m128i _A, int _Count);
extern __m128i _mm_slli_epi16(__m128i _A, int _Count);
+extern __m128i _mm_shuffle_epi32 (__m128i a, int imm8);
+extern __m128i _mm_set_epi64x (__int64 e1, __int64 e0);
+extern __m128i _mm_set1_epi64x (__int64 a);
#define _mm_xor_si64 _m_pxor
#define _mm_empty _m_empty
#define _MM_SHUFFLE(fp3,fp2,fp1,fp0) (((fp3) << 6) | ((fp2) << 4) | \
@@ -122,8 +128,7 @@ extern __m128i _mm_slli_epi16(__m128i _A, int _Count);
#endif
#endif
-#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
-#if defined(__SSSE3__) || defined(__INTEL_COMPILER)
+#if CRYPTOPP_SSSE3_AVAILABLE || defined(__INTEL_COMPILER)
#if defined(TC_WINDOWS_DRIVER) || defined (_UEFI)
#if defined(__cplusplus)
extern "C" {
@@ -135,7 +140,6 @@ extern __m128i _mm_shuffle_epi8 (__m128i a, __m128i b);
#else
#include <tmmintrin.h>
#endif
-#endif
#if defined(__SSE4_1__) || defined(__INTEL_COMPILER) || defined(_MSC_VER)
#if defined(TC_WINDOWS_DRIVER) || defined (_UEFI)
diff --git a/src/Driver/DriveFilter.c b/src/Driver/DriveFilter.c
index 6228009..3c7687f 100644
--- a/src/Driver/DriveFilter.c
+++ b/src/Driver/DriveFilter.c
@@ -29,6 +29,7 @@
#include "Boot/Windows/BootCommon.h"
#include "cpu.h"
#include "rdrand.h"
+#include "chachaRng.h"
static BOOL DeviceFilterActive = FALSE;
@@ -1521,42 +1522,17 @@ static VOID SetupThreadProc (PVOID threadArg)
// generate real random values for wipeRandChars and
// wipeRandCharsUpdate instead of relying on uninitialized stack memory
- LARGE_INTEGER iSeed;
- byte digest[WHIRLPOOL_DIGESTSIZE];
- WHIRLPOOL_CTX tctx;
-
-#ifndef _WIN64
- KFLOATING_SAVE floatingPointState;
- NTSTATUS saveStatus = STATUS_INVALID_PARAMETER;
- if (HasISSE())
- saveStatus = KeSaveFloatingPointState (&floatingPointState);
-#endif
+ ChaCha20RngCtx rngCtx;
+ byte pbSeed[CHACHA20RNG_KEYSZ + CHACHA20RNG_IVSZ];
- KeQuerySystemTime( &iSeed );
- WHIRLPOOL_init (&tctx);
- WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
- // use RDSEED or RDRAND from CPU as source of entropy if enabled
- if ( IsCpuRngEnabled() &&
- ( (HasRDSEED() && RDSEED_getBytes (digest, sizeof (digest)))
- || (HasRDRAND() && RDRAND_getBytes (digest, sizeof (digest)))
- ))
- {
- WHIRLPOOL_add (digest, sizeof(digest), &tctx);
- }
- WHIRLPOOL_finalize (&tctx, digest);
+ GetDriverRandomSeed (pbSeed, sizeof (pbSeed));
+ ChaCha20RngInit (&rngCtx, pbSeed, GetDriverRandomSeed, 0);
-#if !defined (_WIN64)
- if (NT_SUCCESS (saveStatus))
- KeRestoreFloatingPointState (&floatingPointState);
-#endif
-
- memcpy (wipeRandChars, digest, TC_WIPE_RAND_CHAR_COUNT);
- memcpy (wipeRandCharsUpdate, &digest[WHIRLPOOL_DIGESTSIZE - TC_WIPE_RAND_CHAR_COUNT], TC_WIPE_RAND_CHAR_COUNT);
+ ChaCha20RngGetBytes (&rngCtx, wipeRandChars, TC_WIPE_RAND_CHAR_COUNT);
+ ChaCha20RngGetBytes (&rngCtx, wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT);
- burn (digest, WHIRLPOOL_DIGESTSIZE);
- burn (&tctx, sizeof (tctx));
-
- burn (&iSeed, sizeof(iSeed));
+ burn (&rngCtx, sizeof (rngCtx));
+ FAST_ERASE64 (pbSeed, sizeof (pbSeed));
SetupResult = STATUS_UNSUCCESSFUL;
diff --git a/src/Driver/Driver.vcxproj b/src/Driver/Driver.vcxproj
index 894873d..7104be8 100644
--- a/src/Driver/Driver.vcxproj
+++ b/src/Driver/Driver.vcxproj
@@ -193,9 +193,13 @@ BuildDriver.cmd -rebuild -debug -x64 "$(SolutionDir)\Common" "$(SolutionDir)\Cry
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\Crypto\Camellia.c" />
+ <ClCompile Include="..\Crypto\chacha-xmm.c" />
+ <ClCompile Include="..\Crypto\chacha256.c" />
+ <ClCompile Include="..\Crypto\chachaRng.c" />
<ClCompile Include="..\Crypto\rdrand.c" />
<ClCompile Include="..\Crypto\SerpentFast.c" />
<ClCompile Include="..\Crypto\SerpentFast_simd.cpp" />
+ <ClCompile Include="..\Crypto\Streebog.c" />
<ClCompile Include="DriveFilter.c" />
<ClCompile Include="DumpFilter.c" />
<ClCompile Include="EncryptedIoQueue.c" />
diff --git a/src/Driver/Driver.vcxproj.filters b/src/Driver/Driver.vcxproj.filters
index 74cd18e..20227b4 100644
--- a/src/Driver/Driver.vcxproj.filters
+++ b/src/Driver/Driver.vcxproj.filters
@@ -111,6 +111,18 @@
<ClCompile Include="..\Crypto\rdrand.c">
<Filter>Source Files\Crypto</Filter>
</ClCompile>
+ <ClCompile Include="..\Crypto\chacha256.c">
+ <Filter>Source Files\Crypto</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Crypto\chachaRng.c">
+ <Filter>Source Files\Crypto</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Crypto\chacha-xmm.c">
+ <Filter>Source Files\Crypto</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Crypto\Streebog.c">
+ <Filter>Source Files\Crypto</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\Crypto\Aes_hw_cpu.asm">
diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c
index 7e3a08b..9719c91 100644
--- a/src/Driver/Ntdriver.c
+++ b/src/Driver/Ntdriver.c
@@ -30,6 +30,8 @@
#include "Cache.h"
#include "Volumes.h"
#include "VolumeFilter.h"
+#include "cpu.h"
+#include "rdrand.h"
#include <tchar.h>
#include <initguid.h>
@@ -143,6 +145,64 @@ ULONG ExDefaultMdlProtection = 0;
PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1];
+void GetDriverRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed)
+{
+ LARGE_INTEGER iSeed, iSeed2;
+ byte digest[WHIRLPOOL_DIGESTSIZE];
+ WHIRLPOOL_CTX tctx;
+ size_t count;
+
+#ifndef _WIN64
+ KFLOATING_SAVE floatingPointState;
+ NTSTATUS saveStatus = STATUS_INVALID_PARAMETER;
+ if (HasISSE())
+ saveStatus = KeSaveFloatingPointState (&floatingPointState);
+#endif
+
+ while (cbRandSeed)
+ {
+ WHIRLPOOL_init (&tctx);
+ // we hash current content of digest buffer which is initialized the first time
+ WHIRLPOOL_add (digest, WHIRLPOOL_DIGESTSIZE, &tctx);
+
+ // we use various time information as source of entropy
+ KeQuerySystemTime( &iSeed );
+ WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
+ iSeed = KeQueryPerformanceCounter (&iSeed2);
+ WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
+ WHIRLPOOL_add ((unsigned char *) &(iSeed2.QuadPart), sizeof(iSeed2.QuadPart), &tctx);
+ iSeed.QuadPart = KeQueryInterruptTime ();
+ WHIRLPOOL_add ((unsigned char *) &(iSeed.QuadPart), sizeof(iSeed.QuadPart), &tctx);
+
+ // use RDSEED or RDRAND from CPU as source of entropy if enabled
+ if ( IsCpuRngEnabled() &&
+ ( (HasRDSEED() && RDSEED_getBytes (digest, sizeof (digest)))
+ || (HasRDRAND() && RDRAND_getBytes (digest, sizeof (digest)))
+ ))
+ {
+ WHIRLPOOL_add (digest, sizeof(digest), &tctx);
+ }
+ WHIRLPOOL_finalize (&tctx, digest);
+
+ count = VC_MIN (cbRandSeed, sizeof (digest));
+
+ // copy digest value to seed buffer
+ memcpy (pbRandSeed, digest, count);
+ cbRandSeed -= count;
+ pbRandSeed += count;
+ }
+
+#if !defined (_WIN64)
+ if (NT_SUCCESS (saveStatus))
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
+
+ FAST_ERASE64 (digest, sizeof (digest));
+ FAST_ERASE64 (&iSeed.QuadPart, 8);
+ FAST_ERASE64 (&iSeed2.QuadPart, 8);
+ burn (&tctx, sizeof(tctx));
+}
+
NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
diff --git a/src/Driver/Ntdriver.h b/src/Driver/Ntdriver.h
index 42b0919..2e4d655 100644
--- a/src/Driver/Ntdriver.h
+++ b/src/Driver/Ntdriver.h
@@ -191,6 +191,7 @@ void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter);
int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter);
BOOL IsOSAtLeast (OSVersionEnum reqMinOS);
PDEVICE_OBJECT GetVirtualVolumeDeviceObject (int driveNumber);
+void GetDriverRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed);
#define TC_BUG_CHECK(status) KeBugCheckEx (SECURITY_SYSTEM, __LINE__, (ULONG_PTR) status, 0, 'VC')