Crypto++ 8.2
Free C&
chachapoly.cpp
1// chachapoly.cpp - written and placed in the public domain by Jeffrey Walton
2// RFC 8439, Section 2.8, AEAD Construction, http://tools.ietf.org/html/rfc8439
3
4#include "pch.h"
5#include "chachapoly.h"
6#include "algparam.h"
7#include "misc.h"
8
9NAMESPACE_BEGIN(CryptoPP)
10
11////////////////////////////// IETF ChaChaTLS //////////////////////////////
12
13// RekeyCipherAndMac is heavier-weight than we like. The Authenc framework was
14// predicated on BlockCiphers, where the key and key schedule could be
15// calculated independent of the IV being used. However, the ChaCha and
16// ChaCha20Poly1305 construction combines key setup and IV. That is, both are
17// needed to key or rekey the cipher. Even a simple Resync() requires us to
18// regenerate the initial state for both ChaCha20 and Poly1305.
19void ChaCha20Poly1305_Base::RekeyCipherAndMac(const byte *userKey, size_t keylength, const NameValuePairs &params)
20{
21 // Derive MAC key
22 AlgorithmParameters block0 = MakeParameters("InitialBlock", (word64)0, true);
23 AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block0));
24
25 // Only the first 256-bits are used to key the MAC
26 SecByteBlock derived(NULLPTR, 32);
27 AccessSymmetricCipher().ProcessString(derived, derived.size());
28
29 // Key the Poly1305 MAC
30 AccessMAC().SetKey(derived, derived.size(), params);
31
32 // Key the ChaCha20 cipher
33 AlgorithmParameters block1 = MakeParameters("InitialBlock", (word64)1, true);
34 AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block1));
35}
36
37void ChaCha20Poly1305_Base::SetKeyWithoutResync(const byte *userKey, size_t userKeyLength, const NameValuePairs &params)
38{
39 CRYPTOPP_ASSERT(userKey && userKeyLength == 32);
40 m_userKey.Assign(userKey, userKeyLength);
41
42 // ChaCha/Poly1305 initial state depends on both the key and IV. The
43 // IV may or may not be present during the call to SetKeyWithoutResync.
44 // If the IV is present, the framework will call SetKeyWithoutResync
45 // followed by Resynchronize which calls Resync. In this case we defer
46 // calculating the initial state until the call to Resynchronize.
47 // If the IV is not present, it avoids calling ChaCha's SetKey without
48 // an IV, which results in an exception. In this case the user will need
49 // to call Resynchronize to key ChaCha and Poly1305.
50 // RekeyCipherAndMac(userKey, userKeyLength, params);
51 CRYPTOPP_UNUSED(params);
52}
53
54void ChaCha20Poly1305_Base::Resync(const byte *iv, size_t len)
55{
56 CRYPTOPP_ASSERT(iv && len == 12);
57 RekeyCipherAndMac(m_userKey, m_userKey.SizeInBytes(),
59}
60
61size_t ChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len)
62{
63 AccessMAC().Update(data, len);
64 return 0;
65}
66
67void ChaCha20Poly1305_Base::AuthenticateLastHeaderBlock()
68{
69 // Pad to a multiple of 16 or 0
70 const byte zero[16] = {0};
71 size_t pad = (16 - (m_totalHeaderLength % 16)) % 16;
72 AccessMAC().Update(zero, pad);
73}
74
75void ChaCha20Poly1305_Base::AuthenticateLastConfidentialBlock()
76{
77 // Pad to a multiple of 16 or 0
78 const byte zero[16] = {0};
79 size_t pad = (16 - (m_totalMessageLength % 16)) % 16;
80 AccessMAC().Update(zero, pad);
81}
82
83void ChaCha20Poly1305_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize)
84{
85 CRYPTOPP_ALIGN_DATA(8) byte length[2*sizeof(word64)];
86 PutWord(true, LITTLE_ENDIAN_ORDER, length+0, m_totalHeaderLength);
87 PutWord(true, LITTLE_ENDIAN_ORDER, length+8, m_totalMessageLength);
88 AccessMAC().Update(length, sizeof(length));
89 AccessMAC().TruncatedFinal(mac, macSize);
90 m_state = State_KeySet;
91}
92
93void ChaCha20Poly1305_Base::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength)
94{
95 Resynchronize(iv, ivLength);
96 Update(aad, aadLength);
97 ProcessString(ciphertext, message, messageLength);
98 TruncatedFinal(mac, macSize);
99}
100
101bool ChaCha20Poly1305_Base::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength)
102{
103 Resynchronize(iv, ivLength);
104 Update(aad, aadLength);
105 ProcessString(message, ciphertext, ciphertextLength);
106 return TruncatedVerify(mac, macLength);
107}
108
109////////////////////////////// IETF XChaCha20 draft //////////////////////////////
110
111// RekeyCipherAndMac is heavier-weight than we like. The Authenc framework was
112// predicated on BlockCiphers, where the key and key schedule could be
113// calculated independent of the IV being used. However, the ChaCha and
114// ChaCha20Poly1305 construction combines key setup and IV. That is, both are
115// needed to key or rekey the cipher. Even a simple Resync() requires us to
116// regenerate the initial state for both ChaCha20 and Poly1305.
117void XChaCha20Poly1305_Base::RekeyCipherAndMac(const byte *userKey, size_t keylength, const NameValuePairs &params)
118{
119 // Derive MAC key
120 AlgorithmParameters block0 = MakeParameters("InitialBlock", (word64)0, true);
121 AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block0));
122
123 // Only the first 256-bits are used to key the MAC
124 SecByteBlock derived(NULLPTR, 32);
125 AccessSymmetricCipher().ProcessString(derived, derived.size());
126
127 // Key the Poly1305 MAC
128 AccessMAC().SetKey(derived, derived.size(), params);
129
130 // Key the ChaCha20 cipher
131 AlgorithmParameters block1 = MakeParameters("InitialBlock", (word64)1, true);
132 AccessSymmetricCipher().SetKey(userKey, keylength, CombinedNameValuePairs(params, block1));
133}
134
135void XChaCha20Poly1305_Base::SetKeyWithoutResync(const byte *userKey, size_t userKeyLength, const NameValuePairs &params)
136{
137 CRYPTOPP_ASSERT(userKey && userKeyLength == 32);
138 m_userKey.Assign(userKey, userKeyLength);
139
140 // XChaCha20/Poly1305 initial state depends on both the key and IV. The
141 // IV may or may not be present during the call to SetKeyWithoutResync.
142 // If the IV is present, the framework will call SetKeyWithoutResync
143 // followed by Resynchronize which calls Resync. In this case we defer
144 // calculating the initial state until the call to Resynchronize.
145 // If the IV is not present, it avoids calling ChaCha's SetKey without
146 // an IV, which results in an exception. In this case the user will need
147 // to call Resynchronize to key ChaCha and Poly1305.
148 // RekeyCipherAndMac(userKey, userKeyLength, params);
149 CRYPTOPP_UNUSED(params);
150}
151
152void XChaCha20Poly1305_Base::Resync(const byte *iv, size_t len)
153{
154 CRYPTOPP_ASSERT(iv && len == 24);
155 RekeyCipherAndMac(m_userKey, m_userKey.SizeInBytes(),
157}
158
159size_t XChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len)
160{
161 AccessMAC().Update(data, len);
162 return 0;
163}
164
165void XChaCha20Poly1305_Base::AuthenticateLastHeaderBlock()
166{
167 // Pad to a multiple of 16 or 0
168 const byte zero[16] = {0};
169 size_t pad = (16 - (m_totalHeaderLength % 16)) % 16;
170 AccessMAC().Update(zero, pad);
171}
172
173void XChaCha20Poly1305_Base::AuthenticateLastConfidentialBlock()
174{
175 // Pad to a multiple of 16 or 0
176 const byte zero[16] = {0};
177 size_t pad = (16 - (m_totalMessageLength % 16)) % 16;
178 AccessMAC().Update(zero, pad);
179}
180
181void XChaCha20Poly1305_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize)
182{
183 CRYPTOPP_ALIGN_DATA(8) byte length[2*sizeof(word64)];
184 PutWord(true, LITTLE_ENDIAN_ORDER, length+0, m_totalHeaderLength);
185 PutWord(true, LITTLE_ENDIAN_ORDER, length+8, m_totalMessageLength);
186 AccessMAC().Update(length, sizeof(length));
187 AccessMAC().TruncatedFinal(mac, macSize);
188 m_state = State_KeySet;
189}
190
191void XChaCha20Poly1305_Base::EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength)
192{
193 Resynchronize(iv, ivLength);
194 Update(aad, aadLength);
195 ProcessString(ciphertext, message, messageLength);
196 TruncatedFinal(mac, macSize);
197}
198
199bool XChaCha20Poly1305_Base::DecryptAndVerify(byte *message, const byte *mac, size_t macLength, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength)
200{
201 Resynchronize(iv, ivLength);
202 Update(aad, aadLength);
203 ProcessString(message, ciphertext, ciphertextLength);
204 return TruncatedVerify(mac, macLength);
205}
206
207NAMESPACE_END
Classes for working with NameValuePairs.
AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed=true)
Create an object that implements NameValuePairs.
Definition: algparam.h:502
ChaCha20/Poly1305-TLS AEAD scheme.
An object that implements NameValuePairs.
Definition: algparam.h:420
void Resynchronize(const byte *iv, int length=-1)
Resynchronize with an IV.
Definition: authenc.cpp:67
void Update(const byte *input, size_t length)
Updates a hash with additional input.
Definition: authenc.cpp:80
void TruncatedFinal(byte *mac, size_t macSize)
Computes the hash of the current message.
Definition: authenc.cpp:141
ChaCha20Poly1305 cipher base implementation.
Definition: chachapoly.h:30
virtual void EncryptAndAuthenticate(byte *ciphertext, byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *message, size_t messageLength)
Encrypts and calculates a MAC in one call.
Definition: chachapoly.cpp:93
virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength)
Decrypts and verifies a MAC in one call.
Definition: chachapoly.cpp:101
Combines two sets of NameValuePairs.
Definition: algparam.h:125
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:21
virtual bool TruncatedVerify(const byte *digest, size_t digestLength)
Verifies the hash of the current message.
Definition: cryptlib.cpp:406
virtual void Update(const byte *input, size_t length)=0
Updates a hash with additional input.
Interface for retrieving values given their names.
Definition: cryptlib.h:294
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:811
void Assign(const T *ptr, size_type len)
Set contents and size from an array.
Definition: secblock.h:841
SecBlock<byte> typedef.
Definition: secblock.h:1058
virtual void SetKey(const byte *key, size_t length, const NameValuePairs &params=g_nullNameValuePairs)
Sets or reset the key of this object.
Definition: cryptlib.cpp:58
void ProcessString(byte *inoutString, size_t length)
Encrypt or decrypt a string of bytes.
Definition: cryptlib.h:1032
XChaCha20Poly1305 cipher base implementation.
Definition: chachapoly.h:177
virtual bool DecryptAndVerify(byte *message, const byte *mac, size_t macSize, const byte *iv, int ivLength, const byte *aad, size_t aadLength, const byte *ciphertext, size_t ciphertextLength)
Decrypts and verifies a MAC in one call.
Definition: chachapoly.cpp:199
@ LITTLE_ENDIAN_ORDER
byte order is little-endian
Definition: cryptlib.h:145
Utility functions for the Crypto++ library.
void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock=NULL)
Access a block of memory.
Definition: misc.h:2428
Crypto++ library namespace.
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:21
Precompiled header file.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69