chacha20_poly1305.c
Go to the documentation of this file.
1 /**
2  * @file chacha20_poly1305.c
3  * @brief ChaCha20Poly1305 AEAD
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "cipher/chacha.h"
37 #include "mac/poly1305.h"
38 #include "aead/chacha20_poly1305.h"
39 #include "debug.h"
40 
41 //Check crypto library configuration
42 #if (CHACHA20_POLY1305_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief Authenticated encryption using ChaCha20Poly1305
47  * @param[in] k key
48  * @param[in] kLen Length of the key
49  * @param[in] n Nonce
50  * @param[in] nLen Length of the nonce
51  * @param[in] a Additional authenticated data
52  * @param[in] aLen Length of the additional data
53  * @param[in] p Plaintext to be encrypted
54  * @param[out] c Ciphertext resulting from the encryption
55  * @param[in] length Total number of data bytes to be encrypted
56  * @param[out] t MAC resulting from the encryption process
57  * @param[in] tLen Length of the MAC
58  * @return Error code
59  **/
60 
61 error_t chacha20Poly1305Encrypt(const uint8_t *k, size_t kLen,
62  const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen,
63  const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
64 {
65  error_t error;
66  size_t paddingLen;
67  ChachaContext chachaContext;
68  Poly1305Context poly1305Context;
69  uint8_t temp[32];
70 
71  //Check the length of the message-authentication code
72  if(tLen != 16)
73  return ERROR_INVALID_LENGTH;
74 
75  //Initialize ChaCha20 context
76  error = chachaInit(&chachaContext, 20, k, kLen, n, nLen);
77  //Any error to report?
78  if(error)
79  return error;
80 
81  //First, a Poly1305 one-time key is generated from the 256-bit key
82  //and nonce
83  chachaCipher(&chachaContext, NULL, temp, 32);
84 
85  //The other 256 bits of the ChaCha20 block are discarded
86  chachaCipher(&chachaContext, NULL, NULL, 32);
87 
88  //Next, the ChaCha20 encryption function is called to encrypt the
89  //plaintext, using the same key and nonce
90  chachaCipher(&chachaContext, p, c, length);
91 
92  //Initialize the Poly1305 function with the key calculated above
93  poly1305Init(&poly1305Context, temp);
94 
95  //Compute MAC over the AAD
96  poly1305Update(&poly1305Context, a, aLen);
97 
98  //If the length of the AAD is not an integral multiple of 16 bytes,
99  //then padding is required
100  if((aLen % 16) != 0)
101  {
102  //Compute the number of padding bytes
103  paddingLen = 16 - (aLen % 16);
104 
105  //The padding is up to 15 zero bytes, and it brings the total length
106  //so far to an integral multiple of 16
107  osMemset(temp, 0, paddingLen);
108 
109  //Compute MAC over the padding
110  poly1305Update(&poly1305Context, temp, paddingLen);
111  }
112 
113  //Compute MAC over the ciphertext
114  poly1305Update(&poly1305Context, c, length);
115 
116  //If the length of the ciphertext is not an integral multiple of 16 bytes,
117  //then padding is required
118  if((length % 16) != 0)
119  {
120  //Compute the number of padding bytes
121  paddingLen = 16 - (length % 16);
122 
123  //The padding is up to 15 zero bytes, and it brings the total length
124  //so far to an integral multiple of 16
125  osMemset(temp, 0, paddingLen);
126 
127  //Compute MAC over the padding
128  poly1305Update(&poly1305Context, temp, paddingLen);
129  }
130 
131  //Encode the length of the AAD as a 64-bit little-endian integer
132  STORE64LE(aLen, temp);
133  //Compute MAC over the length field
134  poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
135 
136  //Encode the length of the ciphertext as a 64-bit little-endian integer
137  STORE64LE(length, temp);
138  //Compute MAC over the length field
139  poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
140 
141  //Compute message-authentication code
142  poly1305Final(&poly1305Context, t);
143 
144  //Successful encryption
145  return NO_ERROR;
146 }
147 
148 
149 /**
150  * @brief Authenticated decryption using ChaCha20Poly1305
151  * @param[in] k key
152  * @param[in] kLen Length of the key
153  * @param[in] n Nonce
154  * @param[in] nLen Length of the nonce
155  * @param[in] a Additional authenticated data
156  * @param[in] aLen Length of the additional data
157  * @param[in] c Ciphertext to be decrypted
158  * @param[out] p Plaintext resulting from the decryption
159  * @param[in] length Total number of data bytes to be decrypted
160  * @param[in] t MAC to be verified
161  * @param[in] tLen Length of the MAC
162  * @return Error code
163  **/
164 
165 error_t chacha20Poly1305Decrypt(const uint8_t *k, size_t kLen,
166  const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen,
167  const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
168 {
169  error_t error;
170  uint8_t mask;
171  size_t i;
172  size_t paddingLen;
173  ChachaContext chachaContext;
174  Poly1305Context poly1305Context;
175  uint8_t temp[32];
176 
177  //Check the length of the message-authentication code
178  if(tLen != 16)
179  return ERROR_INVALID_LENGTH;
180 
181  //Initialize ChaCha20 context
182  error = chachaInit(&chachaContext, 20, k, kLen, n, nLen);
183  //Any error to report?
184  if(error)
185  return error;
186 
187  //First, a Poly1305 one-time key is generated from the 256-bit key
188  //and nonce
189  chachaCipher(&chachaContext, NULL, temp, 32);
190 
191  //The other 256 bits of the ChaCha20 block are discarded
192  chachaCipher(&chachaContext, NULL, NULL, 32);
193 
194  //Initialize the Poly1305 function with the key calculated above
195  poly1305Init(&poly1305Context, temp);
196 
197  //Compute MAC over the AAD
198  poly1305Update(&poly1305Context, a, aLen);
199 
200  //If the length of the AAD is not an integral multiple of 16 bytes,
201  //then padding is required
202  if((aLen % 16) != 0)
203  {
204  //Compute the number of padding bytes
205  paddingLen = 16 - (aLen % 16);
206 
207  //The padding is up to 15 zero bytes, and it brings the total length
208  //so far to an integral multiple of 16
209  osMemset(temp, 0, paddingLen);
210 
211  //Compute MAC over the padding
212  poly1305Update(&poly1305Context, temp, paddingLen);
213  }
214 
215  //Compute MAC over the ciphertext
216  poly1305Update(&poly1305Context, c, length);
217 
218  //If the length of the ciphertext is not an integral multiple of 16 bytes,
219  //then padding is required
220  if((length % 16) != 0)
221  {
222  //Compute the number of padding bytes
223  paddingLen = 16 - (length % 16);
224 
225  //The padding is up to 15 zero bytes, and it brings the total length
226  //so far to an integral multiple of 16
227  osMemset(temp, 0, paddingLen);
228 
229  //Compute MAC over the padding
230  poly1305Update(&poly1305Context, temp, paddingLen);
231  }
232 
233  //Encode the length of the AAD as a 64-bit little-endian integer
234  STORE64LE(aLen, temp);
235  //Compute MAC over the length field
236  poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
237 
238  //Encode the length of the ciphertext as a 64-bit little-endian integer
239  STORE64LE(length, temp);
240  //Compute MAC over the length field
241  poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
242 
243  //Compute message-authentication code
244  poly1305Final(&poly1305Context, temp);
245 
246  //Finally, we decrypt the ciphertext
247  chachaCipher(&chachaContext, c, p, length);
248 
249  //The calculated tag is bitwise compared to the received tag. The message
250  //is authenticated if and only if the tags match
251  for(mask = 0, i = 0; i < tLen; i++)
252  {
253  mask |= temp[i] ^ t[i];
254  }
255 
256  //Return status code
257  return (mask == 0) ? NO_ERROR : ERROR_FAILURE;
258 }
259 
260 #endif
void poly1305Init(Poly1305Context *context, const uint8_t *key)
Initialize Poly1305 message-authentication code computation.
Definition: poly1305.c:49
uint8_t a
Definition: ndp.h:411
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
Poly1305 context.
Definition: poly1305.h:48
void chachaCipher(ChachaContext *context, const uint8_t *input, uint8_t *output, size_t length)
Encrypt/decrypt data with the ChaCha algorithm.
Definition: chacha.c:183
ChaCha encryption algorithm.
error_t chachaInit(ChachaContext *context, uint_t nr, const uint8_t *key, size_t keyLen, const uint8_t *nonce, size_t nonceLen)
Initialize ChaCha context using the supplied key and nonce.
Definition: chacha.c:70
error_t
Error codes.
Definition: error.h:43
Poly1305 message-authentication code.
error_t chacha20Poly1305Encrypt(const uint8_t *k, size_t kLen, const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
Authenticated encryption using ChaCha20Poly1305.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
uint8_t length
Definition: tcp.h:368
ChaCha algorithm context.
Definition: chacha.h:48
ChaCha20Poly1305 AEAD.
uint8_t n
#define STORE64LE(a, p)
Definition: cpu_endian.h:311
void poly1305Final(Poly1305Context *context, uint8_t *tag)
Finalize Poly1305 message-authentication code computation.
Definition: poly1305.c:127
void poly1305Update(Poly1305Context *context, const void *data, size_t length)
Update Poly1305 message-authentication code computation.
Definition: poly1305.c:89
error_t chacha20Poly1305Decrypt(const uint8_t *k, size_t kLen, const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
Authenticated decryption using ChaCha20Poly1305.
#define osMemset(p, value, length)
Definition: os_port.h:135
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.