From 0f702accfc8fd7eb1f6a9f98e4b004d6949b58c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Thu, 21 Apr 2016 12:08:36 -0400 Subject: [PATCH] Add ChaCha family of stream ciphers --- chacha.cpp | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 chacha.cpp diff --git a/chacha.cpp b/chacha.cpp new file mode 100644 index 00000000..477bbde2 --- /dev/null +++ b/chacha.cpp @@ -0,0 +1,152 @@ +// chacha.cpp - written and placed in the public domain by Jeffrey Walton. +// Copyright assigned to the Crypto++ project. + +#include "pch.h" +#include "config.h" +#include "chacha.h" +#include "argnames.h" +#include "misc.h" +#include "cpu.h" + +#if CRYPTOPP_MSC_VERSION +# pragma warning(disable: 4702 4740) +#endif + +NAMESPACE_BEGIN(CryptoPP) + +#define CHACHA_QUARTER_ROUND(z,a,b,c,d) \ + z[a] += z[b]; z[d] ^= z[a]; z[d] = rotrFixed(z[d],16); \ + z[c] += z[d]; z[b] ^= z[c]; z[b] = rotrFixed(z[b],12); \ + z[a] += z[b]; z[d] ^= z[a]; z[d] = rotrFixed(z[d], 8); \ + z[c] += z[d]; z[b] ^= z[c]; z[b] = rotrFixed(z[b], 7); + +#if !defined(NDEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) +void ChaCha_TestInstantiations() +{ + ChaCha8::Encryption x1; + ChaCha12::Encryption x2; + ChaCha20::Encryption x3; +} +#endif + + +static inline void salsa20_wordtobyte(byte output[64], const word32 input[16]) +{ + word32 x[16]; + unsigned int i; + + for (i = 0;i < 16;++i) + x[i] = input[i]; + + for (i = 8;i > 0;i -= 2) + { + CHACHA_QUARTER_ROUND(x, 0, 4, 8,12); + CHACHA_QUARTER_ROUND(x, 1, 5, 9,13); + CHACHA_QUARTER_ROUND(x, 2, 6,10,14); + CHACHA_QUARTER_ROUND(x, 3, 7,11,15); + CHACHA_QUARTER_ROUND(x, 0, 5,10,15); + CHACHA_QUARTER_ROUND(x, 1, 6,11,12); + CHACHA_QUARTER_ROUND(x, 2, 7, 8,13); + CHACHA_QUARTER_ROUND(x, 3, 4, 9,14); + } + + for (i = 0;i < 16;++i) + x[i] += input[i]; + + //for (i = 0;i < 16;++i) + // U32TO8_LITTLE(output + 4 * i,x[i]); + + //for (i = 0;i < 16;++i) + // PutWord<>(output + 4 * i,x[i]); +} + +template +void ChaCha_Base::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) +{ + // m_state is reordered for SSE2 + GetBlock get1(key); + get1(m_state[13])(m_state[10])(m_state[7])(m_state[4]); + GetBlock get2(key + length - 16); + get2(m_state[15])(m_state[12])(m_state[9])(m_state[6]); + + // "expand 16-byte k" or "expand 32-byte k" + m_state[0] = 0x61707865; + m_state[1] = (length == 16) ? 0x3120646e : 0x3320646e; + m_state[2] = (length == 16) ? 0x79622d36 : 0x79622d32; + m_state[3] = 0x6b206574; +} + +template +void ChaCha_Base::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length) +{ + CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); + assert(length==8); + + GetBlock get(IV); + get(m_state[14])(m_state[11]); + m_state[8] = m_state[5] = 0; +} + +template +void ChaCha_Base::SeekToIteration(lword iterationCount) +{ + m_state[8] = (word32)iterationCount; + m_state[5] = (word32)SafeRightShift<32>(iterationCount); +} + +template +unsigned int ChaCha_Base::GetAlignment() const +{ +#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return 16; + else +#endif + return GetAlignmentOf(); +} + +template +unsigned int ChaCha_Base::GetOptimalBlockSize() const +{ +#if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE + if (HasSSE2()) + return 4*BYTES_PER_ITERATION; + else +#endif + return BYTES_PER_ITERATION; +} + +template +void ChaCha_Base::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) +{ + byte buffer[64]; + size_t i, bytes=64; + + if (!bytes) return; + + for (;;) + { + salsa20_wordtobyte(buffer,m_state); + + m_state[12]++; + if (!m_state[12]) + m_state[13]++; + + if (bytes <= 64) + { + for (i = 0;i < bytes;++i) + output[i] = input[i] ^ buffer[i]; + return; + } + + for (i = 0;i < 64;++i) + output[i] = input[i] ^ buffer[i]; + + bytes -= 64; + output += 64; + input += 64; + } +} + +NAMESPACE_END + \ No newline at end of file