1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CRYPTO_CHACHA20_H
#define BITCOIN_CRYPTO_CHACHA20_H
#include <span.h>
#include <array>
#include <cstddef>
#include <cstdlib>
#include <stdint.h>
#include <utility>
// classes for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
// https://cr.yp.to/chacha/chacha-20080128.pdf.
//
// The 128-bit input is here implemented as a 96-bit nonce and a 32-bit block
// counter, as in RFC8439 Section 2.3. When the 32-bit block counter overflows
// the first 32-bit part of the nonce is automatically incremented, making it
// conceptually compatible with variants that use a 64/64 split instead.
/** ChaCha20 cipher that only operates on multiples of 64 bytes. */
class ChaCha20Aligned
{
private:
uint32_t input[12];
public:
ChaCha20Aligned();
/** Initialize a cipher with specified 32-byte key. */
ChaCha20Aligned(const unsigned char* key32);
/** Destructor to clean up private memory. */
~ChaCha20Aligned();
/** set 32-byte key. */
void SetKey32(const unsigned char* key32);
/** Type for 96-bit nonces used by the Set function below.
*
* The first field corresponds to the LE32-encoded first 4 bytes of the nonce, also referred
* to as the '32-bit fixed-common part' in Example 2.8.2 of RFC8439.
*
* The second field corresponds to the LE64-encoded last 8 bytes of the nonce.
*
*/
using Nonce96 = std::pair<uint32_t, uint64_t>;
/** Set the 96-bit nonce and 32-bit block counter.
*
* Block_counter selects a position to seek to (to byte 64*block_counter). After 256 GiB, the
* block counter overflows, and nonce.first is incremented.
*/
void Seek64(Nonce96 nonce, uint32_t block_counter);
/** outputs the keystream of size <64*blocks> into <c> */
void Keystream64(unsigned char* c, size_t blocks);
/** enciphers the message <input> of length <64*blocks> and write the enciphered representation into <output>
* Used for encryption and decryption (XOR)
*/
void Crypt64(const unsigned char* input, unsigned char* output, size_t blocks);
};
/** Unrestricted ChaCha20 cipher. */
class ChaCha20
{
private:
ChaCha20Aligned m_aligned;
unsigned char m_buffer[64] = {0};
unsigned m_bufleft{0};
public:
ChaCha20() = default;
/** Initialize a cipher with specified 32-byte key. */
ChaCha20(const unsigned char* key32) : m_aligned(key32) {}
/** Destructor to clean up private memory. */
~ChaCha20();
/** set 32-byte key. */
void SetKey32(const unsigned char* key32)
{
m_aligned.SetKey32(key32);
m_bufleft = 0;
}
/** 96-bit nonce type. */
using Nonce96 = ChaCha20Aligned::Nonce96;
/** Set the 96-bit nonce and 32-bit block counter. */
void Seek64(Nonce96 nonce, uint32_t block_counter)
{
m_aligned.Seek64(nonce, block_counter);
m_bufleft = 0;
}
/** outputs the keystream of size <bytes> into <c> */
void Keystream(unsigned char* c, size_t bytes);
/** enciphers the message <input> of length <bytes> and write the enciphered representation into <output>
* Used for encryption and decryption (XOR)
*/
void Crypt(const unsigned char* input, unsigned char* output, size_t bytes);
};
/** Forward-secure ChaCha20
*
* This implements a stream cipher that automatically transitions to a new stream with a new key
* and new nonce after a predefined number of encryptions or decryptions.
*
* See BIP324 for details.
*/
class FSChaCha20
{
private:
/** Internal stream cipher. */
ChaCha20 m_chacha20;
/** The number of encryptions/decryptions before a rekey happens. */
const uint32_t m_rekey_interval;
/** The number of encryptions/decryptions since the last rekey. */
uint32_t m_chunk_counter{0};
/** The number of rekey operations that have happened. */
uint64_t m_rekey_counter{0};
public:
/** Length of keys expected by the constructor. */
static constexpr unsigned KEYLEN = 32;
// No copy or move to protect the secret.
FSChaCha20(const FSChaCha20&) = delete;
FSChaCha20(FSChaCha20&&) = delete;
FSChaCha20& operator=(const FSChaCha20&) = delete;
FSChaCha20& operator=(FSChaCha20&&) = delete;
/** Construct an FSChaCha20 cipher that rekeys every rekey_interval Crypt() calls. */
FSChaCha20(Span<const std::byte> key, uint32_t rekey_interval) noexcept;
/** Encrypt or decrypt a chunk. */
void Crypt(Span<const std::byte> input, Span<std::byte> output) noexcept;
};
#endif // BITCOIN_CRYPTO_CHACHA20_H
|