dtls13_record_encrypt.c
Go to the documentation of this file.
1 /**
2  * @file dtls13_record_encrypt.c
3  * @brief DTLS 1.3 record encryption
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSL 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.6.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL TLS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "tls/tls.h"
37 #include "dtls13/dtls13_misc.h"
39 #include "debug.h"
40 
41 //Check TLS library configuration
42 #if (TLS_SUPPORT == ENABLED && DTLS_SUPPORT == ENABLED && \
43  TLS_MAX_VERSION >= TLS_VERSION_1_3)
44 
45 
46 /**
47  * @brief Encrypt an outgoing DTLS 1.3 record
48  * @param[in] context Pointer to the TLS context
49  * @param[in] encryptionEngine Pointer to the encryption engine
50  * @param[in] type Record type
51  * @param[in] data Pointer to the payload data
52  * @param[in] dataLen Length of the payload data
53  * @param[out] record Buffer where to store the encrypted DTLS record
54  * @param[out] recordLen Length of the encrypted DTLS record, in bytes
55  * @return Error code
56  **/
57 
59  TlsEncryptionEngine *encryptionEngine, uint8_t type, const uint8_t *data,
60  size_t dataLen, uint8_t *record, size_t *recordLen)
61 {
62  error_t error;
63  size_t n;
64  size_t authTagLen;
65  uint8_t header[5];
66  size_t headerLen;
67  uint8_t nonce[48];
68  size_t nonceLen;
69 
70  //Retrieve the length of the authentication tag
71  if(encryptionEngine->hashAlgo != NULL)
72  {
73  authTagLen = encryptionEngine->hashAlgo->digestSize;
74  }
75  else
76  {
77  authTagLen = encryptionEngine->authTagLen;
78  }
79 
80  //The unified header is a structure of variable length
81  n = 0;
82 
83  //Format the first byte of the unified header
85  DTLS13_HEADER_FLAG_L | (encryptionEngine->epoch & DTLS13_HEADER_FLAG_E);
86 
87  //The record sequence number is 16 bits if the S bit is set to 1, and 8 bits
88  //if the S bit is 0
89  if((header[0] & DTLS13_HEADER_FLAG_S) != 0)
90  {
91  header[n++] = encryptionEngine->dtlsSeqNum.b[4];
92  header[n++] = encryptionEngine->dtlsSeqNum.b[5];
93  }
94  else
95  {
96  header[n++] = encryptionEngine->dtlsSeqNum.b[5];
97  }
98 
99  //The length field is present if the L bit is set
100  if((header[0] & DTLS13_HEADER_FLAG_L) != 0)
101  {
102  //The length field is 16 bits
103  header[n++] = MSB(dataLen + authTagLen + 1);
104  header[n++] = LSB(dataLen + authTagLen + 1);
105  }
106 
107  //Save the length of the unified header
108  headerLen = n;
109 
110  //The DTLSCiphertext structure is formed by concatenating the unified_hdr
111  //and encrypted_record fields
112  osMemmove(record + headerLen, data, dataLen);
113  osMemcpy(record, header, headerLen);
114 
115  //Debug message
116  TRACE_DEBUG("Record to be encrypted (%" PRIuSIZE " bytes):\r\n", headerLen + dataLen);
117  TRACE_DEBUG_ARRAY(" ", record, headerLen + dataLen);
118 
119  //The type field indicates the higher-level protocol used to process the
120  //enclosed fragment
121  record[headerLen + dataLen] = type;
122 
123  //Adjust the length of the payload data
124  dataLen++;
125 
126  //Generate the nonce
127  dtls13FormatNonce(encryptionEngine, &encryptionEngine->dtlsSeqNum, nonce,
128  &nonceLen);
129 
130 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \
131  TLS_GCM_CIPHER_SUPPORT == ENABLED || TLS_CHACHA20_POLY1305_SUPPORT == ENABLED)
132  //AEAD cipher?
133  if(encryptionEngine->cipherMode == CIPHER_MODE_CCM ||
134  encryptionEngine->cipherMode == CIPHER_MODE_GCM ||
135  encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
136  {
137  //Perform authenticated encryption
138  error = dtls13EncryptAeadRecord(context, encryptionEngine, nonce,
139  nonceLen, record, headerLen, record + headerLen, dataLen,
140  record + headerLen + dataLen);
141  }
142  else
143 #endif
144 #if (TLS_NULL_CIPHER_SUPPORT == ENABLED)
145  //NULL cipher?
146  if(encryptionEngine->cipherMode == CIPHER_MODE_NULL)
147  {
148  //Compute message authentication code
149  error = dtls13ComputeMac(context, encryptionEngine, nonce,
150  nonceLen, record, headerLen, record + headerLen, dataLen,
151  record + headerLen + dataLen);
152  }
153  else
154 #endif
155  //Invalid cipher mode?
156  {
157  //The specified cipher mode is not supported
159  }
160 
161  //Check status code
162  if(!error)
163  {
164  //In DTLS 1.3, when records are encrypted, record sequence numbers are
165  //also encrypted (refer to RFC 9147, section 4.2.3)
166  error = dtls13EncryptSequenceNumber(encryptionEngine, record);
167 
168  }
169 
170  //Check status code
171  if(!error)
172  {
173  //Length of the resulting datagram, in bytes
174  *recordLen = headerLen + dataLen + authTagLen;
175 
176  //Debug message
177  TRACE_DEBUG("Encrypted record (%" PRIuSIZE " bytes):\r\n", *recordLen);
178  TRACE_DEBUG_ARRAY(" ", record, *recordLen);
179  }
180 
181  //Return status code
182  return error;
183 }
184 
185 
186 /**
187  * @brief Record encryption (AEAD cipher)
188  * @param[in] context Pointer to the TLS context
189  * @param[in] encryptionEngine Pointer to the encryption engine
190  * @param[in] nonce Nonce
191  * @param[in] nonceLen Length of the nonce, in bytes
192  * @param[in] aad Additional authenticated data
193  * @param[in] aadLen Length of the additional data
194  * @param[in,out] data Payload data
195  * @param[in] dataLen Total number of data bytes to be encrypted
196  * @param[out] tag Authentication tag
197  * @return Error code
198  **/
199 
201  TlsEncryptionEngine *encryptionEngine, const uint8_t *nonce,
202  size_t nonceLen, const uint8_t *aad, size_t aadLen, uint8_t *data,
203  size_t dataLen, uint8_t *tag)
204 {
205  error_t error;
206 
207 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED)
208  //CCM AEAD cipher?
209  if(encryptionEngine->cipherMode == CIPHER_MODE_CCM)
210  {
211  //Authenticated encryption using CCM
212  error = ccmEncrypt(encryptionEngine->cipherAlgo,
213  encryptionEngine->cipherContext, nonce, nonceLen, aad, aadLen,
214  data, data, dataLen, tag, encryptionEngine->authTagLen);
215  }
216  else
217 #endif
218 #if (TLS_GCM_CIPHER_SUPPORT == ENABLED)
219  //GCM AEAD cipher?
220  if(encryptionEngine->cipherMode == CIPHER_MODE_GCM)
221  {
222  //Authenticated encryption using GCM
223  error = gcmEncrypt(encryptionEngine->gcmContext, nonce, nonceLen,
224  aad, aadLen, data, data, dataLen, tag, encryptionEngine->authTagLen);
225  }
226  else
227 #endif
228 #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED)
229  //ChaCha20Poly1305 AEAD cipher?
230  if(encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
231  {
232  //Authenticated encryption using ChaCha20Poly1305
233  error = chacha20Poly1305Encrypt(encryptionEngine->encKey,
234  encryptionEngine->encKeyLen, nonce, nonceLen, aad, aadLen,
235  data, data, dataLen, tag, encryptionEngine->authTagLen);
236  }
237  else
238 #endif
239  //Invalid cipher mode?
240  {
241  //The specified cipher mode is not supported
243  }
244 
245  //Successful processing
246  return error;
247 }
248 
249 
250 /**
251  * @brief Compute message authentication code
252  * @param[in] context Pointer to the TLS context
253  * @param[in] encryptionEngine Pointer to the encryption engine
254  * @param[in] nonce Nonce
255  * @param[in] nonceLen Length of the nonce, in bytes
256  * @param[in] aad Additional authenticated data
257  * @param[in] aadLen Length of the additional data
258  * @param[in] data Payload data
259  * @param[in] dataLen Total number of data bytes to be authenticated
260  * @param[out] mac Message authentication code
261  * @return Error code
262  **/
263 
265  TlsEncryptionEngine *encryptionEngine, const uint8_t *nonce,
266  size_t nonceLen, const uint8_t *aad, size_t aadLen, const uint8_t *data,
267  size_t dataLen, uint8_t *mac)
268 {
269  HmacContext *hmacContext;
270 
271  //Point to the HMAC context
272  hmacContext = encryptionEngine->hmacContext;
273 
274  //The protect operation provides the integrity protection using HMAC SHA-256
275  //or HMAC SHA-384 (refer to RFC 9150, section 5)
276  hmacInit(hmacContext, encryptionEngine->hashAlgo,
277  encryptionEngine->encKey, encryptionEngine->encKeyLen);
278 
279  //Compute HMAC(write_key, nonce || additional_data || DTLSInnerPlaintext)
280  hmacUpdate(hmacContext, nonce, nonceLen);
281  hmacUpdate(hmacContext, aad, aadLen);
282  hmacUpdate(hmacContext, data, dataLen);
283 
284  //Finalize HMAC computation
285  hmacFinal(hmacContext, mac);
286 
287  //Successful processing
288  return NO_ERROR;
289 }
290 
291 
292 /**
293  * @brief Encrypt sequence number
294  * @param[in] encryptionEngine Pointer to the encryption engine
295  * @param[in,out] record Pointer to the DTLS 1.3 record
296  * @return Error code
297  **/
298 
300  uint8_t *record)
301 {
302  error_t error;
303  size_t n;
304  uint8_t mask[16];
305 
306  //Initialize status code
307  error = NO_ERROR;
308 
309  //The DTLS 1.3 unified header is a structure of variable length
310  n = sizeof(uint8_t);
311 
312  //The record sequence number is 16 bits if the S bit is set to 1, and 8 bits
313  //if the S bit is 0
314  if((record[0] & DTLS13_HEADER_FLAG_S) != 0)
315  {
316  n += sizeof(uint16_t);
317  }
318  else
319  {
320  n += sizeof(uint8_t);
321  }
322 
323  //The length field is present if the L bit is set
324  if((record[0] & DTLS13_HEADER_FLAG_L) != 0)
325  {
326  n += sizeof(uint16_t);
327  }
328 
329 #if (TLS_CCM_CIPHER_SUPPORT == ENABLED || TLS_CCM_8_CIPHER_SUPPORT == ENABLED || \
330  TLS_GCM_CIPHER_SUPPORT == ENABLED)
331  //CCM or GCM AEAD cipher?
332  if(encryptionEngine->cipherMode == CIPHER_MODE_CCM ||
333  encryptionEngine->cipherMode == CIPHER_MODE_GCM)
334  {
335  //When the AEAD is based on AES, then the mask is generated by computing
336  //AES-ECB on the first 16 bytes of the ciphertext (refer to RFC 9147,
337  //section 4.2.3)
338  encryptionEngine->cipherAlgo->encryptBlock(
339  encryptionEngine->snCipherContext, record + n, mask);
340  }
341  else
342 #endif
343 #if (TLS_CHACHA20_POLY1305_SUPPORT == ENABLED)
344  //ChaCha20Poly1305 AEAD cipher?
345  if(encryptionEngine->cipherMode == CIPHER_MODE_CHACHA20_POLY1305)
346  {
347  ChachaContext chachaContext;
348 
349  //When the AEAD is based on ChaCha20, then the mask is generated by
350  //treating the first 4 bytes of the ciphertext as the block counter and
351  //the next 12 bytes as the nonce
352  error = chachaInit(&chachaContext, 20, encryptionEngine->snKey,
353  encryptionEngine->encKeyLen, record + n, 16);
354 
355  //Check status code
356  if(!error)
357  {
358  //Invoke ChaCha20 block function
359  chachaCipher(&chachaContext, NULL, mask, 2);
360  }
361  }
362  else
363 #endif
364 #if (TLS_NULL_CIPHER_SUPPORT == ENABLED)
365  //NULL cipher?
366  if(encryptionEngine->cipherMode == CIPHER_MODE_NULL)
367  {
368  //For integrity-only cipher suites, the record sequence numbers are sent
369  //unencrypted (refer to RFC 9150, section 9)
370  mask[0] = 0;
371  mask[1] = 0;
372  }
373  else
374 #endif
375  //Invalid cipher mode?
376  {
377  //The specified cipher mode is not supported
379  }
380 
381  //Check status code
382  if(!error)
383  {
384  //The encrypted sequence number is computed by XORing the leading bytes
385  //of the mask with the on-the-wire representation of the sequence number
386  if((record[0] & DTLS13_HEADER_FLAG_S) != 0)
387  {
388  record[1] ^= mask[0];
389  record[2] ^= mask[1];
390  }
391  else
392  {
393  record[1] ^= mask[0];
394  }
395  }
396 
397  //Return status code
398  return error;
399 }
400 
401 #endif
HMAC algorithm context.
Definition: hmac.h:59
@ CIPHER_MODE_GCM
Definition: crypto.h:1068
Collection of AEAD algorithms.
uint8_t data[]
Definition: ethernet.h:224
__weak_func error_t ccmEncrypt(const CipherAlgo *cipher, void *context, 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 CCM.
Definition: ccm.c:67
uint8_t type
Definition: coap_common.h:176
void chachaCipher(ChachaContext *context, const uint8_t *input, uint8_t *output, size_t length)
Encrypt/decrypt data with the ChaCha algorithm.
Definition: chacha.c:192
@ ERROR_UNSUPPORTED_CIPHER_MODE
Definition: error.h:128
error_t dtls13ComputeMac(TlsContext *context, TlsEncryptionEngine *encryptionEngine, const uint8_t *nonce, size_t nonceLen, const uint8_t *aad, size_t aadLen, const uint8_t *data, size_t dataLen, uint8_t *mac)
Compute message authentication code.
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
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define TlsContext
Definition: tls.h:36
error_t
Error codes.
Definition: error.h:43
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.
DTLS 1.3 (Datagram Transport Layer Security)
uint8_t mask
Definition: web_socket.h:319
#define MSB(x)
Definition: os_port.h:59
#define LSB(x)
Definition: os_port.h:55
void dtls13FormatNonce(TlsEncryptionEngine *encryptionEngine, const DtlsSequenceNumber *seqNum, uint8_t *nonce, size_t *nonceLen)
Format nonce.
Definition: dtls13_misc.c:381
#define DTLS13_HEADER_FIXED
Definition: dtls13_misc.h:46
uint32_t dataLen
Definition: sftp_common.h:229
ChaCha algorithm context.
Definition: chacha.h:48
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
Update the HMAC context with a portion of the message being hashed.
Definition: hmac.c:201
#define TRACE_DEBUG(...)
Definition: debug.h:119
@ CIPHER_MODE_CCM
Definition: crypto.h:1067
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
uint8_t n
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
#define DTLS13_HEADER_FLAG_E
Definition: dtls13_misc.h:50
TLS (Transport Layer Security)
error_t dtls13EncryptAeadRecord(TlsContext *context, TlsEncryptionEngine *encryptionEngine, const uint8_t *nonce, size_t nonceLen, const uint8_t *aad, size_t aadLen, uint8_t *data, size_t dataLen, uint8_t *tag)
Record encryption (AEAD cipher)
@ CIPHER_MODE_NULL
Definition: crypto.h:1060
@ CIPHER_MODE_CHACHA20_POLY1305
Definition: crypto.h:1070
error_t dtls13EncryptSequenceNumber(TlsEncryptionEngine *encryptionEngine, uint8_t *record)
Encrypt sequence number.
#define PRIuSIZE
error_t dtls13EncryptRecord(TlsContext *context, TlsEncryptionEngine *encryptionEngine, uint8_t type, const uint8_t *data, size_t dataLen, uint8_t *record, size_t *recordLen)
Encrypt an outgoing DTLS 1.3 record.
#define DTLS13_HEADER_FLAG_L
Definition: dtls13_misc.h:49
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
#define DTLS13_HEADER_FLAG_S
Definition: dtls13_misc.h:48
#define TlsEncryptionEngine
Definition: tls.h:40
__weak_func error_t gcmEncrypt(GcmContext *context, const uint8_t *iv, size_t ivLen, 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 GCM.
Definition: gcm.c:209
DTLS 1.3 record encryption.
uint8_t nonce[]
Definition: ntp_common.h:239
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150