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:
parent
f21994a02e
commit
62ec713961
9 changed files with 46 additions and 53 deletions
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue