0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

Only support 32-byte keys in ChaCha20{,Aligned}

This commit is contained in:
Pieter Wuille 2022-09-21 17:39:48 -04:00
parent f21994a02e
commit 62ec713961
9 changed files with 46 additions and 53 deletions

View file

@ -14,7 +14,7 @@ static const uint64_t BUFFER_SIZE_LARGE = 1024*1024;
static void CHACHA20(benchmark::Bench& bench, size_t buffersize) static void CHACHA20(benchmark::Bench& bench, size_t buffersize)
{ {
std::vector<uint8_t> key(32,0); std::vector<uint8_t> key(32,0);
ChaCha20 ctx(key.data(), key.size()); ChaCha20 ctx(key.data());
ctx.SetIV(0); ctx.SetIV(0);
ctx.Seek64(0); ctx.Seek64(0);
std::vector<uint8_t> in(buffersize,0); std::vector<uint8_t> in(buffersize,0);

View file

@ -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) #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 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[4] = ReadLE32(k + 0);
input[5] = ReadLE32(k + 4); input[5] = ReadLE32(k + 4);
input[6] = ReadLE32(k + 8); input[6] = ReadLE32(k + 8);
input[7] = ReadLE32(k + 12); input[7] = ReadLE32(k + 12);
if (keylen == 32) { /* recommended */ input[8] = ReadLE32(k + 16);
k += 16; input[9] = ReadLE32(k + 20);
constants = sigma; input[10] = ReadLE32(k + 24);
} else { /* keylen == 16 */ input[11] = ReadLE32(k + 28);
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[12] = 0; input[12] = 0;
input[13] = 0; input[13] = 0;
input[14] = 0; input[14] = 0;
@ -57,9 +48,9 @@ ChaCha20Aligned::ChaCha20Aligned()
memset(input, 0, sizeof(input)); 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) void ChaCha20Aligned::SetIV(uint64_t iv)

View file

@ -20,11 +20,11 @@ private:
public: public:
ChaCha20Aligned(); ChaCha20Aligned();
/** Initialize a cipher with specified key (see SetKey for arguments). */ /** Initialize a cipher with specified 32-byte key. */
ChaCha20Aligned(const unsigned char* key, size_t keylen); ChaCha20Aligned(const unsigned char* key32);
/** set key with flexible keylength (16 or 32 bytes; 32 recommended). */ /** set 32-byte key. */
void SetKey(const unsigned char* key, size_t keylen); void SetKey32(const unsigned char* key32);
/** set the 64-bit nonce. */ /** set the 64-bit nonce. */
void SetIV(uint64_t iv); void SetIV(uint64_t iv);
@ -52,13 +52,13 @@ private:
public: public:
ChaCha20() = default; ChaCha20() = default;
/** Initialize a cipher with specified key (see SetKey for arguments). */ /** Initialize a cipher with specified 32-byte key. */
ChaCha20(const unsigned char* key, size_t keylen) : m_aligned(key, keylen) {} ChaCha20(const unsigned char* key32) : m_aligned(key32) {}
/** set key with flexible keylength (16 or 32 bytes; 32 recommended). */ /** set 32-byte key. */
void SetKey(const unsigned char* key, size_t keylen) void SetKey32(const unsigned char* key32)
{ {
m_aligned.SetKey(key, keylen); m_aligned.SetKey32(key32);
m_bufleft = 0; m_bufleft = 0;
} }

View file

@ -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_1_len == CHACHA20_POLY1305_AEAD_KEY_LEN);
assert(K_2_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); static_assert(CHACHA20_POLY1305_AEAD_KEY_LEN == 32);
m_chacha_main.SetKey(K_2, CHACHA20_POLY1305_AEAD_KEY_LEN); 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. // 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 // we can't hit uint64 max since the rekey rule (which resets the sequence number) is 1GB

View file

@ -299,7 +299,7 @@ Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
unsigned char tmp[Num3072::BYTE_SIZE]; unsigned char tmp[Num3072::BYTE_SIZE];
uint256 hashed_in{(HashWriter{} << in).GetSHA256()}; 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}; Num3072 out{tmp};
return out; return out;

View file

@ -599,7 +599,7 @@ uint256 GetRandHash() noexcept
void FastRandomContext::RandomSeed() void FastRandomContext::RandomSeed()
{ {
uint256 seed = GetRandHash(); uint256 seed = GetRandHash();
rng.SetKey(seed.begin(), 32); rng.SetKey32(seed.begin());
requires_seed = false; requires_seed = false;
} }
@ -623,7 +623,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0) FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bitbuf_size(0)
{ {
rng.SetKey(seed.begin(), 32); rng.SetKey32(seed.begin());
} }
bool Random_SanityCheck() bool Random_SanityCheck()
@ -678,7 +678,7 @@ FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_se
return; return;
} }
uint256 seed; uint256 seed;
rng.SetKey(seed.begin(), 32); rng.SetKey32(seed.begin());
} }
FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept

View file

@ -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) static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
{ {
std::vector<unsigned char> key = ParseHex(hexkey); std::vector<unsigned char> key = ParseHex(hexkey);
assert(key.size() == 32);
std::vector<unsigned char> m = ParseHex(hex_message); std::vector<unsigned char> m = ParseHex(hex_message);
ChaCha20 rng(key.data(), key.size()); ChaCha20 rng(key.data());
rng.SetIV(nonce); rng.SetIV(nonce);
rng.Seek64(seek); rng.Seek64(seek);
std::vector<unsigned char> out = ParseHex(hexout); std::vector<unsigned char> out = ParseHex(hexout);
@ -460,7 +461,7 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
BOOST_AUTO_TEST_CASE(chacha20_testvector) BOOST_AUTO_TEST_CASE(chacha20_testvector)
{ {
// Test vector from RFC 7539 // Test vectors from RFC 7539
// test encryption // test encryption
TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756" TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756"
@ -503,12 +504,12 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
BOOST_AUTO_TEST_CASE(chacha20_midblock) BOOST_AUTO_TEST_CASE(chacha20_midblock)
{ {
auto key = ParseHex("0000000000000000000000000000000000000000000000000000000000000000"); auto key = ParseHex("0000000000000000000000000000000000000000000000000000000000000000");
ChaCha20 c20{key.data(), 32}; ChaCha20 c20{key.data()};
// get one block of keystream // get one block of keystream
unsigned char block[64]; unsigned char block[64];
c20.Keystream(block, CHACHA20_ROUND_OUTPUT); c20.Keystream(block, CHACHA20_ROUND_OUTPUT);
unsigned char b1[5], b2[7], b3[52]; unsigned char b1[5], b2[7], b3[52];
c20 = ChaCha20{key.data(), 32}; c20 = ChaCha20{key.data()};
c20.Keystream(b1, 5); c20.Keystream(b1, 5);
c20.Keystream(b2, 7); c20.Keystream(b2, 7);
c20.Keystream(b3, 52); 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()); 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 // create a chacha20 instance to compare against
ChaCha20 cmp_ctx(aead_K_1.data(), 32); ChaCha20 cmp_ctx(aead_K_1.data());
// encipher // encipher
bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true); bool res = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, ciphertext_buf.data(), ciphertext_buf.size(), plaintext_buf.data(), plaintext_buf.size(), true);

View file

@ -17,15 +17,15 @@ FUZZ_TARGET(crypto_chacha20)
ChaCha20 chacha20; ChaCha20 chacha20;
if (fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.ConsumeBool()) {
const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
chacha20 = ChaCha20{key.data(), key.size()}; chacha20 = ChaCha20{key.data()};
} }
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) { LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf( CallOneOf(
fuzzed_data_provider, fuzzed_data_provider,
[&] { [&] {
const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
chacha20.SetKey(key.data(), key.size()); chacha20.SetKey32(key.data());
}, },
[&] { [&] {
chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
@ -68,8 +68,8 @@ void ChaCha20SplitFuzz(FuzzedDataProvider& provider)
uint64_t seek = provider.ConsumeIntegralInRange<uint64_t>(0, ~(total_bytes >> 6)); uint64_t seek = provider.ConsumeIntegralInRange<uint64_t>(0, ~(total_bytes >> 6));
// Initialize two ChaCha20 ciphers, with the same key/iv/position. // Initialize two ChaCha20 ciphers, with the same key/iv/position.
ChaCha20 crypt1(key, 32); ChaCha20 crypt1(key);
ChaCha20 crypt2(key, 32); ChaCha20 crypt2(key);
crypt1.SetIV(iv); crypt1.SetIV(iv);
crypt1.Seek64(seek); crypt1.Seek64(seek);
crypt2.SetIV(iv); crypt2.SetIV(iv);

View file

@ -277,10 +277,10 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20)
} }
if (fuzzed_data_provider.ConsumeBool()) { if (fuzzed_data_provider.ConsumeBool()) {
const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
chacha20 = ChaCha20{key.data(), key.size()}; chacha20 = ChaCha20{key.data()};
ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); 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}; uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
ECRYPT_ivsetup(&ctx, iv); ECRYPT_ivsetup(&ctx, iv);
} }
@ -289,10 +289,10 @@ FUZZ_TARGET(crypto_diff_fuzz_chacha20)
CallOneOf( CallOneOf(
fuzzed_data_provider, fuzzed_data_provider,
[&] { [&] {
const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32)); const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, 32);
chacha20.SetKey(key.data(), key.size()); chacha20.SetKey32(key.data());
ECRYPT_keysetup(&ctx, key.data(), key.size() * 8, 0); 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}; uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0};
ECRYPT_ivsetup(&ctx, iv); ECRYPT_ivsetup(&ctx, iv);
}, },