rsa_misc.c
Go to the documentation of this file.
1 /**
2  * @file rsa_misc.c
3  * @brief Helper routines for RSA
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 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  * @section Description
28  *
29  * RSA is an algorithm for public-key cryptography which is suitable for signing
30  * as well as encryption. Refer to the following RFCs for complete details:
31  * - RFC 2313: PKCS #1: RSA Encryption Version 1.5
32  * - RFC 3447: PKCS #1: RSA Cryptography Specifications Version 2.1
33  * - RFC 8017: PKCS #1: RSA Cryptography Specifications Version 2.2
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 2.6.6
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/crypto.h"
44 #include "pkc/rsa.h"
45 #include "pkc/rsa_misc.h"
46 #include "encoding/asn1.h"
47 #include "debug.h"
48 
49 //Check crypto library configuration
50 #if (RSA_SUPPORT == ENABLED)
51 
52 //Padding string
53 static const uint8_t padding[] =
54 {
55  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
56 };
57 
58 
59 /**
60  * @brief RSA encryption primitive
61  *
62  * The RSA encryption primitive produces a ciphertext representative from
63  * a message representative under the control of a public key
64  *
65  * @param[in] key RSA public key
66  * @param[in] m Message representative
67  * @param[out] c Ciphertext representative
68  * @return Error code
69  **/
70 
71 __weak_func error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
72 {
73  //Ensure the RSA public key is valid
74  if(mpiGetLength(&key->n) == 0 || mpiGetLength(&key->e) == 0)
76 
77  //The message representative m shall be between 0 and n - 1
78  if(mpiCompInt(m, 0) < 0 || mpiComp(m, &key->n) >= 0)
79  return ERROR_OUT_OF_RANGE;
80 
81  //Perform modular exponentiation (c = m ^ e mod n)
82  return mpiExpModFast(c, m, &key->e, &key->n);
83 }
84 
85 
86 /**
87  * @brief RSA decryption primitive
88  *
89  * The RSA decryption primitive recovers the message representative from
90  * the ciphertext representative under the control of a private key
91  *
92  * @param[in] key RSA private key
93  * @param[in] c Ciphertext representative
94  * @param[out] m Message representative
95  * @return Error code
96  **/
97 
98 __weak_func error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
99 {
100  error_t error;
101  Mpi m1;
102  Mpi m2;
103  Mpi h;
104 
105  //The ciphertext representative c shall be between 0 and n - 1
106  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
107  return ERROR_OUT_OF_RANGE;
108 
109  //Initialize multiple-precision integers
110  mpiInit(&m1);
111  mpiInit(&m2);
112  mpiInit(&h);
113 
114  //Use the Chinese remainder algorithm?
115  if(mpiGetLength(&key->p) > 0 && mpiGetLength(&key->q) > 0 &&
116  mpiGetLength(&key->dp) > 0 && mpiGetLength(&key->dq) > 0 &&
117  mpiGetLength(&key->qinv) > 0)
118  {
119  //Compute m1 = c ^ dP mod p
120  MPI_CHECK(mpiMod(&m1, c, &key->p));
121  MPI_CHECK(mpiExpModRegular(&m1, &m1, &key->dp, &key->p));
122  //Compute m2 = c ^ dQ mod q
123  MPI_CHECK(mpiMod(&m2, c, &key->q));
124  MPI_CHECK(mpiExpModRegular(&m2, &m2, &key->dq, &key->q));
125  //Let h = (m1 - m2) * qInv mod p
126  MPI_CHECK(mpiSub(&h, &m1, &m2));
127  MPI_CHECK(mpiMulMod(&h, &h, &key->qinv, &key->p));
128  //Let m = m2 + q * h
129  MPI_CHECK(mpiMul(m, &key->q, &h));
130  MPI_CHECK(mpiAdd(m, m, &m2));
131  }
132  //Use modular exponentiation?
133  else if(mpiGetLength(&key->n) > 0 && mpiGetLength(&key->d) > 0)
134  {
135  //Let m = c ^ d mod n
136  error = mpiExpModRegular(m, c, &key->d, &key->n);
137  }
138  //Invalid parameters?
139  else
140  {
141  //Report an error
142  error = ERROR_INVALID_PARAMETER;
143  }
144 
145 end:
146  //Free previously allocated memory
147  mpiFree(&m1);
148  mpiFree(&m2);
149  mpiFree(&h);
150 
151  //Return status code
152  return error;
153 }
154 
155 
156 /**
157  * @brief RSA signature primitive
158  *
159  * The RSA signature primitive produces a signature representative from
160  * a message representative under the control of a private key
161  *
162  * @param[in] key RSA private key
163  * @param[in] m Message representative
164  * @param[out] s Signature representative
165  * @return Error code
166  **/
167 
168 error_t rsasp1(const RsaPrivateKey *key, const Mpi *m, Mpi *s)
169 {
170  //RSASP1 primitive is the same as RSADP except for the names of its input
171  //and output arguments. They are distinguished as they are intended for
172  //different purposes
173  return rsadp(key, m, s);
174 }
175 
176 
177 /**
178  * @brief RSA verification primitive
179  *
180  * The RSA verification primitive recovers the message representative from
181  * the signature representative under the control of a public key
182  *
183  * @param[in] key RSA public key
184  * @param[in] s Signature representative
185  * @param[out] m Message representative
186  * @return Error code
187  **/
188 
189 error_t rsavp1(const RsaPublicKey *key, const Mpi *s, Mpi *m)
190 {
191  //RSAVP1 primitive is the same as RSAEP except for the names of its input
192  //and output arguments. They are distinguished as they are intended for
193  //different purposes
194  return rsaep(key, s, m);
195 }
196 
197 
198 /**
199  * @brief EME-PKCS1-v1_5 encoding operation
200  * @param[in] prngAlgo PRNG algorithm
201  * @param[in] prngContext Pointer to the PRNG context
202  * @param[in] message Message to be encrypted
203  * @param[in] messageLen Length of the message to be encrypted
204  * @param[out] em Encoded message
205  * @param[in] k Length of the encoded message
206  * @return Error code
207  **/
208 
209 error_t emePkcs1v15Encode(const PrngAlgo *prngAlgo, void *prngContext,
210  const uint8_t *message, size_t messageLen, uint8_t *em, size_t k)
211 {
212  error_t error;
213  size_t i;
214  size_t j;
215  size_t n;
216  uint8_t *p;
217 
218  //Check the length of the message
219  if((messageLen + 11) > k)
220  return ERROR_INVALID_LENGTH;
221 
222  //The leading 0x00 octet ensures that the encoded message, converted to
223  //an integer, is less than the modulus
224  em[0] = 0x00;
225  //For a public-key operation, the block type BT shall be 0x02
226  em[1] = 0x02;
227 
228  //Point to the buffer where to format the padding string PS
229  p = em + 2;
230  //Determine the length of the padding string
231  n = k - messageLen - 3;
232 
233  //Generate an octet string PS of length k - mLen - 3 consisting of
234  //pseudo-randomly generated nonzero octets
235  while(n > 0)
236  {
237  //Generate random data
238  error = prngAlgo->generate(prngContext, p, n);
239  //Any error to report?
240  if(error)
241  return error;
242 
243  //Parse the resulting octet string
244  for(i = 0, j = 0; j < n; j++)
245  {
246  //Strip any byte with a value of zero
247  if(p[j] != 0)
248  {
249  p[i++] = p[j];
250  }
251  }
252 
253  //Advance data pointer
254  p += i;
255  n -= i;
256  }
257 
258  //Append a 0x00 octet to the padding string
259  *p = 0x00;
260 
261  //Copy the message to be encrypted
262  osMemcpy(p + 1, message, messageLen);
263 
264  //Successful processing
265  return NO_ERROR;
266 }
267 
268 
269 /**
270  * @brief EME-PKCS1-v1_5 decoding operation
271  * @param[in] em Encoded message
272  * @param[in] k Length of the encoded message
273  * @param[out] messageLen Length of the decrypted message
274  * @return The function returns 0 on success, 1 on failure
275  **/
276 
277 uint32_t emePkcs1v15Decode(uint8_t *em, size_t k, size_t *messageLen)
278 {
279  size_t i;
280  size_t m;
281  uint32_t c;
282  uint32_t bad;
283 
284  //Separate the encoded message EM into an octet string PS consisting of
285  //nonzero octets and a message M
286  for(m = 0, i = 2; i < k; i++)
287  {
288  //Constant time implementation
289  c = CRYPTO_TEST_Z_8(em[i]);
290  c &= CRYPTO_TEST_Z_32(m);
291  m = CRYPTO_SELECT_32(m, i, c);
292  }
293 
294  //If the first octet of EM does not have hexadecimal value 0x00, then
295  //report a decryption error
296  bad = CRYPTO_TEST_NEQ_8(em[0], 0x00);
297 
298  //If the second octet of EM does not have hexadecimal value 0x02, then
299  //report a decryption error
300  bad |= CRYPTO_TEST_NEQ_8(em[1], 0x02);
301 
302  //If there is no octet with hexadecimal value 0x00 to separate PS from M,
303  //then report a decryption error
304  bad |= CRYPTO_TEST_Z_32(m);
305 
306  //If the length of PS is less than 8 octets, then report a decryption error
307  bad |= CRYPTO_TEST_LT_32(m, 10);
308 
309  //Return the length of the decrypted message
310  *messageLen = CRYPTO_SELECT_32(k - m - 1, 0, bad);
311 
312  //Care must be taken to ensure that an opponent cannot distinguish the
313  //different error conditions, whether by error message or timing
314  return bad;
315 }
316 
317 
318 /**
319  * @brief EME-OAEP encoding operation
320  * @param[in] prngAlgo PRNG algorithm
321  * @param[in] prngContext Pointer to the PRNG context
322  * @param[in] hash Hash function
323  * @param[in] mgfHash MGF hash function
324  * @param[in] label Optional label to be associated with the message
325  * @param[in] labelLen Length of the label, in bytes
326  * @param[in] message Message to be encrypted
327  * @param[in] messageLen Length of the message to be encrypted
328  * @param[out] em Encoded message
329  * @param[in] k Length of the encoded message
330  * @return Error code
331  **/
332 
333 error_t emeOaepEncode(const PrngAlgo *prngAlgo, void *prngContext,
334  const HashAlgo *hash, const HashAlgo *mgfHash, const char_t *label,
335  size_t labelLen, const uint8_t *message, size_t messageLen, uint8_t *em,
336  size_t k)
337 {
338  error_t error;
339  size_t n;
340  uint8_t *db;
341  uint8_t *seed;
342 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
343  HashContext *hashContext;
344 #else
345  HashContext hashContext[1];
346 #endif
347 
348  //The label is optional
349  if(label == NULL && labelLen != 0)
351 
352  //Check the length of the message
353  if(messageLen > (k - 2 * hash->digestSize - 2))
354  return ERROR_INVALID_LENGTH;
355 
356  //Point to the buffer where to format the seed
357  seed = em + 1;
358  //Point to the buffer where to format the data block
359  db = em + hash->digestSize + 1;
360 
361  //Generate a random octet string seed of length hLen
362  error = prngAlgo->generate(prngContext, seed, hash->digestSize);
363  //Any error to report?
364  if(error)
365  return error;
366 
367 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
368  //Allocate a memory buffer to hold the hash context
369  hashContext = cryptoAllocMem(sizeof(HashContext));
370  //Failed to allocate memory?
371  if(hashContext == NULL)
372  return ERROR_OUT_OF_MEMORY;
373 #endif
374 
375  //Let lHash = Hash(L)
376  hash->init(hashContext);
377  hash->update(hashContext, label, labelLen);
378  hash->final(hashContext, db);
379 
380  //The padding string PS consists of k - mLen - 2hLen - 2 zero octets
381  n = k - messageLen - 2 * hash->digestSize - 2;
382  //Generate the padding string
383  osMemset(db + hash->digestSize, 0, n);
384 
385  //Concatenate lHash, PS, a single octet with hexadecimal value 0x01, and
386  //the message M to form a data block DB of length k - hLen - 1 octets
387  db[hash->digestSize + n] = 0x01;
388  osMemcpy(db + hash->digestSize + n + 1, message, messageLen);
389 
390  //Calculate the length of the data block
391  n = k - hash->digestSize - 1;
392 
393  //Let maskedDB = DB xor MGF(seed, k - hLen - 1)
394  mgf(mgfHash, hashContext, seed, hash->digestSize, db, n);
395  //Let maskedSeed = seed xor MGF(maskedDB, hLen)
396  mgf(mgfHash, hashContext, db, n, seed, hash->digestSize);
397 
398  //Concatenate a single octet with hexadecimal value 0x00, maskedSeed, and
399  //maskedDB to form an encoded message EM of length k octets
400  em[0] = 0x00;
401 
402 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
403  //Release hash context
404  cryptoFreeMem(hashContext);
405 #endif
406 
407  //Successful processing
408  return NO_ERROR;
409 }
410 
411 
412 /**
413  * @brief EME-OAEP decoding operation
414  * @param[in] hash Hash function
415  * @param[in] mgfHash MGF hash function
416  * @param[in] label Optional label to be associated with the message
417  * @param[in] labelLen Length of the label, in bytes
418  * @param[in] em Encoded message
419  * @param[in] k Length of the encoded message
420  * @param[out] messageLen Length of the decrypted message
421  * @return The function returns 0 on success, 1 on failure
422  **/
423 
424 uint32_t emeOaepDecode(const HashAlgo *hash, const HashAlgo *mgfHash,
425  const char_t *label, size_t labelLen, uint8_t *em, size_t k,
426  size_t *messageLen)
427 {
428  size_t i;
429  size_t m;
430  size_t n;
431  uint32_t c;
432  uint32_t bad;
433  uint8_t *db;
434  uint8_t *seed;
435  uint8_t lHash[MAX_HASH_DIGEST_SIZE];
436 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
437  HashContext *hashContext;
438 #else
439  HashContext hashContext[1];
440 #endif
441 
442  //The label is optional
443  if(label == NULL && labelLen != 0)
445 
446 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
447  //Allocate a memory buffer to hold the hash context
448  hashContext = cryptoAllocMem(sizeof(HashContext));
449  //Failed to allocate memory?
450  if(hashContext == NULL)
451  return TRUE;
452 #endif
453 
454  //Let lHash = Hash(L)
455  hash->init(hashContext);
456  hash->update(hashContext, label, labelLen);
457  hash->final(hashContext, lHash);
458 
459  //Separate the encoded message EM into a single octet Y, an octet string
460  //maskedSeed of length hLen, and an octet string maskedDB of length k - hLen - 1
461  seed = em + 1;
462  db = em + hash->digestSize + 1;
463 
464  //Calculate the length of the data block
465  n = k - hash->digestSize - 1;
466 
467  //Let seed = maskedSeed xor MGF(maskedDB, hLen)
468  mgf(mgfHash, hashContext, db, n, seed, hash->digestSize);
469  //Let DB = maskedDB xor MGF(seed, k - hLen - 1)
470  mgf(mgfHash, hashContext, seed, hash->digestSize, db, n);
471 
472 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
473  //Release hash context
474  cryptoFreeMem(hashContext);
475 #endif
476 
477  //Separate DB into an octet string lHash' of length hLen, a padding string
478  //PS consisting of octets with hexadecimal value 0x00, and a message M
479  for(m = 0, i = hash->digestSize; i < n; i++)
480  {
481  //Constant time implementation
482  c = CRYPTO_TEST_NZ_8(db[i]);
483  c &= CRYPTO_TEST_Z_32(m);
484  m = CRYPTO_SELECT_32(m, i, c);
485  }
486 
487  //Make sure the padding string PS is terminated
488  bad = CRYPTO_TEST_Z_32(m);
489 
490  //If there is no octet with hexadecimal value 0x01 to separate PS from M,
491  //then report a decryption error
492  bad |= CRYPTO_TEST_NEQ_8(db[m], 0x01);
493 
494  //If lHash does not equal lHash', then report a decryption error
495  for(i = 0; i < hash->digestSize; i++)
496  {
497  bad |= CRYPTO_TEST_NEQ_8(db[i], lHash[i]);
498  }
499 
500  //If Y is nonzero, then report a decryption error
501  bad |= CRYPTO_TEST_NEQ_8(em[0], 0x00);
502 
503  //Return the length of the decrypted message
504  *messageLen = CRYPTO_SELECT_32(n - m - 1, 0, bad);
505 
506  //Care must be taken to ensure that an opponent cannot distinguish the
507  //different error conditions, whether by error message or timing
508  return bad;
509 }
510 
511 
512 /**
513  * @brief EMSA-PKCS1-v1_5 encoding operation
514  * @param[in] hash Hash function used to digest the message
515  * @param[in] digest Digest of the message to be signed
516  * @param[out] em Encoded message
517  * @param[in] emLen Intended length of the encoded message
518  * @return Error code
519  **/
520 
522  const uint8_t *digest, uint8_t *em, size_t emLen)
523 {
524  size_t i;
525  size_t n;
526 
527  //Check the intended length of the encoded message
528  if(emLen < (hash->oidSize + hash->digestSize + 21))
529  return ERROR_INVALID_LENGTH;
530 
531  //Point to the first byte of the encoded message
532  i = 0;
533 
534  //The leading 0x00 octet ensures that the encoded message, converted to
535  //an integer, is less than the modulus
536  em[i++] = 0x00;
537  //Block type 0x01 is used for private-key operations
538  em[i++] = 0x01;
539 
540  //Determine the length of the padding string PS
541  n = emLen - hash->oidSize - hash->digestSize - 13;
542 
543  //Each byte of PS must be set to 0xFF when the block type is 0x01
544  osMemset(em + i, 0xFF, n);
545  i += n;
546 
547  //Append a 0x00 octet to the padding string
548  em[i++] = 0x00;
549 
550  //Encode the DigestInfo structure using ASN.1
551  em[i++] = (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
552  em[i++] = (uint8_t) (hash->oidSize + hash->digestSize + 8);
553  em[i++] = (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
554  em[i++] = (uint8_t) (hash->oidSize + 4);
555  em[i++] = (uint8_t) ASN1_TYPE_OBJECT_IDENTIFIER;
556  em[i++] = (uint8_t) hash->oidSize;
557 
558  //Copy the hash algorithm OID
559  osMemcpy(em + i, hash->oid, hash->oidSize);
560  i += hash->oidSize;
561 
562  //Encode the rest of the ASN.1 structure
563  em[i++] = (uint8_t) ASN1_TYPE_NULL;
564  em[i++] = 0;
565  em[i++] = (uint8_t) ASN1_TYPE_OCTET_STRING;
566  em[i++] = (uint8_t) hash->digestSize;
567 
568  //Append the hash value
569  osMemcpy(em + i, digest, hash->digestSize);
570 
571  //Successful processing
572  return NO_ERROR;
573 }
574 
575 
576 /**
577  * @brief EMSA-PKCS1-v1_5 verification operation
578  * @param[in] hash Hash function
579  * @param[in] digest Digest value
580  * @param[in] em Encoded message
581  * @param[in] emLen Length of the encoded message
582  * @return Error code
583  **/
584 
585 error_t emsaPkcs1v15Verify(const HashAlgo *hash, const uint8_t *digest,
586  const uint8_t *em, size_t emLen)
587 {
588  size_t i;
589  size_t j;
590  size_t n;
591  uint8_t bad;
592 
593  //Check the length of the encoded message
594  if(emLen < (hash->oidSize + hash->digestSize + 21))
595  return ERROR_INVALID_LENGTH;
596 
597  //Point to the first byte of the encoded message
598  i = 0;
599 
600  //The first octet of EM must have hexadecimal value 0x00
601  bad = em[i++];
602  //The second octet of EM must have hexadecimal value 0x01
603  bad |= em[i++] ^ 0x01;
604 
605  //Determine the length of the padding string PS
606  n = emLen - hash->oidSize - hash->digestSize - 13;
607 
608  //Each byte of PS must be set to 0xFF when the block type is 0x01
609  for(j = 0; j < n; j++)
610  {
611  bad |= em[i++] ^ 0xFF;
612  }
613 
614  //The padding string must be followed by a 0x00 octet
615  bad |= em[i++];
616 
617  //Check the ASN.1 syntax of the DigestInfo structure
618  bad |= em[i++] ^ (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
619  bad |= em[i++] ^ (uint8_t) (hash->oidSize + hash->digestSize + 8);
620  bad |= em[i++] ^ (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
621  bad |= em[i++] ^ (uint8_t) (hash->oidSize + 4);
622  bad |= em[i++] ^ (uint8_t) ASN1_TYPE_OBJECT_IDENTIFIER;
623  bad |= em[i++] ^ (uint8_t) hash->oidSize;
624 
625  //Verify the hash algorithm OID
626  for(j = 0; j < hash->oidSize; j++)
627  {
628  bad |= em[i++] ^ hash->oid[j];
629  }
630 
631  //Check the rest of the ASN.1 structure
632  bad |= em[i++] ^ (uint8_t) ASN1_TYPE_NULL;
633  bad |= em[i++];
634  bad |= em[i++] ^ (uint8_t) ASN1_TYPE_OCTET_STRING;
635  bad |= em[i++] ^ (uint8_t) hash->digestSize;
636 
637  //Recover the underlying hash value, and then compare it to the newly
638  //computed hash value
639  for(j = 0; j < hash->digestSize; j++)
640  {
641  bad |= em[i++] ^ digest[j];
642  }
643 
644  //Verification result
645  return (bad != 0) ? ERROR_INCONSISTENT_VALUE : NO_ERROR;
646 }
647 
648 
649 /**
650  * @brief EMSA-PSS encoding operation
651  * @param[in] prngAlgo PRNG algorithm
652  * @param[in] prngContext Pointer to the PRNG context
653  * @param[in] hash Hash function
654  * @param[in] mgfHash MGF hash function
655  * @param[in] saltLen Length of the salt, in bytes
656  * @param[in] digest Digest of the message to be signed
657  * @param[out] em Encoded message
658  * @param[in] emBits Maximal bit length of the integer OS2IP(EM)
659  * @return Error code
660  **/
661 
662 error_t emsaPssEncode(const PrngAlgo *prngAlgo, void *prngContext,
663  const HashAlgo *hash, const HashAlgo *mgfHash, size_t saltLen,
664  const uint8_t *digest, uint8_t *em, uint_t emBits)
665 {
666  error_t error;
667  size_t n;
668  size_t emLen;
669  uint8_t *db;
670  uint8_t *salt;
671  uint8_t h[MAX_HASH_DIGEST_SIZE];
672 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
673  HashContext *hashContext;
674 #else
675  HashContext hashContext[1];
676 #endif
677 
678  //The encoded message is an octet string of length emLen = ceil(emBits / 8)
679  emLen = (emBits + 7) / 8;
680 
681  //If emLen < hLen + sLen + 2, output "encoding error" and stop
682  if(emLen < (hash->digestSize + saltLen + 2))
683  return ERROR_INVALID_LENGTH;
684 
685  //The padding string PS consists of emLen - sLen - hLen - 2 zero octets
686  n = emLen - saltLen - hash->digestSize - 2;
687 
688  //Point to the buffer where to format the data block DB
689  db = em;
690  //Point to the buffer where to generate the salt
691  salt = db + n + 1;
692 
693  //Generate a random octet string salt of length sLen
694  error = prngAlgo->generate(prngContext, salt, saltLen);
695  //Any error to report?
696  if(error)
697  return error;
698 
699 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
700  //Allocate a memory buffer to hold the hash context
701  hashContext = cryptoAllocMem(sizeof(HashContext));
702  //Failed to allocate memory?
703  if(hashContext == NULL)
704  return ERROR_OUT_OF_MEMORY;
705 #endif
706 
707  //Let H = Hash(00 00 00 00 00 00 00 00 || mHash || salt)
708  hash->init(hashContext);
709  hash->update(hashContext, padding, sizeof(padding));
710  hash->update(hashContext, digest, hash->digestSize);
711  hash->update(hashContext, salt, saltLen);
712  hash->final(hashContext, h);
713 
714  //Let DB = PS || 0x01 || salt
715  osMemset(db, 0, n);
716  db[n] = 0x01;
717 
718  //Calculate the length of the data block
719  n += saltLen + 1;
720 
721  //Let maskedDB = DB xor MGF(H, emLen - hLen - 1)
722  mgf(mgfHash, hashContext, h, hash->digestSize, db, n);
723 
724  //Set the leftmost 8emLen - emBits bits of the leftmost octet in maskedDB
725  //to zero
726  db[0] &= 0xFF >> (8 * emLen - emBits);
727 
728  //Let EM = maskedDB || H || 0xbc
729  osMemcpy(em + n, h, hash->digestSize);
730  em[n + hash->digestSize] = 0xBC;
731 
732 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
733  //Release hash context
734  cryptoFreeMem(hashContext);
735 #endif
736 
737  //Successful processing
738  return NO_ERROR;
739 }
740 
741 
742 /**
743  * @brief EMSA-PSS verification operation
744  * @param[in] hash Hash function
745  * @param[in] mgfHash MGF hash function
746  * @param[in] saltLen Length of the salt, in bytes
747  * @param[in] digest Digest of the message to be signed
748  * @param[out] em Encoded message
749  * @param[in] emBits Maximal bit length of the integer OS2IP(EM)
750  * @return Error code
751  **/
752 
753 error_t emsaPssVerify(const HashAlgo *hash, const HashAlgo *mgfHash,
754  size_t saltLen, const uint8_t *digest, uint8_t *em, uint_t emBits)
755 {
756  size_t i;
757  size_t n;
758  size_t emLen;
759  uint8_t bad;
760  uint8_t mask;
761  uint8_t *h;
762  uint8_t *db;
763  uint8_t *salt;
764  uint8_t h2[MAX_HASH_DIGEST_SIZE];
765 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
766  HashContext *hashContext;
767 #else
768  HashContext hashContext[1];
769 #endif
770 
771  //The encoded message is an octet string of length emLen = ceil(emBits / 8)
772  emLen = (emBits + 7) / 8;
773 
774  //Check the length of the encoded message EM
775  if(emLen < (hash->digestSize + saltLen + 2))
776  return ERROR_INVALID_LENGTH;
777 
778 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
779  //Allocate a memory buffer to hold the hash context
780  hashContext = cryptoAllocMem(sizeof(HashContext));
781  //Failed to allocate memory?
782  if(hashContext == NULL)
783  return ERROR_OUT_OF_MEMORY;
784 #endif
785 
786  //If the rightmost octet of EM does not have hexadecimal value 0xbc, output
787  //"inconsistent" and stop
788  bad = em[emLen - 1] ^ 0xBC;
789 
790  //Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and let H be
791  //the next hLen octets
792  db = em;
793  n = emLen - hash->digestSize - 1;
794  h = em + n;
795 
796  //Form a mask
797  mask = 0xFF >> (8 * emLen - emBits);
798 
799  //If the leftmost 8emLen - emBits bits of the leftmost octet in maskedDB are
800  //not all equal to zero, output "inconsistent" and stop
801  bad |= db[0] & ~mask;
802 
803  //Let DB = maskedDB xor MGF(H, emLen - hLen - 1)
804  mgf(mgfHash, hashContext, h, hash->digestSize, db, n);
805 
806  //Set the leftmost 8emLen - emBits bits of the leftmost octet in DB to zero
807  db[0] &= mask;
808 
809  //The padding string PS consists of emLen - sLen - hLen - 2 octets
810  n = emLen - hash->digestSize - saltLen - 2;
811 
812  //If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero, output
813  //"inconsistent" and stop
814  for(i = 0; i < n; i++)
815  {
816  bad |= db[i];
817  }
818 
819  //If the octet at position emLen - hLen - sLen - 1 does not have hexadecimal
820  //value 0x01, output "inconsistent" and stop
821  bad |= db[n] ^ 0x01;
822 
823  //Let salt be the last sLen octets of DB
824  salt = db + n + 1;
825 
826  //Let H' = Hash(00 00 00 00 00 00 00 00 || mHash || salt)
827  hash->init(hashContext);
828  hash->update(hashContext, padding, sizeof(padding));
829  hash->update(hashContext, digest, hash->digestSize);
830  hash->update(hashContext, salt, saltLen);
831  hash->final(hashContext, h2);
832 
833  //If H = H', output "consistent". Otherwise, output "inconsistent"
834  for(i = 0; i < hash->digestSize; i++)
835  {
836  bad |= h[i] ^ h2[i];
837  }
838 
839 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
840  //Release hash context
841  cryptoFreeMem(hashContext);
842 #endif
843 
844  //Verification result
845  return (bad != 0) ? ERROR_INCONSISTENT_VALUE : NO_ERROR;
846 }
847 
848 
849 /**
850  * @brief Mask generation function
851  * @param[in] hash MGF hash function
852  * @param[in] hashContext Hash function context
853  * @param[in] seed Seed from which the mask is generated
854  * @param[in] seedLen Length of the seed in bytes
855  * @param[in,out] data Data block to be masked
856  * @param[in] dataLen Length of the data block in bytes
857  **/
858 
859 void mgf(const HashAlgo *hash, HashContext *hashContext, const uint8_t *seed,
860  size_t seedLen, uint8_t *data, size_t dataLen)
861 {
862 #if (SHAKE128_256_SUPPORT == ENABLED)
863  //SHAKE128 mask generation function?
864  if(hash == SHAKE128_256_HASH_ALGO)
865  {
866  size_t i;
867  size_t j;
868  size_t n;
869  uint8_t mask[16];
870 
871  //In RSASSA-PSS with SHAKEs, the SHAKEs must be used natively as the MGF
872  //(refer to RFC 8692, section 4.1.1)
873  shakeInit(&hashContext->shake128_256Context, 128);
874  shakeAbsorb(&hashContext->shake128_256Context, seed, seedLen);
875  shakeFinal(&hashContext->shake128_256Context);
876 
877  //The MGF outputs an octet string of the desired length
878  for(i = 0; i < dataLen; i += n)
879  {
880  //Number of bytes to generate at a time
881  n = MIN(dataLen - i, sizeof(mask));
882 
883  //Generate the mask
884  shakeSqueeze(&hashContext->shake128_256Context, mask, n);
885 
886  //Apply the mask
887  for(j = 0; j < n; j++)
888  {
889  data[i + j] ^= mask[j];
890  }
891  }
892  }
893  else
894 #endif
895 #if (SHAKE256_512_SUPPORT == ENABLED)
896  //SHAKE256 mask generation function?
897  if(hash == SHAKE256_512_HASH_ALGO)
898  {
899  size_t i;
900  size_t j;
901  size_t n;
902  uint8_t mask[16];
903 
904  //In RSASSA-PSS with SHAKEs, the SHAKEs must be used natively as the MGF
905  //(refer to RFC 8692, section 4.1.1)
906  shakeInit(&hashContext->shake256_512Context, 256);
907  shakeAbsorb(&hashContext->shake256_512Context, seed, seedLen);
908  shakeFinal(&hashContext->shake256_512Context);
909 
910  //The MGF outputs an octet string of the desired length
911  for(i = 0; i < dataLen; i += n)
912  {
913  //Number of bytes to generate at a time
914  n = MIN(dataLen - i, sizeof(mask));
915 
916  //Generate the mask
917  shakeSqueeze(&hashContext->shake256_512Context, mask, n);
918 
919  //Apply the mask
920  for(j = 0; j < n; j++)
921  {
922  data[i + j] ^= mask[j];
923  }
924  }
925  }
926  else
927 #endif
928  //MGF1 mask generation function?
929  {
930  //The MGF1 algorithm uses the hash function in multiple iterations
931  mgf1(hash, hashContext, seed, seedLen, data, dataLen);
932  }
933 }
934 
935 
936 /**
937  * @brief MGF1 mask generation function
938  * @param[in] hash MGF hash function
939  * @param[in] hashContext Hash function context
940  * @param[in] seed Seed from which the mask is generated
941  * @param[in] seedLen Length of the seed in bytes
942  * @param[in,out] data Data block to be masked
943  * @param[in] dataLen Length of the data block in bytes
944  **/
945 
946 void mgf1(const HashAlgo *hash, HashContext *hashContext, const uint8_t *seed,
947  size_t seedLen, uint8_t *data, size_t dataLen)
948 {
949  size_t i;
950  size_t n;
951  uint32_t counter;
952  uint8_t c[4];
953  uint8_t digest[MAX_HASH_DIGEST_SIZE];
954 
955  //The data is processed block by block
956  for(counter = 0; dataLen > 0; counter++)
957  {
958  //Limit the number of bytes to process at a time
959  n = MIN(dataLen, hash->digestSize);
960 
961  //Convert counter to an octet string C of length 4 octets
962  STORE32BE(counter, c);
963 
964  //Calculate Hash(mgfSeed || C)
965  hash->init(hashContext);
966  hash->update(hashContext, seed, seedLen);
967  hash->update(hashContext, c, sizeof(c));
968  hash->final(hashContext, digest);
969 
970  //Apply the mask
971  for(i = 0; i < n; i++)
972  {
973  data[i] ^= digest[i];
974  }
975 
976  //Advance data pointer
977  data += n;
978  dataLen -= n;
979  }
980 }
981 
982 #endif
HashAlgoInit init
Definition: crypto.h:1253
Generic hash algorithm context.
#define CRYPTO_TEST_Z_32(a)
Definition: crypto.h:1099
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
Mpi p
First factor.
Definition: rsa.h:72
const uint8_t * oid
Definition: crypto.h:1245
Arbitrary precision integer.
Definition: mpi.h:102
#define PrngAlgo
Definition: crypto.h:1140
#define CRYPTO_SELECT_32(a, b, c)
Definition: crypto.h:1131
uint8_t p
Definition: ndp.h:300
error_t emeOaepEncode(const PrngAlgo *prngAlgo, void *prngContext, const HashAlgo *hash, const HashAlgo *mgfHash, const char_t *label, size_t labelLen, const uint8_t *message, size_t messageLen, uint8_t *em, size_t k)
EME-OAEP encoding operation.
Definition: rsa_misc.c:333
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
Shake128_256Context shake128_256Context
uint8_t data[]
Definition: ethernet.h:224
size_t digestSize
Definition: crypto.h:1249
HashAlgoUpdate update
Definition: crypto.h:1254
Mpi n
Modulus.
Definition: rsa.h:69
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
error_t emsaPssEncode(const PrngAlgo *prngAlgo, void *prngContext, const HashAlgo *hash, const HashAlgo *mgfHash, size_t saltLen, const uint8_t *digest, uint8_t *em, uint_t emBits)
EMSA-PSS encoding operation.
Definition: rsa_misc.c:662
error_t emsaPssVerify(const HashAlgo *hash, const HashAlgo *mgfHash, size_t saltLen, const uint8_t *digest, uint8_t *em, uint_t emBits)
EMSA-PSS verification operation.
Definition: rsa_misc.c:753
Mpi e
Public exponent.
Definition: rsa.h:59
uint32_t emePkcs1v15Decode(uint8_t *em, size_t k, size_t *messageLen)
EME-PKCS1-v1_5 decoding operation.
Definition: rsa_misc.c:277
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:49
#define CRYPTO_TEST_Z_8(a)
Definition: crypto.h:1027
Mpi d
Private exponent.
Definition: rsa.h:71
#define ASN1_ENCODING_CONSTRUCTED
Definition: asn1.h:48
Mpi n
Modulus.
Definition: rsa.h:58
size_t oidSize
Definition: crypto.h:1246
error_t emePkcs1v15Encode(const PrngAlgo *prngAlgo, void *prngContext, const uint8_t *message, size_t messageLen, uint8_t *em, size_t k)
EME-PKCS1-v1_5 encoding operation.
Definition: rsa_misc.c:209
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1589
#define MAX_HASH_DIGEST_SIZE
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
uint8_t h
Definition: ndp.h:302
error_t emsaPkcs1v15Verify(const HashAlgo *hash, const uint8_t *digest, const uint8_t *em, size_t emLen)
EMSA-PKCS1-v1_5 verification operation.
Definition: rsa_misc.c:585
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t emsaPkcs1v15Encode(const HashAlgo *hash, const uint8_t *digest, uint8_t *em, size_t emLen)
EMSA-PKCS1-v1_5 encoding operation.
Definition: rsa_misc.c:521
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
#define CRYPTO_TEST_NZ_8(a)
Definition: crypto.h:1031
error_t mpiSub(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision subtraction.
Definition: mpi.c:971
error_t
Error codes.
Definition: error.h:43
#define MPI_CHECK(f)
Definition: mpi.h:74
void mgf1(const HashAlgo *hash, HashContext *hashContext, const uint8_t *seed, size_t seedLen, uint8_t *data, size_t dataLen)
MGF1 mask generation function.
Definition: rsa_misc.c:946
error_t mpiAdd(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision addition.
Definition: mpi.c:893
Mpi q
Second factor.
Definition: rsa.h:73
error_t shakeInit(ShakeContext *context, uint_t strength)
Initialize SHAKE context.
Definition: shake.c:187
RSA public key.
Definition: rsa.h:57
#define CRYPTO_TEST_LT_32(a, b)
Definition: crypto.h:1115
#define SHAKE256_512_HASH_ALGO
Definition: shake256_512.h:45
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void shakeAbsorb(ShakeContext *context, const void *input, size_t length)
Absorb data.
Definition: shake.c:241
General definitions for cryptographic algorithms.
void shakeSqueeze(ShakeContext *context, uint8_t *output, size_t length)
Extract data from the squeezing phase.
Definition: shake.c:267
RSA public-key cryptography standard.
uint8_t mask
Definition: web_socket.h:319
error_t rsavp1(const RsaPublicKey *key, const Mpi *s, Mpi *m)
RSA verification primitive.
Definition: rsa_misc.c:189
#define MIN(a, b)
Definition: os_port.h:63
uint32_t dataLen
Definition: sftp_common.h:229
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
HashAlgoFinal final
Definition: crypto.h:1255
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:75
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:189
char char_t
Definition: compiler_port.h:55
Helper routines for RSA.
#define SHAKE128_256_HASH_ALGO
Definition: shake128_256.h:45
__weak_func error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
RSA decryption primitive.
Definition: rsa_misc.c:98
uint8_t m
Definition: ndp.h:304
uint8_t n
RSA private key.
Definition: rsa.h:68
void mgf(const HashAlgo *hash, HashContext *hashContext, const uint8_t *seed, size_t seedLen, uint8_t *data, size_t dataLen)
Mask generation function.
Definition: rsa_misc.c:859
#define cryptoFreeMem(p)
Definition: crypto.h:966
error_t mpiExpModFast(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation (fast calculation)
__weak_func error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
RSA encryption primitive.
Definition: rsa_misc.c:71
#define cryptoAllocMem(size)
Definition: crypto.h:961
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:77
uint8_t s
Definition: igmp_common.h:234
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:83
error_t rsasp1(const RsaPrivateKey *key, const Mpi *m, Mpi *s)
RSA signature primitive.
Definition: rsa_misc.c:168
void shakeFinal(ShakeContext *context)
Finish absorbing phase.
Definition: shake.c:253
Common interface for hash algorithms.
Definition: crypto.h:1243
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:359
Mpi dp
First factor's CRT exponent.
Definition: rsa.h:74
int_t mpiCompInt(const Mpi *a, mpi_sword_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:430
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:141
error_t mpiMulMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular multiplication.
uint32_t emeOaepDecode(const HashAlgo *hash, const HashAlgo *mgfHash, const char_t *label, size_t labelLen, uint8_t *em, size_t k, size_t *messageLen)
EME-OAEP decoding operation.
Definition: rsa_misc.c:424
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define CRYPTO_TEST_NEQ_8(a, b)
Definition: crypto.h:1039
@ ERROR_INCONSISTENT_VALUE
Definition: error.h:124
@ NO_ERROR
Success.
Definition: error.h:44
error_t mpiExpModRegular(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation (regular calculation)
uint8_t c
Definition: ndp.h:514
Shake256_512Context shake256_512Context
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)
@ ASN1_TYPE_NULL
Definition: asn1.h:76
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:65