Crypto++  8.0
Free C++ class library of cryptographic schemes
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 
9 NAMESPACE_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.
19 void 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 
37 void 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 
54 void 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 
61 size_t ChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len)
62 {
63  AccessMAC().Update(data, len);
64  return 0;
65 }
66 
67 void 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 
75 void 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 
83 void 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 
93 void 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 
101 bool 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.
117 void 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 
135 void 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 
152 void 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 
159 size_t XChaCha20Poly1305_Base::AuthenticateBlocks(const byte *data, size_t len)
160 {
161  AccessMAC().Update(data, len);
162  return 0;
163 }
164 
165 void 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 
173 void 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 
181 void 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 
191 void 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 
199 bool 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 
207 NAMESPACE_END
Used to pass byte array input as part of a NameValuePairs object.
Definition: algparam.h:20
Classes for working with NameValuePairs.
ChaCha20/Poly1305-TLS AEAD scheme.
Utility functions for the Crypto++ library.
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
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:811
void PutWord(bool assumeAligned, ByteOrder order, byte *block, T value, const byte *xorBlock=NULL)
Access a block of memory.
Definition: misc.h:2396
void Resynchronize(const byte *iv, int length=-1)
Resynchronize with an IV.
Definition: authenc.cpp:67
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
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
void ProcessString(byte *inoutString, size_t length)
Encrypt or decrypt a string of bytes.
Definition: cryptlib.h:1032
Combines two sets of NameValuePairs.
Definition: algparam.h:124
virtual bool TruncatedVerify(const byte *digest, size_t digestLength)
Verifies the hash of the current message.
Definition: cryptlib.cpp:406
SecBlock<byte> typedef.
Definition: secblock.h:1058
byte order is little-endian
Definition: cryptlib.h:145
AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed=true)
Create an object that implements NameValuePairs.
Definition: algparam.h:502
XChaCha20Poly1305 cipher base implementation.
Definition: chachapoly.h:176
void Assign(const T *ptr, size_type len)
Set contents and size from an array.
Definition: secblock.h:841
Precompiled header file.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69
const char * IV()
ConstByteArrayParameter, also accepts const byte * for backwards compatibility.
Definition: argnames.h:21
void Update(const byte *input, size_t length)
Updates a hash with additional input.
Definition: authenc.cpp:80
An object that implements NameValuePairs.
Definition: algparam.h:419
ChaCha20Poly1305 cipher base implementation.
Definition: chachapoly.h:29
Crypto++ library namespace.
void TruncatedFinal(byte *mac, size_t macSize)
Computes the hash of the current message.
Definition: authenc.cpp:141
virtual void Update(const byte *input, size_t length)=0
Updates a hash with additional input.
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
Interface for retrieving values given their names.
Definition: cryptlib.h:293