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-2025 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.5.0
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(!key->n.size || !key->e.size)
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->n) > 0 && mpiGetLength(&key->p) > 0 &&
116  mpiGetLength(&key->q) > 0 && mpiGetLength(&key->dp) > 0 &&
117  mpiGetLength(&key->dq) > 0 && 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->read(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 Underlying hash function
323  * @param[in] label Optional label to be associated with the message
324  * @param[in] message Message to be encrypted
325  * @param[in] messageLen Length of the message to be encrypted
326  * @param[out] em Encoded message
327  * @param[in] k Length of the encoded message
328  * @return Error code
329  **/
330 
331 error_t emeOaepEncode(const PrngAlgo *prngAlgo, void *prngContext,
332  const HashAlgo *hash, const char_t *label, const uint8_t *message,
333  size_t messageLen, uint8_t *em, size_t k)
334 {
335  error_t error;
336  size_t n;
337  uint8_t *db;
338  uint8_t *seed;
339 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
340  HashContext *hashContext;
341 #else
342  HashContext hashContext[1];
343 #endif
344 
345  //Check the length of the message
346  if(messageLen > (k - 2 * hash->digestSize - 2))
347  return ERROR_INVALID_LENGTH;
348 
349  //Point to the buffer where to format the seed
350  seed = em + 1;
351  //Point to the buffer where to format the data block
352  db = em + hash->digestSize + 1;
353 
354  //Generate a random octet string seed of length hLen
355  error = prngAlgo->read(prngContext, seed, hash->digestSize);
356  //Any error to report?
357  if(error)
358  return error;
359 
360 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
361  //Allocate a memory buffer to hold the hash context
362  hashContext = cryptoAllocMem(hash->contextSize);
363  //Failed to allocate memory?
364  if(hashContext == NULL)
365  return ERROR_OUT_OF_MEMORY;
366 #endif
367 
368  //If the label L is not provided, let L be the empty string
369  if(label == NULL)
370  {
371  label = "";
372  }
373 
374  //Let lHash = Hash(L)
375  hash->init(hashContext);
376  hash->update(hashContext, label, osStrlen(label));
377  hash->final(hashContext, db);
378 
379  //The padding string PS consists of k - mLen - 2hLen - 2 zero octets
380  n = k - messageLen - 2 * hash->digestSize - 2;
381  //Generate the padding string
382  osMemset(db + hash->digestSize, 0, n);
383 
384  //Concatenate lHash, PS, a single octet with hexadecimal value 0x01, and
385  //the message M to form a data block DB of length k - hLen - 1 octets
386  db[hash->digestSize + n] = 0x01;
387  osMemcpy(db + hash->digestSize + n + 1, message, messageLen);
388 
389  //Calculate the length of the data block
390  n = k - hash->digestSize - 1;
391 
392  //Let maskedDB = DB xor MGF(seed, k - hLen - 1)
393  mgf1(hash, hashContext, seed, hash->digestSize, db, n);
394  //Let maskedSeed = seed xor MGF(maskedDB, hLen)
395  mgf1(hash, hashContext, db, n, seed, hash->digestSize);
396 
397  //Concatenate a single octet with hexadecimal value 0x00, maskedSeed, and
398  //maskedDB to form an encoded message EM of length k octets
399  em[0] = 0x00;
400 
401 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
402  //Release hash context
403  cryptoFreeMem(hashContext);
404 #endif
405 
406  //Successful processing
407  return NO_ERROR;
408 }
409 
410 
411 /**
412  * @brief EME-OAEP decoding operation
413  * @param[in] hash Underlying hash function
414  * @param[in] label Optional label to be associated with the message
415  * @param[in] em Encoded message
416  * @param[in] k Length of the encoded message
417  * @param[out] messageLen Length of the decrypted message
418  * @return The function returns 0 on success, 1 on failure
419  **/
420 
421 uint32_t emeOaepDecode(const HashAlgo *hash, const char_t *label, uint8_t *em,
422  size_t k, size_t *messageLen)
423 {
424  size_t i;
425  size_t m;
426  size_t n;
427  uint32_t c;
428  uint32_t bad;
429  uint8_t *db;
430  uint8_t *seed;
431  uint8_t lHash[MAX_HASH_DIGEST_SIZE];
432 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
433  HashContext *hashContext;
434 #else
435  HashContext hashContext[1];
436 #endif
437 
438 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
439  //Allocate a memory buffer to hold the hash context
440  hashContext = cryptoAllocMem(hash->contextSize);
441  //Failed to allocate memory?
442  if(hashContext == NULL)
443  return TRUE;
444 #endif
445 
446  //If the label L is not provided, let L be the empty string
447  if(label == NULL)
448  {
449  label = "";
450  }
451 
452  //Let lHash = Hash(L)
453  hash->init(hashContext);
454  hash->update(hashContext, label, osStrlen(label));
455  hash->final(hashContext, lHash);
456 
457  //Separate the encoded message EM into a single octet Y, an octet string
458  //maskedSeed of length hLen, and an octet string maskedDB of length k - hLen - 1
459  seed = em + 1;
460  db = em + hash->digestSize + 1;
461 
462  //Calculate the length of the data block
463  n = k - hash->digestSize - 1;
464 
465  //Let seed = maskedSeed xor MGF(maskedDB, hLen)
466  mgf1(hash, hashContext, db, n, seed, hash->digestSize);
467  //Let DB = maskedDB xor MGF(seed, k - hLen - 1)
468  mgf1(hash, hashContext, seed, hash->digestSize, db, n);
469 
470 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
471  //Release hash context
472  cryptoFreeMem(hashContext);
473 #endif
474 
475  //Separate DB into an octet string lHash' of length hLen, a padding string
476  //PS consisting of octets with hexadecimal value 0x00, and a message M
477  for(m = 0, i = hash->digestSize; i < n; i++)
478  {
479  //Constant time implementation
480  c = CRYPTO_TEST_NZ_8(db[i]);
481  c &= CRYPTO_TEST_Z_32(m);
482  m = CRYPTO_SELECT_32(m, i, c);
483  }
484 
485  //Make sure the padding string PS is terminated
486  bad = CRYPTO_TEST_Z_32(m);
487 
488  //If there is no octet with hexadecimal value 0x01 to separate PS from M,
489  //then report a decryption error
490  bad |= CRYPTO_TEST_NEQ_8(db[m], 0x01);
491 
492  //If lHash does not equal lHash', then report a decryption error
493  for(i = 0; i < hash->digestSize; i++)
494  {
495  bad |= CRYPTO_TEST_NEQ_8(db[i], lHash[i]);
496  }
497 
498  //If Y is nonzero, then report a decryption error
499  bad |= CRYPTO_TEST_NEQ_8(em[0], 0x00);
500 
501  //Return the length of the decrypted message
502  *messageLen = CRYPTO_SELECT_32(n - m - 1, 0, bad);
503 
504  //Care must be taken to ensure that an opponent cannot distinguish the
505  //different error conditions, whether by error message or timing
506  return bad;
507 }
508 
509 
510 /**
511  * @brief EMSA-PKCS1-v1_5 encoding operation
512  * @param[in] hash Hash function used to digest the message
513  * @param[in] digest Digest of the message to be signed
514  * @param[out] em Encoded message
515  * @param[in] emLen Intended length of the encoded message
516  * @return Error code
517  **/
518 
520  const uint8_t *digest, uint8_t *em, size_t emLen)
521 {
522  size_t i;
523  size_t n;
524 
525  //Check the intended length of the encoded message
526  if(emLen < (hash->oidSize + hash->digestSize + 21))
527  return ERROR_INVALID_LENGTH;
528 
529  //Point to the first byte of the encoded message
530  i = 0;
531 
532  //The leading 0x00 octet ensures that the encoded message, converted to
533  //an integer, is less than the modulus
534  em[i++] = 0x00;
535  //Block type 0x01 is used for private-key operations
536  em[i++] = 0x01;
537 
538  //Determine the length of the padding string PS
539  n = emLen - hash->oidSize - hash->digestSize - 13;
540 
541  //Each byte of PS must be set to 0xFF when the block type is 0x01
542  osMemset(em + i, 0xFF, n);
543  i += n;
544 
545  //Append a 0x00 octet to the padding string
546  em[i++] = 0x00;
547 
548  //Encode the DigestInfo structure using ASN.1
549  em[i++] = (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
550  em[i++] = (uint8_t) (hash->oidSize + hash->digestSize + 8);
551  em[i++] = (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
552  em[i++] = (uint8_t) (hash->oidSize + 4);
553  em[i++] = (uint8_t) ASN1_TYPE_OBJECT_IDENTIFIER;
554  em[i++] = (uint8_t) hash->oidSize;
555 
556  //Copy the hash algorithm OID
557  osMemcpy(em + i, hash->oid, hash->oidSize);
558  i += hash->oidSize;
559 
560  //Encode the rest of the ASN.1 structure
561  em[i++] = (uint8_t) ASN1_TYPE_NULL;
562  em[i++] = 0;
563  em[i++] = (uint8_t) ASN1_TYPE_OCTET_STRING;
564  em[i++] = (uint8_t) hash->digestSize;
565 
566  //Append the hash value
567  osMemcpy(em + i, digest, hash->digestSize);
568 
569  //Successful processing
570  return NO_ERROR;
571 }
572 
573 
574 /**
575  * @brief EMSA-PKCS1-v1_5 verification operation
576  * @param[in] hash Hash function
577  * @param[in] digest Digest value
578  * @param[in] em Encoded message
579  * @param[in] emLen Length of the encoded message
580  * @return Error code
581  **/
582 
583 error_t emsaPkcs1v15Verify(const HashAlgo *hash, const uint8_t *digest,
584  const uint8_t *em, size_t emLen)
585 {
586  size_t i;
587  size_t j;
588  size_t n;
589  uint8_t bad;
590 
591  //Check the length of the encoded message
592  if(emLen < (hash->oidSize + hash->digestSize + 21))
593  return ERROR_INVALID_LENGTH;
594 
595  //Point to the first byte of the encoded message
596  i = 0;
597 
598  //The first octet of EM must have hexadecimal value 0x00
599  bad = em[i++];
600  //The second octet of EM must have hexadecimal value 0x01
601  bad |= em[i++] ^ 0x01;
602 
603  //Determine the length of the padding string PS
604  n = emLen - hash->oidSize - hash->digestSize - 13;
605 
606  //Each byte of PS must be set to 0xFF when the block type is 0x01
607  for(j = 0; j < n; j++)
608  {
609  bad |= em[i++] ^ 0xFF;
610  }
611 
612  //The padding string must be followed by a 0x00 octet
613  bad |= em[i++];
614 
615  //Check the ASN.1 syntax of the DigestInfo structure
616  bad |= em[i++] ^ (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
617  bad |= em[i++] ^ (uint8_t) (hash->oidSize + hash->digestSize + 8);
618  bad |= em[i++] ^ (uint8_t) (ASN1_ENCODING_CONSTRUCTED | ASN1_TYPE_SEQUENCE);
619  bad |= em[i++] ^ (uint8_t) (hash->oidSize + 4);
620  bad |= em[i++] ^ (uint8_t) ASN1_TYPE_OBJECT_IDENTIFIER;
621  bad |= em[i++] ^ (uint8_t) hash->oidSize;
622 
623  //Verify the hash algorithm OID
624  for(j = 0; j < hash->oidSize; j++)
625  {
626  bad |= em[i++] ^ hash->oid[j];
627  }
628 
629  //Check the rest of the ASN.1 structure
630  bad |= em[i++] ^ (uint8_t) ASN1_TYPE_NULL;
631  bad |= em[i++];
632  bad |= em[i++] ^ (uint8_t) ASN1_TYPE_OCTET_STRING;
633  bad |= em[i++] ^ (uint8_t) hash->digestSize;
634 
635  //Recover the underlying hash value, and then compare it to the newly
636  //computed hash value
637  for(j = 0; j < hash->digestSize; j++)
638  {
639  bad |= em[i++] ^ digest[j];
640  }
641 
642  //Verification result
643  return (bad != 0) ? ERROR_INCONSISTENT_VALUE : NO_ERROR;
644 }
645 
646 
647 /**
648  * @brief EMSA-PSS encoding operation
649  * @param[in] prngAlgo PRNG algorithm
650  * @param[in] prngContext Pointer to the PRNG context
651  * @param[in] hash Underlying hash function
652  * @param[in] saltLen Length of the salt, in bytes
653  * @param[in] digest Digest of the message to be signed
654  * @param[out] em Encoded message
655  * @param[in] emBits Maximal bit length of the integer OS2IP(EM)
656  * @return Error code
657  **/
658 
659 error_t emsaPssEncode(const PrngAlgo *prngAlgo, void *prngContext,
660  const HashAlgo *hash, size_t saltLen, const uint8_t *digest,
661  uint8_t *em, uint_t emBits)
662 {
663  error_t error;
664  size_t n;
665  size_t emLen;
666  uint8_t *db;
667  uint8_t *salt;
668  uint8_t h[MAX_HASH_DIGEST_SIZE];
669 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
670  HashContext *hashContext;
671 #else
672  HashContext hashContext[1];
673 #endif
674 
675  //The encoded message is an octet string of length emLen = ceil(emBits / 8)
676  emLen = (emBits + 7) / 8;
677 
678  //If emLen < hLen + sLen + 2, output "encoding error" and stop
679  if(emLen < (hash->digestSize + saltLen + 2))
680  return ERROR_INVALID_LENGTH;
681 
682  //The padding string PS consists of emLen - sLen - hLen - 2 zero octets
683  n = emLen - saltLen - hash->digestSize - 2;
684 
685  //Point to the buffer where to format the data block DB
686  db = em;
687  //Point to the buffer where to generate the salt
688  salt = db + n + 1;
689 
690  //Generate a random octet string salt of length sLen
691  error = prngAlgo->read(prngContext, salt, saltLen);
692  //Any error to report?
693  if(error)
694  return error;
695 
696 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
697  //Allocate a memory buffer to hold the hash context
698  hashContext = cryptoAllocMem(hash->contextSize);
699  //Failed to allocate memory?
700  if(hashContext == NULL)
701  return ERROR_OUT_OF_MEMORY;
702 #endif
703 
704  //Let H = Hash(00 00 00 00 00 00 00 00 || mHash || salt)
705  hash->init(hashContext);
706  hash->update(hashContext, padding, sizeof(padding));
707  hash->update(hashContext, digest, hash->digestSize);
708  hash->update(hashContext, salt, saltLen);
709  hash->final(hashContext, h);
710 
711  //Let DB = PS || 0x01 || salt
712  osMemset(db, 0, n);
713  db[n] = 0x01;
714 
715  //Calculate the length of the data block
716  n += saltLen + 1;
717 
718  //Let maskedDB = DB xor MGF(H, emLen - hLen - 1)
719  mgf1(hash, hashContext, h, hash->digestSize, db, n);
720 
721  //Set the leftmost 8emLen - emBits bits of the leftmost octet in maskedDB
722  //to zero
723  db[0] &= 0xFF >> (8 * emLen - emBits);
724 
725  //Let EM = maskedDB || H || 0xbc
726  osMemcpy(em + n, h, hash->digestSize);
727  em[n + hash->digestSize] = 0xBC;
728 
729 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
730  //Release hash context
731  cryptoFreeMem(hashContext);
732 #endif
733 
734  //Successful processing
735  return NO_ERROR;
736 }
737 
738 
739 /**
740  * @brief EMSA-PSS verification operation
741  * @param[in] hash Underlying hash function
742  * @param[in] saltLen Length of the salt, in bytes
743  * @param[in] digest Digest of the message to be signed
744  * @param[out] em Encoded message
745  * @param[in] emBits Maximal bit length of the integer OS2IP(EM)
746  * @return Error code
747  **/
748 
749 error_t emsaPssVerify(const HashAlgo *hash, size_t saltLen,
750  const uint8_t *digest, uint8_t *em, uint_t emBits)
751 {
752  size_t i;
753  size_t n;
754  size_t emLen;
755  uint8_t bad;
756  uint8_t mask;
757  uint8_t *h;
758  uint8_t *db;
759  uint8_t *salt;
760  uint8_t h2[MAX_HASH_DIGEST_SIZE];
761 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
762  HashContext *hashContext;
763 #else
764  HashContext hashContext[1];
765 #endif
766 
767  //The encoded message is an octet string of length emLen = ceil(emBits / 8)
768  emLen = (emBits + 7) / 8;
769 
770  //Check the length of the encoded message EM
771  if(emLen < (hash->digestSize + saltLen + 2))
772  return ERROR_INVALID_LENGTH;
773 
774 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
775  //Allocate a memory buffer to hold the hash context
776  hashContext = cryptoAllocMem(hash->contextSize);
777  //Failed to allocate memory?
778  if(hashContext == NULL)
779  return ERROR_OUT_OF_MEMORY;
780 #endif
781 
782  //If the rightmost octet of EM does not have hexadecimal value 0xbc, output
783  //"inconsistent" and stop
784  bad = em[emLen - 1] ^ 0xBC;
785 
786  //Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and let H be
787  //the next hLen octets
788  db = em;
789  n = emLen - hash->digestSize - 1;
790  h = em + n;
791 
792  //Form a mask
793  mask = 0xFF >> (8 * emLen - emBits);
794 
795  //If the leftmost 8emLen - emBits bits of the leftmost octet in maskedDB are
796  //not all equal to zero, output "inconsistent" and stop
797  bad |= db[0] & ~mask;
798 
799  //Let DB = maskedDB xor MGF(H, emLen - hLen - 1)
800  mgf1(hash, hashContext, h, hash->digestSize, db, n);
801 
802  //Set the leftmost 8emLen - emBits bits of the leftmost octet in DB to zero
803  db[0] &= mask;
804 
805  //The padding string PS consists of emLen - sLen - hLen - 2 octets
806  n = emLen - hash->digestSize - saltLen - 2;
807 
808  //If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero, output
809  //"inconsistent" and stop
810  for(i = 0; i < n; i++)
811  {
812  bad |= db[i];
813  }
814 
815  //If the octet at position emLen - hLen - sLen - 1 does not have hexadecimal
816  //value 0x01, output "inconsistent" and stop
817  bad |= db[n] ^ 0x01;
818 
819  //Let salt be the last sLen octets of DB
820  salt = db + n + 1;
821 
822  //Let H' = Hash(00 00 00 00 00 00 00 00 || mHash || salt)
823  hash->init(hashContext);
824  hash->update(hashContext, padding, sizeof(padding));
825  hash->update(hashContext, digest, hash->digestSize);
826  hash->update(hashContext, salt, saltLen);
827  hash->final(hashContext, h2);
828 
829  //If H = H', output "consistent". Otherwise, output "inconsistent"
830  for(i = 0; i < hash->digestSize; i++)
831  {
832  bad |= h[i] ^ h2[i];
833  }
834 
835 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
836  //Release hash context
837  cryptoFreeMem(hashContext);
838 #endif
839 
840  //Verification result
841  return (bad != 0) ? ERROR_INCONSISTENT_VALUE : NO_ERROR;
842 }
843 
844 
845 /**
846  * @brief MGF1 mask generation function
847  * @param[in] hash Hash function
848  * @param[in] hashContext Hash function context
849  * @param[in] seed Seed from which the mask is generated
850  * @param[in] seedLen Length of the seed in bytes
851  * @param[in,out] data Data block to be masked
852  * @param[in] dataLen Length of the data block in bytes
853  **/
854 
855 void mgf1(const HashAlgo *hash, HashContext *hashContext, const uint8_t *seed,
856  size_t seedLen, uint8_t *data, size_t dataLen)
857 {
858  size_t i;
859  size_t n;
860  uint32_t counter;
861  uint8_t c[4];
862  uint8_t digest[MAX_HASH_DIGEST_SIZE];
863 
864  //The data is processed block by block
865  for(counter = 0; dataLen > 0; counter++)
866  {
867  //Limit the number of bytes to process at a time
868  n = MIN(dataLen, hash->digestSize);
869 
870  //Convert counter to an octet string C of length 4 octets
871  STORE32BE(counter, c);
872 
873  //Calculate Hash(mgfSeed || C)
874  hash->init(hashContext);
875  hash->update(hashContext, seed, seedLen);
876  hash->update(hashContext, c, sizeof(c));
877  hash->final(hashContext, digest);
878 
879  //Apply the mask
880  for(i = 0; i < n; i++)
881  {
882  data[i] ^= digest[i];
883  }
884 
885  //Advance data pointer
886  data += n;
887  dataLen -= n;
888  }
889 }
890 
891 #endif
HashAlgoInit init
Definition: crypto.h:1092
Generic hash algorithm context.
#define CRYPTO_TEST_Z_32(a)
Definition: crypto.h:932
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
Mpi p
First factor.
Definition: rsa.h:72
const uint8_t * oid
Definition: crypto.h:1084
Arbitrary precision integer.
Definition: mpi.h:102
#define PrngAlgo
Definition: crypto.h:973
#define CRYPTO_SELECT_32(a, b, c)
Definition: crypto.h:964
uint8_t p
Definition: ndp.h:300
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
size_t digestSize
Definition: crypto.h:1088
HashAlgoUpdate update
Definition: crypto.h:1093
Mpi n
Modulus.
Definition: rsa.h:69
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
Mpi e
Public exponent.
Definition: rsa.h:59
#define osStrlen(s)
Definition: os_port.h:168
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:48
#define CRYPTO_TEST_Z_8(a)
Definition: crypto.h:860
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 contextSize
Definition: crypto.h:1086
size_t oidSize
Definition: crypto.h:1085
error_t emsaPssEncode(const PrngAlgo *prngAlgo, void *prngContext, const HashAlgo *hash, size_t saltLen, const uint8_t *digest, uint8_t *em, uint_t emBits)
EMSA-PSS encoding operation.
Definition: rsa_misc.c:659
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:1587
#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:583
@ 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:519
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
#define CRYPTO_TEST_NZ_8(a)
Definition: crypto.h:864
error_t mpiSub(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision subtraction.
Definition: mpi.c:969
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:855
error_t mpiAdd(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision addition.
Definition: mpi.c:891
Mpi q
Second factor.
Definition: rsa.h:73
RSA public key.
Definition: rsa.h:57
#define CRYPTO_TEST_LT_32(a, b)
Definition: crypto.h:948
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
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
error_t emeOaepEncode(const PrngAlgo *prngAlgo, void *prngContext, const HashAlgo *hash, const char_t *label, const uint8_t *message, size_t messageLen, uint8_t *em, size_t k)
EME-OAEP encoding operation.
Definition: rsa_misc.c:331
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
HashAlgoFinal final
Definition: crypto.h:1094
@ ASN1_TYPE_OCTET_STRING
Definition: asn1.h:72
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:188
char char_t
Definition: compiler_port.h:55
Helper routines for RSA.
__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
uint_t size
Definition: mpi.h:104
#define cryptoFreeMem(p)
Definition: crypto.h:826
error_t emsaPssVerify(const HashAlgo *hash, size_t saltLen, const uint8_t *digest, uint8_t *em, uint_t emBits)
EMSA-PSS verification operation.
Definition: rsa_misc.c:749
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:821
@ ASN1_TYPE_OBJECT_IDENTIFIER
Definition: asn1.h:74
uint8_t s
Definition: igmp_common.h:234
@ ASN1_TYPE_SEQUENCE
Definition: asn1.h:80
error_t rsasp1(const RsaPrivateKey *key, const Mpi *m, Mpi *s)
RSA signature primitive.
Definition: rsa_misc.c:168
Common interface for hash algorithms.
Definition: crypto.h:1082
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:358
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:429
uint32_t emeOaepDecode(const HashAlgo *hash, const char_t *label, uint8_t *em, size_t k, size_t *messageLen)
EME-OAEP decoding operation.
Definition: rsa_misc.c:421
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
error_t mpiMulMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular multiplication.
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define CRYPTO_TEST_NEQ_8(a, b)
Definition: crypto.h:872
@ 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
Debugging facilities.
ASN.1 (Abstract Syntax Notation One)
@ ASN1_TYPE_NULL
Definition: asn1.h:73
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64