From 62ec713961ade7b58e90c905395558a41e8a59f0 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 21 Sep 2022 17:39:48 -0400 Subject: [PATCH] Only support 32-byte keys in ChaCha20{,Aligned} --- src/bench/chacha20.cpp | 2 +- src/crypto/chacha20.cpp | 31 ++++++++------------- src/crypto/chacha20.h | 18 ++++++------ src/crypto/chacha_poly_aead.cpp | 5 ++-- src/crypto/muhash.cpp | 2 +- src/random.cpp | 6 ++-- src/test/crypto_tests.cpp | 11 ++++---- src/test/fuzz/crypto_chacha20.cpp | 12 ++++---- src/test/fuzz/crypto_diff_fuzz_chacha20.cpp | 12 ++++---- 9 files changed, 46 insertions(+), 53 deletions(-) diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp index 8d1d1952bc..115cd064bd 100644 --- a/src/bench/chacha20.cpp +++ b/src/bench/chacha20.cpp @@ -14,7 +14,7 @@ static const uint64_t BUFFER_SIZE_LARGE = 1024*1024; static void CHACHA20(benchmark::Bench& bench, size_t buffersize) { std::vector key(32,0); - ChaCha20 ctx(key.data(), key.size()); + ChaCha20 ctx(key.data()); ctx.SetIV(0); ctx.Seek64(0); std::vector in(buffersize,0); diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp index 80db0a3a83..c5eee5ccfd 100644 --- a/src/crypto/chacha20.cpp +++ b/src/crypto/chacha20.cpp @@ -22,30 +22,21 @@ constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | ( #define REPEAT10(a) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while(0) static const unsigned char sigma[] = "expand 32-byte k"; -static const unsigned char tau[] = "expand 16-byte k"; -void ChaCha20Aligned::SetKey(const unsigned char* k, size_t keylen) +void ChaCha20Aligned::SetKey32(const unsigned char* k) { - const unsigned char *constants; - + input[0] = ReadLE32(sigma + 0); + input[1] = ReadLE32(sigma + 4); + input[2] = ReadLE32(sigma + 8); + input[3] = ReadLE32(sigma + 12); input[4] = ReadLE32(k + 0); input[5] = ReadLE32(k + 4); input[6] = ReadLE32(k + 8); input[7] = ReadLE32(k + 12); - if (keylen == 32) { /* recommended */ - k += 16; - constants = sigma; - } else { /* keylen == 16 */ - constants = tau; - } - input[8] = ReadLE32(k + 0); - input[9] = ReadLE32(k + 4); - input[10] = ReadLE32(k + 8); - input[11] = ReadLE32(k + 12); - input[0] = ReadLE32(constants + 0); - input[1] = ReadLE32(constants + 4); - input[2] = ReadLE32(constants + 8); - input[3] = ReadLE32(constants + 12); + input[8] = ReadLE32(k + 16); + input[9] = ReadLE32(k + 20); + input[10] = ReadLE32(k + 24); + input[11] = ReadLE32(k + 28); input[12] = 0; input[13] = 0; input[14] = 0; @@ -57,9 +48,9 @@ ChaCha20Aligned::ChaCha20Aligned() memset(input, 0, sizeof(input)); } -ChaCha20Aligned::ChaCha20Aligned(const unsigned char* k, size_t keylen) +ChaCha20Aligned::ChaCha20Aligned(const unsigned char* key32) { - SetKey(k, keylen); + SetKey32(key32); } void ChaCha20Aligned::SetIV(uint64_t iv) diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h index 715bf4e8e9..1119bf6323 100644 --- a/src/crypto/chacha20.h +++ b/src/crypto/chacha20.h @@ -20,11 +20,11 @@ private: public: ChaCha20Aligned(); - /** Initialize a cipher with specified key (see SetKey for arguments). */ - ChaCha20Aligned(const unsigned char* key, size_t keylen); + /** Initialize a cipher with specified 32-byte key. */ + ChaCha20Aligned(const unsigned char* key32); - /** set key with flexible keylength (16 or 32 bytes; 32 recommended). */ - void SetKey(const unsigned char* key, size_t keylen); + /** set 32-byte key. */ + void SetKey32(const unsigned char* key32); /** set the 64-bit nonce. */ void SetIV(uint64_t iv); @@ -52,13 +52,13 @@ private: public: ChaCha20() = default; - /** Initialize a cipher with specified key (see SetKey for arguments). */ - ChaCha20(const unsigned char* key, size_t keylen) : m_aligned(key, keylen) {} + /** Initialize a cipher with specified 32-byte key. */ + ChaCha20(const unsigned char* key32) : m_aligned(key32) {} - /** set key with flexible keylength (16 or 32 bytes; 32 recommended). */ - void SetKey(const unsigned char* key, size_t keylen) + /** set 32-byte key. */ + void SetKey32(const unsigned char* key32) { - m_aligned.SetKey(key, keylen); + m_aligned.SetKey32(key32); m_bufleft = 0; } diff --git a/src/crypto/chacha_poly_aead.cpp b/src/crypto/chacha_poly_aead.cpp index 5d135f8987..119ad6902f 100644 --- a/src/crypto/chacha_poly_aead.cpp +++ b/src/crypto/chacha_poly_aead.cpp @@ -36,8 +36,9 @@ ChaCha20Poly1305AEAD::ChaCha20Poly1305AEAD(const unsigned char* K_1, size_t K_1_ assert(K_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN); assert(K_2_len == CHACHA20_POLY1305_AEAD_KEY_LEN); - m_chacha_header.SetKey(K_1, CHACHA20_POLY1305_AEAD_KEY_LEN); - m_chacha_main.SetKey(K_2, CHACHA20_POLY1305_AEAD_KEY_LEN); + static_assert(CHACHA20_POLY1305_AEAD_KEY_LEN == 32); + m_chacha_header.SetKey32(K_1); + m_chacha_main.SetKey32(K_2); // set the cached sequence number to uint64 max which hints for an unset cache. // we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp index d5ae67f374..471ee6af97 100644 --- a/src/crypto/muhash.cpp +++ b/src/crypto/muhash.cpp @@ -299,7 +299,7 @@ Num3072 MuHash3072::ToNum3072(Span in) { unsigned char tmp[Num3072::BYTE_SIZE]; uint256 hashed_in{(HashWriter{} << in).GetSHA256()}; - ChaCha20Aligned(hashed_in.data(), hashed_in.size()).Keystream64(tmp, Num3072::BYTE_SIZE / 64); + ChaCha20Aligned(hashed_in.data()).Keystream64(tmp, Num3072::BYTE_SIZE / 64); Num3072 out{tmp}; return out; diff --git a/src/random.cpp b/src/random.cpp index 32deca9f70..5f50c001cd 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -599,7 +599,7 @@ uint256 GetRandHash() noexcept void FastRandomContext::RandomSeed() { uint256 seed = GetRandHash(); - rng.SetKey(seed.begin(), 32); + rng.SetKey32(seed.begin()); requires_seed = false; } @@ -623,7 +623,7 @@ std::vector FastRandomContext::randbytes(size_t len) FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0) { - rng.SetKey(seed.begin(), 32); + rng.SetKey32(seed.begin()); } bool Random_SanityCheck() @@ -678,7 +678,7 @@ FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_se return; } uint256 seed; - rng.SetKey(seed.begin(), 32); + rng.SetKey32(seed.begin()); } FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index ae2aa46d50..ddeaed761e 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -133,8 +133,9 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout) { std::vector key = ParseHex(hexkey); + assert(key.size() == 32); std::vector m = ParseHex(hex_message); - ChaCha20 rng(key.data(), key.size()); + ChaCha20 rng(key.data()); rng.SetIV(nonce); rng.Seek64(seek); std::vector out = ParseHex(hexout); @@ -460,7 +461,7 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) { BOOST_AUTO_TEST_CASE(chacha20_testvector) { - // Test vector from RFC 7539 + // Test vectors from RFC 7539 // test encryption TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756" @@ -503,12 +504,12 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector) BOOST_AUTO_TEST_CASE(chacha20_midblock) { auto key = ParseHex("0000000000000000000000000000000000000000000000000000000000000000"); - ChaCha20 c20{key.data(), 32}; + ChaCha20 c20{key.data()}; // get one block of keystream unsigned char block[64]; c20.Keystream(block, CHACHA20_ROUND_OUTPUT); unsigned char b1[5], b2[7], b3[52]; - c20 = ChaCha20{key.data(), 32}; + c20 = ChaCha20{key.data()}; c20.Keystream(b1, 5); c20.Keystream(b2, 7); c20.Keystream(b3, 52); @@ -635,7 +636,7 @@ static void TestChaCha20Poly1305AEAD(bool must_succeed, unsigned int expected_aa ChaCha20Poly1305AEAD aead(aead_K_1.data(), aead_K_1.size(), aead_K_2.data(), aead_K_2.size()); // create a chacha20 instance to compare against - ChaCha20 cmp_ctx(aead_K_1.data(), 32); + ChaCha20 cmp_ctx(aead_K_1.data()); // encipher bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true); diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp index f1e239bcc8..3fa445096a 100644 --- a/src/test/fuzz/crypto_chacha20.cpp +++ b/src/test/fuzz/crypto_chacha20.cpp @@ -17,15 +17,15 @@ FUZZ_TARGET(crypto_chacha20) ChaCha20 chacha20; if (fuzzed_data_provider.ConsumeBool()) { - const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange(16, 32)); - chacha20 = ChaCha20{key.data(), key.size()}; + const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); + chacha20 = ChaCha20{key.data()}; } LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { CallOneOf( fuzzed_data_provider, [&] { - const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange(16, 32)); - chacha20.SetKey(key.data(), key.size()); + std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); + chacha20.SetKey32(key.data()); }, [&] { chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral()); @@ -68,8 +68,8 @@ void ChaCha20SplitFuzz(FuzzedDataProvider& provider) uint64_t seek = provider.ConsumeIntegralInRange(0, ~(total_bytes >> 6)); // Initialize two ChaCha20 ciphers, with the same key/iv/position. - ChaCha20 crypt1(key, 32); - ChaCha20 crypt2(key, 32); + ChaCha20 crypt1(key); + ChaCha20 crypt2(key); crypt1.SetIV(iv); crypt1.Seek64(seek); crypt2.SetIV(iv); diff --git a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp index 1193a244db..9d650fc492 100644 --- a/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp +++ b/src/test/fuzz/crypto_diff_fuzz_chacha20.cpp @@ -277,10 +277,10 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20) } if (fuzzed_data_provider.ConsumeBool()) { - const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange(16, 32)); - chacha20 = ChaCha20{key.data(), key.size()}; + const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); + chacha20 = ChaCha20{key.data()}; ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); - // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does + // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey32() does uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; ECRYPT_ivsetup(&ctx, iv); } @@ -289,10 +289,10 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20) CallOneOf( fuzzed_data_provider, [&] { - const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange(16, 32)); - chacha20.SetKey(key.data(), key.size()); + const std::vector key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32); + chacha20.SetKey32(key.data()); ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); - // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey() does + // ECRYPT_keysetup() doesn't set the counter and nonce to 0 while SetKey32() does uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; ECRYPT_ivsetup(&ctx, iv); },