Add ChaChaTLS implementation (GH #265)

We tweaked ChaCha to arrive at the IETF's implementation specified by RFC 7539. We are not sure how to handle block counter wrap. At the moment the caller is responsible for managing it. We were not able to find a reference implementation so we disable SIMD implementations like SSE, AVX, NEON and Power4. We need the wide block tests for corner cases to ensure our implementation is correct.
pull/795/head
Jeffrey Walton 2019-01-24 09:36:05 -05:00
parent b47f04418c
commit 5603661eec
No known key found for this signature in database
GPG Key ID: B36AB348921B1838
11 changed files with 465 additions and 46 deletions

View File

@ -1,37 +1,93 @@
AlgorithmType: SymmetricCipher AlgorithmType: SymmetricCipher
Name: ChaCha20 Name: ChaChaTLS
Source: http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305 Source: http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305
Comment: Section 7, Test 1 #
Key: 0000000000000000000000000000000000000000000000000000000000000000 Comment: Section A.2, ChaCha20 Encryption, Test 1
IV: 0000000000000000 Key: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
Plaintext: IV: 00 00 00 00 00 00 00 00 00 00 00 00
Ciphertext: 76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669 Plaintext: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Ciphertext: 76 b8 e0 ad a0 f1 3d 90 40 5d 6a e5 53 86 bd 28 \
bd d2 19 b8 a0 8d ed 1a a8 36 ef cc 8b 77 0d c7 \
da 41 59 7c 51 57 48 8d 77 24 e0 3f b8 d8 4a 37 \
6a 43 b8 f4 15 18 a1 1c c3 87 b6 69 b2 ee 65 86
Test: Encrypt Test: Encrypt
Comment: Section 7, Test 2 #
Key: 0000000000000000000000000000000000000000000000000000000000000001 Comment: Section A.2, ChaCha20 Encryption, Test 2
IV: 0000000000000000 Key: 0000000000000000 0000000000000000 0000000000000000 0000000000000001
Plaintext: IV: 00 00 00 00 00 00 00 00 00 00 00 02
Ciphertext: 4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275 Plaintext: 41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74 \
6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e \
64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72 \
69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69 \
63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72 \
20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46 \
20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20 \
6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73 \
74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69 \
74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74 \
20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69 \
76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72 \
65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74 \
72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20 \
73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75 \
64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e \
74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69 \
6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20 \
77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63 \
74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61 \
74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e \
79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c \
20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65 \
73 73 65 64 20 74 6f
Ciphertext: a3 fb f0 7d f3 fa 2f de 4f 37 6c a2 3e 82 73 70 \
41 60 5d 9f 4f 4f 57 bd 8c ff 2c 1d 4b 79 55 ec \
2a 97 94 8b d3 72 29 15 c8 f3 d3 37 f7 d3 70 05 \
0e 9e 96 d6 47 b7 c3 9f 56 e0 31 ca 5e b6 25 0d \
40 42 e0 27 85 ec ec fa 4b 4b b5 e8 ea d0 44 0e \
20 b6 e8 db 09 d8 81 a7 c6 13 2f 42 0e 52 79 50 \
42 bd fa 77 73 d8 a9 05 14 47 b3 29 1c e1 41 1c \
68 04 65 55 2a a6 c4 05 b7 76 4d 5e 87 be a8 5a \
d0 0f 84 49 ed 8f 72 d0 d6 62 ab 05 26 91 ca 66 \
42 4b c8 6d 2d f8 0e a4 1f 43 ab f9 37 d3 25 9d \
c4 b2 d0 df b4 8a 6c 91 39 dd d7 f7 69 66 e9 28 \
e6 35 55 3b a7 6c 5c 87 9d 7b 35 d4 9e b2 e6 2b \
08 71 cd ac 63 89 39 e2 5e 8a 1e 0e f9 d5 28 0f \
a8 ca 32 8b 35 1c 3c 76 59 89 cb cf 3d aa 8b 6c \
cc 3a af 9f 39 79 c9 2b 37 20 fc 88 dc 95 ed 84 \
a1 be 05 9c 64 99 b9 fd a2 36 e7 e8 18 b0 4b 0b \
c3 9c 1e 87 6b 19 3b fe 55 69 75 3f 88 12 8c c0 \
8a aa 9b 63 d1 a1 6f 80 ef 25 54 d7 18 9c 41 1f \
58 69 ca 52 c5 b8 3f a3 6f f2 16 b9 c1 d3 00 62 \
be bc fd 2d c5 bc e0 91 19 34 fd a7 9a 86 f6 e6 \
98 ce d7 59 c3 ff 9b 64 77 33 8f 3d a4 f9 cd 85 \
14 ea 99 82 cc af b3 41 b2 38 4d d9 02 f3 d1 ab \
7a c6 1d d2 9c 6f 21 ba 5b 86 2f 37 30 e3 7c fd \
c4 fd 80 6c 22 f2 21
InitialBlock: 1
Test: Encrypt Test: Encrypt
Comment: Section 7, Test 3 #
Key: 0000000000000000000000000000000000000000000000000000000000000000 Comment: Section A.2, ChaCha20 Encryption, Test 3
IV: 0000000000000001 Key: 1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 \
Plaintext: 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0
Ciphertext: de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e445f41e3 IV: 00 00 00 00 00 00 00 00 00 00 00 02
Test: Encrypt Plaintext: 27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61 \
Comment: Section 7, Test 4 6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f \
Key: 0000000000000000000000000000000000000000000000000000000000000000 76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64 \
IV: 0100000000000000 20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77 \
Plaintext: 61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77 \
Ciphertext: ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d6bbdb004 65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65 \
Test: Encrypt 73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20 \
Comment: Section 7, Test 5 72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e
Key: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f Ciphertext: 62 e6 34 7f 95 ed 87 a4 5f fa e7 42 6f 27 a1 df \
IV: 0001020304050607 5f b6 91 10 04 4c 0d 73 11 8e ff a9 5b 01 e5 cf \
Plaintext: 16 6d 3d f2 d7 21 ca f9 b2 1e 5f b1 4c 61 68 71 \
Ciphertext: f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1 \ fd 84 c5 4f 9d 65 b2 83 19 6c 7f e4 f6 05 53 eb \
5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e \ f3 9c 64 02 c4 22 34 e3 2a 35 6b 3e 76 43 12 a6 \
09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5 \ 1a 55 32 05 57 16 ea d6 96 25 68 f8 7d 3f 3f 77 \
07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2 \ 04 c6 a8 d1 bc d1 bf 4d 50 d6 15 4b 6d a7 31 b1 \
ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb 87 b5 8d fd 72 8a fa 36 75 7a 79 7a c1 88 d1
InitialBlock: 42
Test: Encrypt Test: Encrypt

View File

@ -141,6 +141,7 @@ void Benchmark2(double t, double hertz)
BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha20"); BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha20");
BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha12", MakeParameters(Name::Rounds(), 12)); BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha12", MakeParameters(Name::Rounds(), 12));
BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha8", MakeParameters(Name::Rounds(), 8)); BenchMarkByName<SymmetricCipher>("ChaCha", 0, "ChaCha8", MakeParameters(Name::Rounds(), 8));
BenchMarkByName<SymmetricCipher>("ChaChaTLS");
BenchMarkByName<SymmetricCipher>("Sosemanuk"); BenchMarkByName<SymmetricCipher>("Sosemanuk");
BenchMarkByName<SymmetricCipher>("Rabbit"); BenchMarkByName<SymmetricCipher>("Rabbit");
BenchMarkByName<SymmetricCipher>("RabbitWithIV"); BenchMarkByName<SymmetricCipher>("RabbitWithIV");

View File

@ -63,9 +63,12 @@ extern void ChaCha_OperateKeystream_ALTIVEC(const word32 *state, const byte* inp
void ChaCha_TestInstantiations() void ChaCha_TestInstantiations()
{ {
ChaCha::Encryption x; ChaCha::Encryption x;
ChaChaTLS::Encryption y;
} }
#endif #endif
////////////////////////////// Bernstein ChaCha //////////////////////////////
std::string ChaCha_Policy::AlgorithmName() const std::string ChaCha_Policy::AlgorithmName() const
{ {
return std::string("ChaCha")+IntToString(m_rounds); return std::string("ChaCha")+IntToString(m_rounds);
@ -102,8 +105,7 @@ std::string ChaCha_Policy::AlgorithmProvider() const
void ChaCha_Policy::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length) void ChaCha_Policy::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)
{ {
CRYPTOPP_UNUSED(params); CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 16 || length == 32);
CRYPTOPP_ASSERT(length == 16 || length == 32);
m_rounds = params.GetIntValueWithDefault(Name::Rounds(), 20); m_rounds = params.GetIntValueWithDefault(Name::Rounds(), 20);
if (!(m_rounds == 8 || m_rounds == 12 || m_rounds == 20)) if (!(m_rounds == 8 || m_rounds == 12 || m_rounds == 20))
@ -326,4 +328,281 @@ void ChaCha_Policy::OperateKeystream(KeystreamOperation operation,
} while (iterationCount--); } while (iterationCount--);
} }
////////////////////////////// IETF ChaChaTLS //////////////////////////////
std::string ChaChaTLS_Policy::AlgorithmName() const
{
return std::string("ChaChaTLS")+IntToString(static_cast<unsigned int>(m_rounds));
}
std::string ChaChaTLS_Policy::AlgorithmProvider() const
{
#if (CRYPTOPP_AVX2_AVAILABLE)
if (HasAVX2())
return "AVX2";
else
#endif
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
if (HasSSE2())
return "SSE2";
else
#endif
#if (CRYPTOPP_ARM_NEON_AVAILABLE)
if (HasNEON())
return "NEON";
else
#endif
#if (CRYPTOPP_POWER7_AVAILABLE)
if (HasPower7())
return "Power7";
else
#elif (CRYPTOPP_ALTIVEC_AVAILABLE)
if (HasAltivec())
return "Altivec";
else
#endif
return "C++";
}
void ChaChaTLS_Policy::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)
{
CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 32);
// ChaChaTLS is always 20 rounds. Fetch Rounds() to avoid a spurious failure.
int rounds = params.GetIntValueWithDefault(Name::Rounds(), m_rounds);
if (rounds != 20)
throw InvalidRounds(ChaChaTLS::StaticAlgorithmName(), rounds);
// RFC 7539 test vectors use an initial block counter. However, some of them
// don't start at 0. If Resynchronize() is called we set to 0. Hence, stash
// the initial block counter in m_state[16]. Then use it in Resynchronize().
int block;
if (params.GetValue("InitialBlock", block))
m_state[16] = static_cast<word32>(block);
else
m_state[16] = 0;
// State words are defined in RFC 7539, Section 2.3.
m_state[0] = 0x61707865;
m_state[1] = 0x3320646e;
m_state[2] = 0x79622d32;
m_state[3] = 0x6b206574;
// State words are defined in RFC 7539, Section 2.3. Key is 32-bytes.
GetBlock<word32, LittleEndian> get(key);
get(m_state[4])(m_state[5])(m_state[6])(m_state[7])(m_state[8])(m_state[9])(m_state[10])(m_state[11]);
}
void ChaChaTLS_Policy::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length)
{
CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length);
CRYPTOPP_ASSERT(length==12);
// State words are defined in RFC 7539, Section 2.3
GetBlock<word32, LittleEndian> get(IV);
m_state[12] = m_state[16];
get(m_state[13])(m_state[14])(m_state[15]);
}
void ChaChaTLS_Policy::SeekToIteration(lword iterationCount)
{
// State words are defined in RFC 7539, Section 2.3
// Should we throw here???
CRYPTOPP_ASSERT(iterationCount <= std::numeric_limits<word32>::max());
m_state[12] = (word32)iterationCount; // low word
}
unsigned int ChaChaTLS_Policy::GetAlignment() const
{
#if (CRYPTOPP_AVX2_AVAILABLE)
if (HasAVX2())
return 16;
else
#endif
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
if (HasSSE2())
return 16;
else
#endif
#if (CRYPTOPP_ALTIVEC_AVAILABLE)
if (HasAltivec())
return 16;
else
#endif
return GetAlignmentOf<word32>();
}
unsigned int ChaChaTLS_Policy::GetOptimalBlockSize() const
{
// Disable SIMD until we can generate large block test vectors
// https://mailarchive.ietf.org/arch/msg/saag/S0_YjVkzEx2s2bHd8KIzjK1CwZ4
#if 0
#if (CRYPTOPP_AVX2_AVAILABLE)
if (HasAVX2())
return 8 * BYTES_PER_ITERATION;
else
#endif
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
if (HasSSE2())
return 4*BYTES_PER_ITERATION;
else
#endif
#if (CRYPTOPP_ARM_NEON_AVAILABLE)
if (HasNEON())
return 4*BYTES_PER_ITERATION;
else
#endif
#if (CRYPTOPP_ALTIVEC_AVAILABLE)
if (HasAltivec())
return 4*BYTES_PER_ITERATION;
else
#endif
#endif
return BYTES_PER_ITERATION;
}
// 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.
void ChaChaTLS_Policy::OperateKeystream(KeystreamOperation operation,
byte *output, const byte *input, size_t iterationCount)
{
// Disable SIMD until we can generate large block test vectors
// https://mailarchive.ietf.org/arch/msg/saag/S0_YjVkzEx2s2bHd8KIzjK1CwZ4
#if 0
#if (CRYPTOPP_AVX2_AVAILABLE)
if (HasAVX2())
{
while (iterationCount >= 8)
{
const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL;
ChaCha_OperateKeystream_AVX2(m_state, xorInput ? input : NULLPTR, output, m_rounds);
// MultiBlockSafe avoids overflow on the counter words
m_state[12] += 8;
//if (m_state[12] < 8)
// m_state[13]++;
input += (!!xorInput) * 8 * BYTES_PER_ITERATION;
output += 8 * BYTES_PER_ITERATION;
iterationCount -= 8;
}
}
#endif
#if (CRYPTOPP_SSE2_INTRIN_AVAILABLE)
if (HasSSE2())
{
while (iterationCount >= 4)
{
const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL;
ChaCha_OperateKeystream_SSE2(m_state, xorInput ? input : NULLPTR, output, m_rounds);
// MultiBlockSafe avoids overflow on the counter words
m_state[12] += 4;
//if (m_state[12] < 4)
// m_state[13]++;
input += (!!xorInput)*4*BYTES_PER_ITERATION;
output += 4*BYTES_PER_ITERATION;
iterationCount -= 4;
}
}
#endif
#if (CRYPTOPP_ARM_NEON_AVAILABLE)
if (HasNEON())
{
while (iterationCount >= 4)
{
const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL;
ChaCha_OperateKeystream_NEON(m_state, xorInput ? input : NULLPTR, output, m_rounds);
// MultiBlockSafe avoids overflow on the counter words
m_state[12] += 4;
//if (m_state[12] < 4)
// m_state[13]++;
input += (!!xorInput)*4*BYTES_PER_ITERATION;
output += 4*BYTES_PER_ITERATION;
iterationCount -= 4;
}
}
#endif
#if (CRYPTOPP_POWER7_AVAILABLE)
if (HasPower7())
{
while (iterationCount >= 4)
{
const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL;
ChaCha_OperateKeystream_POWER7(m_state, xorInput ? input : NULLPTR, output, m_rounds);
// MultiBlockSafe avoids overflow on the counter words
m_state[12] += 4;
//if (m_state[12] < 4)
// m_state[13]++;
input += (!!xorInput)*4*BYTES_PER_ITERATION;
output += 4*BYTES_PER_ITERATION;
iterationCount -= 4;
}
}
#elif (CRYPTOPP_ALTIVEC_AVAILABLE)
if (HasAltivec())
{
while (iterationCount >= 4)
{
const bool xorInput = (operation & INPUT_NULL) != INPUT_NULL;
ChaCha_OperateKeystream_ALTIVEC(m_state, xorInput ? input : NULLPTR, output, m_rounds);
// MultiBlockSafe avoids overflow on the counter words
m_state[12] += 4;
//if (m_state[12] < 4)
// m_state[13]++;
input += (!!xorInput)*4*BYTES_PER_ITERATION;
output += 4*BYTES_PER_ITERATION;
iterationCount -= 4;
}
}
#endif
#endif
while (iterationCount--)
{
word32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
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];
for (int i = static_cast<int>(m_rounds); i > 0; i -= 2)
{
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);
}
CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(CHACHA_OUTPUT, BYTES_PER_ITERATION);
if (++m_state[12] == 0)
{
// m_state[13]++;
// RFC 7539 does not say what to do here. ChaCha-TLS uses state[13]
// for part of the nonce. We can't carry into it. Shit or go blind...
// https://mailarchive.ietf.org/arch/msg/saag/S0_YjVkzEx2s2bHd8KIzjK1CwZ4
CRYPTOPP_ASSERT(0);
}
}
}
NAMESPACE_END NAMESPACE_END

View File

@ -3,13 +3,24 @@
// and Bernstein's reference ChaCha family implementation at // and Bernstein's reference ChaCha family implementation at
// http://cr.yp.to/chacha.html. // http://cr.yp.to/chacha.html.
// Crypto++ added Bernstein's ChaCha classses at version 5.6.4 of the library.
// The IETF uses a slightly different implementation, and the classes were
// added at Crypto++ version 8.1. We wanted to maintain ABI compatibility at
// the 8.1 release so the original ChaCha classes were not disturbed. Instead
// new classes were added for IETF ChaCha. The back-end implementation shares
// code as expected, however.
/// \file chacha.h /// \file chacha.h
/// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers /// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers
/// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from <a href="http://cr.yp.to/chacha/chacha-20080128.pdf">ChaCha, /// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from <a href="http://cr.yp.to/chacha/chacha-20080128.pdf">ChaCha,
/// a variant of Salsa20</a> (2008.01.28). Bernstein's implementation is _slightly_ different from the TLS working group's /// a variant of Salsa20</a> (2008.01.28). Crypto++ also provides the IETF
/// implementation for cipher suites <tt>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>, /// implementation of ChaCha using the ChaChaTLS name. Bernstein's
/// <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>, and <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>. /// implementation is _slightly_ different from the TLS working group's
/// \since Crypto++ 5.6.4 /// implementation for cipher suites
/// <tt>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
/// <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
/// and <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>.
/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS since Crypto++ 8.1
#ifndef CRYPTOPP_CHACHA_H #ifndef CRYPTOPP_CHACHA_H
#define CRYPTOPP_CHACHA_H #define CRYPTOPP_CHACHA_H
@ -19,6 +30,8 @@
NAMESPACE_BEGIN(CryptoPP) NAMESPACE_BEGIN(CryptoPP)
////////////////////////////// Bernstein ChaCha //////////////////////////////
/// \brief ChaCha stream cipher information /// \brief ChaCha stream cipher information
/// \since Crypto++ 5.6.4 /// \since Crypto++ 5.6.4
struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8> struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterface::UNIQUE_IV, 8>
@ -40,8 +53,8 @@ struct ChaCha_Info : public VariableKeyLength<32, 16, 32, 16, SimpleKeyingInterf
class CRYPTOPP_NO_VTABLE ChaCha_Policy : public AdditiveCipherConcretePolicy<word32, 16> class CRYPTOPP_NO_VTABLE ChaCha_Policy : public AdditiveCipherConcretePolicy<word32, 16>
{ {
public: public:
~ChaCha_Policy() {} virtual ~ChaCha_Policy() {}
ChaCha_Policy() : m_rounds(0) {} ChaCha_Policy() : m_rounds(0) {}
protected: protected:
void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length); void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
@ -80,6 +93,65 @@ struct ChaCha : public ChaCha_Info, public SymmetricCipherDocumentation
typedef Encryption Decryption; typedef Encryption Decryption;
}; };
////////////////////////////// IETF ChaChaTLS //////////////////////////////
/// \brief ChaCha-TLS stream cipher information
/// \since Crypto++ 8.1
struct ChaChaTLS_Info : public FixedKeyLength<32, SimpleKeyingInterface::UNIQUE_IV, 12>, FixedRounds<20>
{
/// \brief The algorithm name
/// \returns the algorithm name
/// \details StaticAlgorithmName returns the algorithm's name as a static
/// member function.
/// \details This is the IETF's variant of Bernstein's ChaCha from RFC 7539.
/// IETF ChaCha is called ChaChaTLS in the Crypto++ library. It is
/// _slightly_ different from Bernstein's implementation.
static const char* StaticAlgorithmName() {
return "ChaChaTLS";
}
};
/// \brief ChaCha-TLS stream cipher implementation
/// \since Crypto++ 8.1
class CRYPTOPP_NO_VTABLE ChaChaTLS_Policy : public AdditiveCipherConcretePolicy<word32, 16>
{
public:
virtual ~ChaChaTLS_Policy() {}
ChaChaTLS_Policy() {}
protected:
void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length);
void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount);
void CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length);
bool CipherIsRandomAccess() const {return true;}
void SeekToIteration(lword iterationCount);
unsigned int GetAlignment() const;
unsigned int GetOptimalBlockSize() const;
std::string AlgorithmName() const;
std::string AlgorithmProvider() const;
FixedSizeAlignedSecBlock<word32, 16+1> m_state;
CRYPTOPP_CONSTANT(m_rounds = ChaChaTLS_Info::ROUNDS)
};
/// \brief ChaCha-TLS stream cipher
/// \details This is the IETF's variant of Bernstein's ChaCha from RFC 7539.
/// IETF ChaCha is called ChaChaTLS in the Crypto++ library. It is
/// _slightly_ different from the Bernstein's implementation. ChaCha-TLS
/// can be used for cipher suites
/// <tt>TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>,
/// <tt>TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256</tt>, and
/// <tt>TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256</tt>.
/// \sa <a href="https://tools.ietf.org/html/rfc7539">ChaCha20 and Poly1305 for
/// IETF Protocols</a>.
/// \since Crypto++ 8.1
struct ChaChaTLS : public ChaChaTLS_Info, public SymmetricCipherDocumentation
{
typedef SymmetricCipherFinal<ConcretePolicyHolder<ChaChaTLS_Policy, AdditiveCipherTemplate<> >, ChaChaTLS_Info > Encryption;
typedef Encryption Decryption;
};
NAMESPACE_END NAMESPACE_END
#endif // CRYPTOPP_CHACHA_H #endif // CRYPTOPP_CHACHA_H

View File

@ -527,7 +527,7 @@ void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters)
// been processed. Also note we only unlatch from testDataPairs. If // been processed. Also note we only unlatch from testDataPairs. If
// overrideParameters are specified, the caller is responsible for // overrideParameters are specified, the caller is responsible for
// managing the parameter. // managing the parameter.
v.erase("Tweak"); v.erase("BlockSize"); v.erase("BlockPaddingScheme"); v.erase("Tweak"); v.erase("InitialBlock"); v.erase("BlockSize"); v.erase("BlockPaddingScheme");
std::string encrypted, xorDigest, ciphertext, ciphertextXorDigest; std::string encrypted, xorDigest, ciphertext, ciphertextXorDigest;
if (test == "EncryptionMCT" || test == "DecryptionMCT") if (test == "EncryptionMCT" || test == "DecryptionMCT")

View File

@ -93,6 +93,7 @@ void RegisterFactories3()
RegisterSymmetricCipherDefaultFactories<Salsa20>(); RegisterSymmetricCipherDefaultFactories<Salsa20>();
RegisterSymmetricCipherDefaultFactories<XSalsa20>(); RegisterSymmetricCipherDefaultFactories<XSalsa20>();
RegisterSymmetricCipherDefaultFactories<ChaCha>(); RegisterSymmetricCipherDefaultFactories<ChaCha>();
RegisterSymmetricCipherDefaultFactories<ChaChaTLS>();
RegisterSymmetricCipherDefaultFactories<Sosemanuk>(); RegisterSymmetricCipherDefaultFactories<Sosemanuk>();
RegisterSymmetricCipherDefaultFactories<Rabbit>(); RegisterSymmetricCipherDefaultFactories<Rabbit>();
RegisterSymmetricCipherDefaultFactories<RabbitWithIV>(); RegisterSymmetricCipherDefaultFactories<RabbitWithIV>();

View File

@ -983,10 +983,11 @@ bool Validate(int alg, bool thorough, const char *seedInput)
case 68: result = ValidateTTMAC(); break; case 68: result = ValidateTTMAC(); break;
case 70: result = ValidateSalsa(); break; case 70: result = ValidateSalsa(); break;
case 71: result = ValidateChaCha(); break; case 71: result = ValidateChaCha(); break;
case 72: result = ValidateSosemanuk(); break; case 72: result = ValidateChaChaTLS(); break;
case 73: result = ValidateRabbit(); break; case 73: result = ValidateSosemanuk(); break;
case 74: result = ValidateHC128(); break; case 74: result = ValidateRabbit(); break;
case 75: result = ValidateHC256(); break; case 75: result = ValidateHC128(); break;
case 76: result = ValidateHC256(); break;
case 80: result = ValidateVMAC(); break; case 80: result = ValidateVMAC(); break;
case 81: result = ValidateCCM(); break; case 81: result = ValidateCCM(); break;
case 82: result = ValidateGCM(); break; case 82: result = ValidateGCM(); break;

View File

@ -156,6 +156,7 @@ bool ValidateAll(bool thorough)
pass=ValidateCamellia() && pass; pass=ValidateCamellia() && pass;
pass=ValidateSalsa() && pass; pass=ValidateSalsa() && pass;
pass=ValidateChaCha() && pass; pass=ValidateChaCha() && pass;
pass=ValidateChaChaTLS() && pass;
pass=ValidateSosemanuk() && pass; pass=ValidateSosemanuk() && pass;
pass=ValidateRabbit() && pass; pass=ValidateRabbit() && pass;
pass=ValidateHC128() && pass; pass=ValidateHC128() && pass;

View File

@ -1743,6 +1743,13 @@ bool ValidateChaCha()
return RunTestDataFile("TestVectors/chacha.txt"); return RunTestDataFile("TestVectors/chacha.txt");
} }
bool ValidateChaChaTLS()
{
std::cout << "\nChaCha-TLS validation suite running...\n";
return RunTestDataFile("TestVectors/chacha_tls.txt");
}
bool ValidateSosemanuk() bool ValidateSosemanuk()
{ {
std::cout << "\nSosemanuk validation suite running...\n"; std::cout << "\nSosemanuk validation suite running...\n";

View File

@ -106,6 +106,7 @@ bool ValidateHC256();
bool ValidateRabbit(); bool ValidateRabbit();
bool ValidateSalsa(); bool ValidateSalsa();
bool ValidateChaCha(); bool ValidateChaCha();
bool ValidateChaChaTLS();
bool ValidateSosemanuk(); bool ValidateSosemanuk();
bool ValidateVMAC(); bool ValidateVMAC();