From 5603661eec5b7410695d97ba6e7576b3daf83491 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Thu, 24 Jan 2019 09:36:05 -0500 Subject: [PATCH] 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. --- TestVectors/chacha_tls.txt | 120 +++++++++++----- bench2.cpp | 1 + chacha.cpp | 283 ++++++++++++++++++++++++++++++++++++- chacha.h | 84 ++++++++++- datatest.cpp | 2 +- regtest2.cpp | 1 + test.cpp | 9 +- validat3.cpp | 1 + validat4.cpp | 7 + validate.h | 1 + xed25519.h | 2 +- 11 files changed, 465 insertions(+), 46 deletions(-) diff --git a/TestVectors/chacha_tls.txt b/TestVectors/chacha_tls.txt index 6e44e39d..2a9f0912 100644 --- a/TestVectors/chacha_tls.txt +++ b/TestVectors/chacha_tls.txt @@ -1,37 +1,93 @@ AlgorithmType: SymmetricCipher -Name: ChaCha20 +Name: ChaChaTLS Source: http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305 -Comment: Section 7, Test 1 -Key: 0000000000000000000000000000000000000000000000000000000000000000 -IV: 0000000000000000 -Plaintext: -Ciphertext: 76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669 +# +Comment: Section A.2, ChaCha20 Encryption, Test 1 +Key: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 +IV: 00 00 00 00 00 00 00 00 00 00 00 00 +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 -Comment: Section 7, Test 2 -Key: 0000000000000000000000000000000000000000000000000000000000000001 -IV: 0000000000000000 -Plaintext: -Ciphertext: 4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275 +# +Comment: Section A.2, ChaCha20 Encryption, Test 2 +Key: 0000000000000000 0000000000000000 0000000000000000 0000000000000001 +IV: 00 00 00 00 00 00 00 00 00 00 00 02 +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 -Comment: Section 7, Test 3 -Key: 0000000000000000000000000000000000000000000000000000000000000000 -IV: 0000000000000001 -Plaintext: -Ciphertext: de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e445f41e3 -Test: Encrypt -Comment: Section 7, Test 4 -Key: 0000000000000000000000000000000000000000000000000000000000000000 -IV: 0100000000000000 -Plaintext: -Ciphertext: ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d6bbdb004 -Test: Encrypt -Comment: Section 7, Test 5 -Key: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f -IV: 0001020304050607 -Plaintext: -Ciphertext: f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1 \ - 5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e \ - 09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5 \ - 07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2 \ - ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb +# +Comment: Section A.2, ChaCha20 Encryption, Test 3 +Key: 1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 \ + 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0 +IV: 00 00 00 00 00 00 00 00 00 00 00 02 +Plaintext: 27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61 \ + 6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f \ + 76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64 \ + 20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77 \ + 61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77 \ + 65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65 \ + 73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20 \ + 72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e +Ciphertext: 62 e6 34 7f 95 ed 87 a4 5f fa e7 42 6f 27 a1 df \ + 5f b6 91 10 04 4c 0d 73 11 8e ff a9 5b 01 e5 cf \ + 16 6d 3d f2 d7 21 ca f9 b2 1e 5f b1 4c 61 68 71 \ + fd 84 c5 4f 9d 65 b2 83 19 6c 7f e4 f6 05 53 eb \ + f3 9c 64 02 c4 22 34 e3 2a 35 6b 3e 76 43 12 a6 \ + 1a 55 32 05 57 16 ea d6 96 25 68 f8 7d 3f 3f 77 \ + 04 c6 a8 d1 bc d1 bf 4d 50 d6 15 4b 6d a7 31 b1 \ + 87 b5 8d fd 72 8a fa 36 75 7a 79 7a c1 88 d1 +InitialBlock: 42 Test: Encrypt diff --git a/bench2.cpp b/bench2.cpp index 38da6224..9370df34 100644 --- a/bench2.cpp +++ b/bench2.cpp @@ -141,6 +141,7 @@ void Benchmark2(double t, double hertz) BenchMarkByName("ChaCha", 0, "ChaCha20"); BenchMarkByName("ChaCha", 0, "ChaCha12", MakeParameters(Name::Rounds(), 12)); BenchMarkByName("ChaCha", 0, "ChaCha8", MakeParameters(Name::Rounds(), 8)); + BenchMarkByName("ChaChaTLS"); BenchMarkByName("Sosemanuk"); BenchMarkByName("Rabbit"); BenchMarkByName("RabbitWithIV"); diff --git a/chacha.cpp b/chacha.cpp index 2bde58b1..2df162e0 100644 --- a/chacha.cpp +++ b/chacha.cpp @@ -63,9 +63,12 @@ extern void ChaCha_OperateKeystream_ALTIVEC(const word32 *state, const byte* inp void ChaCha_TestInstantiations() { ChaCha::Encryption x; + ChaChaTLS::Encryption y; } #endif +////////////////////////////// Bernstein ChaCha ////////////////////////////// + std::string ChaCha_Policy::AlgorithmName() const { return std::string("ChaCha")+IntToString(m_rounds); @@ -102,8 +105,7 @@ std::string ChaCha_Policy::AlgorithmProvider() const void ChaCha_Policy::CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length) { - CRYPTOPP_UNUSED(params); - CRYPTOPP_ASSERT(length == 16 || length == 32); + CRYPTOPP_ASSERT(key); CRYPTOPP_ASSERT(length == 16 || length == 32); m_rounds = params.GetIntValueWithDefault(Name::Rounds(), 20); if (!(m_rounds == 8 || m_rounds == 12 || m_rounds == 20)) @@ -326,4 +328,281 @@ void ChaCha_Policy::OperateKeystream(KeystreamOperation operation, } while (iterationCount--); } +////////////////////////////// IETF ChaChaTLS ////////////////////////////// + +std::string ChaChaTLS_Policy::AlgorithmName() const +{ + return std::string("ChaChaTLS")+IntToString(static_cast(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 ¶ms, 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(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 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 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::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(); +} + +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(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 diff --git a/chacha.h b/chacha.h index 39246c0f..d59dea0f 100644 --- a/chacha.h +++ b/chacha.h @@ -3,13 +3,24 @@ // and Bernstein's reference ChaCha family implementation at // 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 /// \brief Classes for ChaCha8, ChaCha12 and ChaCha20 stream ciphers /// \details Crypto++ provides Bernstein and ECRYPT's ChaCha from ChaCha, -/// a variant of Salsa20 (2008.01.28). Bernstein's implementation is _slightly_ different from the TLS working group's -/// implementation for cipher suites TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, -/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. -/// \since Crypto++ 5.6.4 +/// a variant of Salsa20 (2008.01.28). Crypto++ also provides the IETF +/// implementation of ChaCha using the ChaChaTLS name. Bernstein's +/// implementation is _slightly_ different from the TLS working group's +/// implementation for cipher suites +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, +/// and TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \since ChaCha since Crypto++ 5.6.4, ChaChaTLS since Crypto++ 8.1 #ifndef CRYPTOPP_CHACHA_H #define CRYPTOPP_CHACHA_H @@ -19,6 +30,8 @@ NAMESPACE_BEGIN(CryptoPP) +////////////////////////////// Bernstein ChaCha ////////////////////////////// + /// \brief ChaCha stream cipher information /// \since Crypto++ 5.6.4 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 { public: - ~ChaCha_Policy() {} - ChaCha_Policy() : m_rounds(0) {} + virtual ~ChaCha_Policy() {} + ChaCha_Policy() : m_rounds(0) {} protected: void CipherSetKey(const NameValuePairs ¶ms, const byte *key, size_t length); @@ -80,6 +93,65 @@ struct ChaCha : public ChaCha_Info, public SymmetricCipherDocumentation 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 +{ +public: + virtual ~ChaChaTLS_Policy() {} + ChaChaTLS_Policy() {} + +protected: + void CipherSetKey(const NameValuePairs ¶ms, 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 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 +/// TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +/// TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, and +/// TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256. +/// \sa ChaCha20 and Poly1305 for +/// IETF Protocols. +/// \since Crypto++ 8.1 +struct ChaChaTLS : public ChaChaTLS_Info, public SymmetricCipherDocumentation +{ + typedef SymmetricCipherFinal >, ChaChaTLS_Info > Encryption; + typedef Encryption Decryption; +}; + NAMESPACE_END #endif // CRYPTOPP_CHACHA_H diff --git a/datatest.cpp b/datatest.cpp index 6a15ecb2..d948421a 100644 --- a/datatest.cpp +++ b/datatest.cpp @@ -527,7 +527,7 @@ void TestSymmetricCipher(TestData &v, const NameValuePairs &overrideParameters) // been processed. Also note we only unlatch from testDataPairs. If // overrideParameters are specified, the caller is responsible for // 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; if (test == "EncryptionMCT" || test == "DecryptionMCT") diff --git a/regtest2.cpp b/regtest2.cpp index e68db6cc..57984c27 100644 --- a/regtest2.cpp +++ b/regtest2.cpp @@ -93,6 +93,7 @@ void RegisterFactories3() RegisterSymmetricCipherDefaultFactories(); RegisterSymmetricCipherDefaultFactories(); RegisterSymmetricCipherDefaultFactories(); + RegisterSymmetricCipherDefaultFactories(); RegisterSymmetricCipherDefaultFactories(); RegisterSymmetricCipherDefaultFactories(); RegisterSymmetricCipherDefaultFactories(); diff --git a/test.cpp b/test.cpp index 70f44526..8226b975 100644 --- a/test.cpp +++ b/test.cpp @@ -983,10 +983,11 @@ bool Validate(int alg, bool thorough, const char *seedInput) case 68: result = ValidateTTMAC(); break; case 70: result = ValidateSalsa(); break; case 71: result = ValidateChaCha(); break; - case 72: result = ValidateSosemanuk(); break; - case 73: result = ValidateRabbit(); break; - case 74: result = ValidateHC128(); break; - case 75: result = ValidateHC256(); break; + case 72: result = ValidateChaChaTLS(); break; + case 73: result = ValidateSosemanuk(); break; + case 74: result = ValidateRabbit(); break; + case 75: result = ValidateHC128(); break; + case 76: result = ValidateHC256(); break; case 80: result = ValidateVMAC(); break; case 81: result = ValidateCCM(); break; case 82: result = ValidateGCM(); break; diff --git a/validat3.cpp b/validat3.cpp index 9a2d454f..1dd9ac2e 100644 --- a/validat3.cpp +++ b/validat3.cpp @@ -156,6 +156,7 @@ bool ValidateAll(bool thorough) pass=ValidateCamellia() && pass; pass=ValidateSalsa() && pass; pass=ValidateChaCha() && pass; + pass=ValidateChaChaTLS() && pass; pass=ValidateSosemanuk() && pass; pass=ValidateRabbit() && pass; pass=ValidateHC128() && pass; diff --git a/validat4.cpp b/validat4.cpp index 96161a81..14409cc0 100644 --- a/validat4.cpp +++ b/validat4.cpp @@ -1743,6 +1743,13 @@ bool ValidateChaCha() return RunTestDataFile("TestVectors/chacha.txt"); } +bool ValidateChaChaTLS() +{ + std::cout << "\nChaCha-TLS validation suite running...\n"; + + return RunTestDataFile("TestVectors/chacha_tls.txt"); +} + bool ValidateSosemanuk() { std::cout << "\nSosemanuk validation suite running...\n"; diff --git a/validate.h b/validate.h index 3fa49d12..5337169e 100644 --- a/validate.h +++ b/validate.h @@ -106,6 +106,7 @@ bool ValidateHC256(); bool ValidateRabbit(); bool ValidateSalsa(); bool ValidateChaCha(); +bool ValidateChaChaTLS(); bool ValidateSosemanuk(); bool ValidateVMAC(); diff --git a/xed25519.h b/xed25519.h index e97c63f6..bb6ff228 100644 --- a/xed25519.h +++ b/xed25519.h @@ -598,7 +598,7 @@ protected: /// LSB is at element 0 and the MSB is at element 31. /// If you call GetPublicElement() then the little-endian byte /// array is converted to a big-endian Integer() so it can be -/// returned the way a caller expects. And calling +/// returned the way a caller expects. And calling /// SetPublicElement() perfoms a similar internal conversion. /// \since Crypto++ 8.0 struct ed25519PublicKey : public X509PublicKey