2016-04-21 16:08:36 +00:00
|
|
|
// chacha.cpp - written and placed in the public domain by Jeffrey Walton.
|
2016-07-23 23:37:17 +00:00
|
|
|
// Based on Wei Dai's Salsa20 and Bernstein's reference ChaCha
|
2016-04-21 16:12:42 +00:00
|
|
|
// family implementation at http://cr.yp.to/chacha.html.
|
2016-04-21 16:08:36 +00:00
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "chacha.h"
|
|
|
|
#include "argnames.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
|
|
|
|
NAMESPACE_BEGIN(CryptoPP)
|
2016-04-21 23:53:04 +00:00
|
|
|
|
2018-10-24 05:11:45 +00:00
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE)
|
2018-10-24 15:00:35 +00:00
|
|
|
extern void ChaCha_OperateKeystream_SSE2(const word32 *state, const byte* input, byte *output, unsigned int rounds, bool xorInput);
|
2018-10-24 05:11:45 +00:00
|
|
|
#endif
|
|
|
|
|
2016-04-21 16:12:42 +00:00
|
|
|
#define CHACHA_QUARTER_ROUND(a,b,c,d) \
|
2017-11-25 07:52:19 +00:00
|
|
|
a += b; d ^= a; d = rotlConstant<16,word32>(d); \
|
|
|
|
c += d; b ^= c; b = rotlConstant<12,word32>(b); \
|
|
|
|
a += b; d ^= a; d = rotlConstant<8,word32>(d); \
|
|
|
|
c += d; b ^= c; b = rotlConstant<7,word32>(b);
|
2016-04-21 16:08:36 +00:00
|
|
|
|
2016-10-18 02:00:31 +00:00
|
|
|
#if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING)
|
2016-04-21 16:08:36 +00:00
|
|
|
void ChaCha_TestInstantiations()
|
|
|
|
{
|
2018-08-18 05:31:35 +00:00
|
|
|
ChaCha::Encryption x;
|
2016-04-21 16:08:36 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-10-23 11:57:59 +00:00
|
|
|
std::string ChaCha_Policy::AlgorithmProvider() const
|
|
|
|
{
|
2018-10-24 05:11:45 +00:00
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE)
|
2018-10-23 11:57:59 +00:00
|
|
|
if (HasSSE2())
|
|
|
|
return "SSE2";
|
|
|
|
#endif
|
|
|
|
return "C++";
|
|
|
|
}
|
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
void ChaCha_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length)
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2016-04-21 16:12:42 +00:00
|
|
|
CRYPTOPP_UNUSED(params);
|
2016-09-16 15:27:15 +00:00
|
|
|
CRYPTOPP_ASSERT(length == 16 || length == 32);
|
2016-04-21 16:08:36 +00:00
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
m_rounds = params.GetIntValueWithDefault(Name::Rounds(), 20);
|
|
|
|
if (!(m_rounds == 8 || m_rounds == 12 || m_rounds == 20))
|
|
|
|
throw InvalidRounds(ChaCha::StaticAlgorithmName(), m_rounds);
|
|
|
|
|
2016-04-21 16:08:36 +00:00
|
|
|
// "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;
|
2016-04-21 16:12:42 +00:00
|
|
|
|
|
|
|
GetBlock<word32, LittleEndian> get1(key);
|
|
|
|
get1(m_state[4])(m_state[5])(m_state[6])(m_state[7]);
|
|
|
|
|
|
|
|
GetBlock<word32, LittleEndian> get2(key + ((length == 32) ? 16 : 0));
|
|
|
|
get2(m_state[8])(m_state[9])(m_state[10])(m_state[11]);
|
2016-04-21 16:08:36 +00:00
|
|
|
}
|
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
void ChaCha_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length)
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
|
|
|
CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length);
|
2016-09-16 15:27:15 +00:00
|
|
|
CRYPTOPP_ASSERT(length==8);
|
2016-04-21 16:08:36 +00:00
|
|
|
|
|
|
|
GetBlock<word32, LittleEndian> get(IV);
|
2016-04-21 16:12:42 +00:00
|
|
|
m_state[12] = m_state[13] = 0;
|
|
|
|
get(m_state[14])(m_state[15]);
|
2016-04-21 16:08:36 +00:00
|
|
|
}
|
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
void ChaCha_Policy::SeekToIteration(lword iterationCount)
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2018-10-23 11:57:59 +00:00
|
|
|
m_state[13] = (word32)iterationCount;
|
|
|
|
m_state[12] = (word32)SafeRightShift<32>(iterationCount);
|
2016-04-21 16:08:36 +00:00
|
|
|
}
|
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
unsigned int ChaCha_Policy::GetAlignment() const
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2018-10-24 05:11:45 +00:00
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE)
|
2016-04-21 16:08:36 +00:00
|
|
|
if (HasSSE2())
|
|
|
|
return 16;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
return GetAlignmentOf<word32>();
|
|
|
|
}
|
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
unsigned int ChaCha_Policy::GetOptimalBlockSize() const
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2018-10-24 05:11:45 +00:00
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE)
|
2016-04-21 16:08:36 +00:00
|
|
|
if (HasSSE2())
|
|
|
|
return 4*BYTES_PER_ITERATION;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
return BYTES_PER_ITERATION;
|
|
|
|
}
|
|
|
|
|
2018-10-24 15:00:35 +00:00
|
|
|
// OperateKeystream always produces a key stream. The key stream is written
|
|
|
|
// to output. Optionally a message may be supplied to xor with the key stream.
|
|
|
|
// The message is input, and output = output ^ input.
|
2018-10-23 11:57:59 +00:00
|
|
|
void ChaCha_Policy::OperateKeystream(KeystreamOperation operation,
|
|
|
|
byte *output, const byte *input, size_t iterationCount)
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2018-10-24 05:11:45 +00:00
|
|
|
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE || CRYPTOPP_SSE2_ASM_AVAILABLE)
|
2018-10-23 11:57:59 +00:00
|
|
|
if (HasSSE2())
|
|
|
|
{
|
|
|
|
while (iterationCount >= 4)
|
|
|
|
{
|
2018-10-24 15:00:35 +00:00
|
|
|
bool xorInput = (operation & INPUT_NULL) != INPUT_NULL;
|
|
|
|
ChaCha_OperateKeystream_SSE2(m_state, input, output, m_rounds, xorInput);
|
2018-10-23 11:57:59 +00:00
|
|
|
|
|
|
|
m_state[12] += 4;
|
|
|
|
if (m_state[12] < 4)
|
|
|
|
m_state[13]++;
|
|
|
|
|
2018-10-24 19:34:54 +00:00
|
|
|
input += !!xorInput*4*BYTES_PER_ITERATION;
|
2018-10-23 11:57:59 +00:00
|
|
|
output += 4*BYTES_PER_ITERATION;
|
|
|
|
iterationCount -= 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2016-04-21 16:08:36 +00:00
|
|
|
|
2016-04-21 16:12:42 +00:00
|
|
|
while (iterationCount--)
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2018-10-23 11:57:59 +00:00
|
|
|
word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
|
|
|
|
2016-04-21 16:12:42 +00:00
|
|
|
x0 = m_state[0]; x1 = m_state[1]; x2 = m_state[2]; x3 = m_state[3];
|
|
|
|
x4 = m_state[4]; x5 = m_state[5]; x6 = m_state[6]; x7 = m_state[7];
|
|
|
|
x8 = m_state[8]; x9 = m_state[9]; x10 = m_state[10]; x11 = m_state[11];
|
|
|
|
x12 = m_state[12]; x13 = m_state[13]; x14 = m_state[14]; x15 = m_state[15];
|
2016-04-21 16:08:36 +00:00
|
|
|
|
2018-08-17 10:19:30 +00:00
|
|
|
for (int i = static_cast<int>(m_rounds); i > 0; i -= 2)
|
2016-04-21 16:08:36 +00:00
|
|
|
{
|
2016-04-21 16:12:42 +00:00
|
|
|
CHACHA_QUARTER_ROUND(x0, x4, x8, x12);
|
|
|
|
CHACHA_QUARTER_ROUND(x1, x5, x9, x13);
|
|
|
|
CHACHA_QUARTER_ROUND(x2, x6, x10, x14);
|
|
|
|
CHACHA_QUARTER_ROUND(x3, x7, x11, x15);
|
|
|
|
|
|
|
|
CHACHA_QUARTER_ROUND(x0, x5, x10, x15);
|
|
|
|
CHACHA_QUARTER_ROUND(x1, x6, x11, x12);
|
|
|
|
CHACHA_QUARTER_ROUND(x2, x7, x8, x13);
|
|
|
|
CHACHA_QUARTER_ROUND(x3, x4, x9, x14);
|
2016-04-21 16:08:36 +00:00
|
|
|
}
|
|
|
|
|
2018-10-23 11:57:59 +00:00
|
|
|
#ifndef CRYPTOPP_DOXYGEN_PROCESSING
|
2016-04-21 16:12:42 +00:00
|
|
|
#define CHACHA_OUTPUT(x){\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 0, x0 + m_state[0]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 1, x1 + m_state[1]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 2, x2 + m_state[2]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 3, x3 + m_state[3]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 4, x4 + m_state[4]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 5, x5 + m_state[5]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 6, x6 + m_state[6]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 7, x7 + m_state[7]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 8, x8 + m_state[8]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 9, x9 + m_state[9]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 10, x10 + m_state[10]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 11, x11 + m_state[11]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 12, x12 + m_state[12]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 13, x13 + m_state[13]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 14, x14 + m_state[14]);\
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, LITTLE_ENDIAN_ORDER, 15, x15 + m_state[15]);}
|
|
|
|
|
|
|
|
CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(CHACHA_OUTPUT, BYTES_PER_ITERATION);
|
2018-10-23 11:57:59 +00:00
|
|
|
#undef CHACHA_OUTPUT
|
2016-04-21 16:12:42 +00:00
|
|
|
#endif
|
|
|
|
|
2018-10-23 11:57:59 +00:00
|
|
|
if (++m_state[12] == 0)
|
|
|
|
m_state[13]++;
|
2016-04-21 16:08:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 20:25:41 +00:00
|
|
|
NAMESPACE_END
|