Bitcoin ABC  0.29.2
P2P Digital Currency
chacha_poly_aead.h
Go to the documentation of this file.
1 // Copyright (c) 2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
6 #define BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
7 
8 #include <crypto/chacha20.h>
9 
10 #include <cmath>
11 
12 static constexpr int CHACHA20_POLY1305_AEAD_KEY_LEN = 32;
13 static constexpr int CHACHA20_POLY1305_AEAD_AAD_LEN = 3; /* 3 bytes length */
14 static constexpr int CHACHA20_ROUND_OUTPUT = 64; /* 64 bytes per round */
15 static constexpr int AAD_PACKAGES_PER_ROUND = 21; /* 64 / 3 round down*/
16 
17 /* A AEAD class for ChaCha20-Poly1305@bitcoin.
18  *
19  * ChaCha20 is a stream cipher designed by Daniel Bernstein and described in
20  * <ref>[http://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates
21  * by permuting 128 fixed bits, 128 or 256 bits of key, a 64 bit nonce and a 64
22  * bit counter into 64 bytes of output. This output is used as a keystream, with
23  * any unused bytes simply discarded.
24  *
25  * Poly1305 <ref>[http://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>,
26  * also by Daniel Bernstein, is a one-time Carter-Wegman MAC that computes a 128
27  * bit integrity tag given a message and a single-use 256 bit secret key.
28  *
29  * The chacha20-poly1305@bitcoin combines these two primitives into an
30  * authenticated encryption mode. The construction used is based on that
31  * proposed for TLS by Adam Langley in
32  * <ref>[http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03 "ChaCha20
33  * and Poly1305 based Cipher Suites for TLS", Adam Langley]</ref>, but differs
34  * in the layout of data passed to the MAC and in the addition of encryption of
35  * the packet lengths.
36  *
37  * ==== Detailed Construction ====
38  *
39  * The chacha20-poly1305@bitcoin cipher requires two 256 bits of key material as
40  * output from the key exchange. Each key (K_1 and K_2) are used by two separate
41  * instances of chacha20.
42  *
43  * The instance keyed by K_1 is a stream cipher that is used only to encrypt the
44  * 3 byte packet length field and has its own sequence number. The second
45  * instance, keyed by K_2, is used in conjunction with poly1305 to build an AEAD
46  * (Authenticated Encryption with Associated Data) that is used to encrypt and
47  * authenticate the entire packet.
48  *
49  * Two separate cipher instances are used here so as to keep the packet lengths
50  * confidential but not create an oracle for the packet payload cipher by
51  * decrypting and using the packet length prior to checking the MAC. By using an
52  * independently-keyed cipher instance to encrypt the length, an active attacker
53  * seeking to exploit the packet input handling as a decryption oracle can learn
54  * nothing about the payload contents or its MAC (assuming key derivation,
55  * ChaCha20 and Poly1305 are secure).
56  *
57  * The AEAD is constructed as follows: for each packet, generate a Poly1305 key
58  * by taking the first 256 bits of ChaCha20 stream output generated using K_2,
59  * an IV consisting of the packet sequence number encoded as an LE uint64 and a
60  * ChaCha20 block counter of zero. The K_2 ChaCha20 block counter is then set to
61  * the little-endian encoding of 1 (i.e. {1, 0, 0, 0, 0, 0, 0, 0}) and this
62  * instance is used for encryption of the packet payload.
63  *
64  * ==== Packet Handling ====
65  *
66  * When receiving a packet, the length must be decrypted first. When 3 bytes of
67  * ciphertext length have been received, they may be decrypted.
68  *
69  * A ChaCha20 round always calculates 64bytes which is sufficient to crypt 21
70  * times a 3 bytes length field (21*3 = 63). The length field sequence number
71  * can thus be used 21 times (keystream caching).
72  *
73  * The length field must be enc-/decrypted with the ChaCha20 keystream keyed
74  * with K_1 defined by block counter 0, the length field sequence number in
75  * little endian and a keystream position from 0 to 60.
76  *
77  * Once the entire packet has been received, the MAC MUST be checked before
78  * decryption. A per-packet Poly1305 key is generated as described above and the
79  * MAC tag calculated using Poly1305 with this key over the ciphertext of the
80  * packet length and the payload together. The calculated MAC is then compared
81  * in constant time with the one appended to the packet and the packet decrypted
82  * using ChaCha20 as described above (with K_2, the packet sequence number as
83  * nonce and a starting block counter of 1).
84  *
85  * Detection of an invalid MAC MUST lead to immediate connection termination.
86  *
87  * To send a packet, first encode the 3 byte length and encrypt it using K_1 as
88  * described above. Encrypt the packet payload (using K_2) and append it to the
89  * encrypted length. Finally, calculate a MAC tag and append it.
90  *
91  * The initiating peer MUST use <code>K_1_A, K_2_A</code> to encrypt messages on
92  * the send channel, <code>K_1_B, K_2_B</code> MUST be used to decrypt messages
93  * on the receive channel.
94  *
95  * The responding peer MUST use <code>K_1_A, K_2_A</code> to decrypt messages on
96  * the receive channel, <code>K_1_B, K_2_B</code> MUST be used to encrypt
97  * messages on the send channel.
98  *
99  * Optimized implementations of ChaCha20-Poly1305@bitcoin are relatively fast in
100  * general, therefore it is very likely that encrypted messages require not more
101  * CPU cycles per bytes then the current unencrypted p2p message format
102  * (ChaCha20/Poly1305 versus double SHA256).
103  *
104  * The initial packet sequence numbers are 0.
105  *
106  * K_2 ChaCha20 cipher instance (payload) must never reuse a {key, nonce} for
107  * encryption nor may it be used to encrypt more than 2^70 bytes under the same
108  * {key, nonce}.
109  *
110  * K_1 ChaCha20 cipher instance (length field/AAD) must never reuse a {key,
111  * nonce, position-in-keystream} for encryption nor may it be used to encrypt
112  * more than 2^70 bytes under the same {key, nonce}.
113  *
114  * We use message sequence numbers for both communication directions.
115  */
116 
118 private:
119  // payload and poly1305 key-derivation cipher instance
121  // AAD cipher instance (encrypted length)
123  // aad keystream cache
125  // aad keystream cache hint
127 
128 public:
129  ChaCha20Poly1305AEAD(const uint8_t *K_1, size_t K_1_len, const uint8_t *K_2,
130  size_t K_2_len);
131 
132  explicit ChaCha20Poly1305AEAD(const ChaCha20Poly1305AEAD &) = delete;
133 
149  bool Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos,
150  uint8_t *dest, size_t dest_len, const uint8_t *src,
151  size_t src_len, bool is_encrypt);
152 
154  bool GetLength(uint32_t *len24_out, uint64_t seqnr_aad, int aad_pos,
155  const uint8_t *ciphertext);
156 };
157 
158 #endif // BITCOIN_CRYPTO_CHACHA_POLY_AEAD_H
static constexpr int CHACHA20_POLY1305_AEAD_KEY_LEN
static constexpr int AAD_PACKAGES_PER_ROUND
static constexpr int CHACHA20_POLY1305_AEAD_AAD_LEN
static constexpr int CHACHA20_ROUND_OUTPUT
A class for ChaCha20 256-bit stream cipher developed by Daniel J.
Definition: chacha20.h:15
bool Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int aad_pos, uint8_t *dest, size_t dest_len, const uint8_t *src, size_t src_len, bool is_encrypt)
Encrypts/decrypts a packet.
bool GetLength(uint32_t *len24_out, uint64_t seqnr_aad, int aad_pos, const uint8_t *ciphertext)
decrypts the 3 bytes AAD data and decodes it into a uint32_t field
uint8_t m_aad_keystream_buffer[CHACHA20_ROUND_OUTPUT]
ChaCha20Poly1305AEAD(const uint8_t *K_1, size_t K_1_len, const uint8_t *K_2, size_t K_2_len)
ChaCha20Poly1305AEAD(const ChaCha20Poly1305AEAD &)=delete