aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/chacha20.cpp
diff options
context:
space:
mode:
authorPieter Wuille <pieter@wuille.net>2023-06-28 18:20:30 -0400
committerPieter Wuille <pieter@wuille.net>2023-07-26 16:55:05 -0400
commit0fee267792eb8cbdd48ad78f1712420b5d8d905b (patch)
treebf815576f3aedf2b0ab5f3a98b6fd577110f2bc0 /src/crypto/chacha20.cpp
parent9ff0768bdcca06836ccc673eacfa648e801930cb (diff)
downloadbitcoin-0fee267792eb8cbdd48ad78f1712420b5d8d905b.tar.xz
crypto: add FSChaCha20, a rekeying wrapper around ChaCha20
This adds the FSChaCha20 stream cipher as specified in BIP324, a wrapper around the ChaCha20 stream cipher (specified in RFC8439 section 2.4) which automatically rekeys every N messages, and manages the nonces used for encryption. Co-authored-by: dhruv <856960+dhruv@users.noreply.github.com>
Diffstat (limited to 'src/crypto/chacha20.cpp')
-rw-r--r--src/crypto/chacha20.cpp41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
index fafd783ab1..469b280494 100644
--- a/src/crypto/chacha20.cpp
+++ b/src/crypto/chacha20.cpp
@@ -7,6 +7,7 @@
#include <crypto/common.h>
#include <crypto/chacha20.h>
+#include <support/cleanse.h>
#include <algorithm>
#include <string.h>
@@ -42,6 +43,11 @@ ChaCha20Aligned::ChaCha20Aligned()
memset(input, 0, sizeof(input));
}
+ChaCha20Aligned::~ChaCha20Aligned()
+{
+ memory_cleanse(input, sizeof(input));
+}
+
ChaCha20Aligned::ChaCha20Aligned(const unsigned char* key32)
{
SetKey32(key32);
@@ -318,3 +324,38 @@ void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
m_bufleft = 64 - bytes;
}
}
+
+ChaCha20::~ChaCha20()
+{
+ memory_cleanse(m_buffer, sizeof(m_buffer));
+}
+
+FSChaCha20::FSChaCha20(Span<const std::byte> key, uint32_t rekey_interval) noexcept :
+ m_chacha20(UCharCast(key.data())), m_rekey_interval(rekey_interval)
+{
+ assert(key.size() == KEYLEN);
+}
+
+void FSChaCha20::Crypt(Span<const std::byte> input, Span<std::byte> output) noexcept
+{
+ assert(input.size() == output.size());
+
+ // Invoke internal stream cipher for actual encryption/decryption.
+ m_chacha20.Crypt(UCharCast(input.data()), UCharCast(output.data()), input.size());
+
+ // Rekey after m_rekey_interval encryptions/decryptions.
+ if (++m_chunk_counter == m_rekey_interval) {
+ // Get new key from the stream cipher.
+ std::byte new_key[KEYLEN];
+ m_chacha20.Keystream(UCharCast(new_key), sizeof(new_key));
+ // Update its key.
+ m_chacha20.SetKey32(UCharCast(new_key));
+ // Wipe the key (a copy remains inside m_chacha20, where it'll be wiped on the next rekey
+ // or on destruction).
+ memory_cleanse(new_key, sizeof(new_key));
+ // Set the nonce for the new section of output.
+ m_chacha20.Seek64({0, ++m_rekey_counter}, 0);
+ // Reset the chunk counter.
+ m_chunk_counter = 0;
+ }
+}