Embedded SDK
Embedded SDK
cx_pkcs1.c
Go to the documentation of this file.
1 
2 /*******************************************************************************
3  * Ledger Nano S - Secure firmware
4  * (c) 2022 Ledger
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  ********************************************************************************/
18 
19 #ifdef HAVE_RSA
20 
21 #include "cx_rsa.h"
22 #include "cx_ram.h"
23 #include "cx_utils.h"
24 #include "errors.h"
25 #include "exceptions.h"
26 #include "lcx_rng.h"
27 
28 #include <string.h>
29 
30 #ifdef HAVE_RSA
31 
32 /* ----------------------------------------------------------------------- */
33 /* */
34 /* ----------------------------------------------------------------------- */
35 
36 // clang-format off
37 #if defined(HAVE_SHA224)
38 /* sha224 OID */
39 const uint8_t C_cx_oid_sha224[CX_OID_SHA224_LENGTH] = {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
40  0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c};
41 #endif // HAVE_SHA224
42 
43 #if defined(HAVE_SHA256)
44 /* sha256 OID */
45 const uint8_t C_cx_oid_sha256[CX_OID_SHA256_LENGTH] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
46  0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
47 #endif // HAVE_SHA256
48 
49 #if defined(HAVE_SHA384)
50 /* sha384 OID */
51 const uint8_t C_cx_oid_sha384[CX_OID_SHA384_LENGTH] = {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
52  0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30};
53 #endif // HAVE_SHA384
54 
55 #if defined(HAVE_SHA512)
56 /* sha512 OID */
57 const uint8_t C_cx_oid_sha512[CX_OID_SHA512_LENGTH] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
58  0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
59 #endif // HAVE_SHA512
60 
61 #if defined(HAVE_SHA3)
62 /* sha3-256 OID */
63 const uint8_t C_cx_oid_sha3_256[CX_OID_SHA3_256_LENGTH]
64  = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
65  0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20};
66 
67 /* sha3-512 OID */
68 const uint8_t C_cx_oid_sha3_512[CX_OID_SHA3_512_LENGTH]
69  = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
70  0x65, 0x03, 0x04, 0x02, 0x0a, 0x05, 0x00, 0x04, 0x40};
71 #endif // HAVE_SHA3
72 // clang-format on
73 
74 size_t cx_pkcs1_get_hash_len(cx_md_t hID)
75 {
76  switch (hID) {
77 #if defined(HAVE_SHA224)
78  case CX_SHA224:
79  return 224 / 8;
80 #endif // HAVE_SHA224
81 
82 #if defined(HAVE_SHA256)
83  case CX_SHA256:
84  return 256 / 8;
85 #endif // HAVE_SHA256
86 
87 #if defined(HAVE_SHA384)
88  case CX_SHA384:
89  return 384 / 8;
90 #endif // HAVE_SHA384
91 
92 #if defined(HAVE_SHA512)
93  case CX_SHA512:
94  return 512 / 8;
95 #endif // HAVE_SHA512
96 
97 #if defined(HAVE_SHA3)
98  case CX_SHA3_256:
99  return 256 / 8;
100 
101  case CX_SHA3_512:
102  return 512 / 8;
103 #endif // HAVE_SHA3
104 
105  default:
106  break;
107  }
108  return 0;
109 }
110 
111 static const uint8_t *cx_pkcs1_get_hash_oid(cx_md_t hID, size_t *len)
112 {
113  switch (hID) {
114 #if defined(HAVE_SHA224)
115  case CX_SHA224:
116  *len = sizeof(C_cx_oid_sha224);
117  return C_cx_oid_sha224;
118 #endif // HAVE_SHA224
119 
120 #if defined(HAVE_SHA256)
121  case CX_SHA256:
122  *len = sizeof(C_cx_oid_sha256);
123  return C_cx_oid_sha256;
124 #endif // HAVE_SHA256
125 
126 #if defined(HAVE_SHA384)
127  case CX_SHA384:
128  *len = sizeof(C_cx_oid_sha384);
129  return C_cx_oid_sha384;
130 #endif // HAVE_SHA384
131 
132 #if defined(HAVE_SHA512)
133  case CX_SHA512:
134  *len = sizeof(C_cx_oid_sha512);
135  return C_cx_oid_sha512;
136 #endif // HAVE_SHA512
137 
138 #if defined(HAVE_SHA3)
139  case CX_SHA3_256:
140  *len = sizeof(C_cx_oid_sha3_256);
141  return C_cx_oid_sha3_256;
142 
143  case CX_SHA3_512:
144  *len = sizeof(C_cx_oid_sha3_512);
145  return C_cx_oid_sha3_512;
146 #endif // HAVE_SHA3
147 
148  default:
149  break;
150  }
151  *len = 0;
152  return NULL;
153 }
154 
155 #ifdef _CX_PKCS1_CONST_SEED_SALT
156 static const uint8_t C_cx_pkcs_salt[]
157  = {'T', 'h', 'e', 'S', 'a', 'l', 't', ' ', 'T', 'h', 'e', 'S', 'a', 'l', 't', ' ',
158  'T', 'h', 'e', 'S', 'a', 'l', 't', ' ', 'T', 'h', 'e', 'S', 'a', 'l', 't', ' '};
159 #endif
160 
161 static const uint8_t C_cx_pss_zeros[] = {0, 0, 0, 0, 0, 0, 0, 0};
162 
163 // We only support the empty string label, defined as default.
164 // The following arrays are the corresponding hash applied to this empty string label.
165 #if defined(HAVE_SHA224)
166 static const uint8_t C_cx_oeap_sha224_[]
167  = {0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82,
168  0x34, 0xc4, 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, 0x2f};
169 #endif // HAVE_SHA224
170 
171 #if defined(HAVE_SHA256)
172 static const uint8_t C_cx_oeap_sha256_[] = {
173  0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
174  0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
175 };
176 #endif // HAVE_SHA256
177 
178 #if defined(HAVE_SHA384)
179 static const uint8_t C_cx_oeap_sha384_[] = {
180  0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a,
181  0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda,
182  0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b};
183 #endif // HAVE_SHA384
184 
185 #if defined(HAVE_SHA512)
186 static const uint8_t C_cx_oeap_sha512_[] = {
187  0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
188  0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
189  0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
190  0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e};
191 #endif // HAVE_SHA512
192 
193 static const uint8_t *cx_pkcs1_get_hash_oeap(cx_md_t hID, size_t *len)
194 {
195  switch (hID) {
196 #if defined(HAVE_SHA224)
197  case CX_SHA224:
198  *len = sizeof(C_cx_oeap_sha224_);
199  return C_cx_oeap_sha224_;
200 #endif // HAVE_SHA224
201 
202 #if defined(HAVE_SHA256)
203  case CX_SHA256:
204  *len = sizeof(C_cx_oeap_sha256_);
205  return C_cx_oeap_sha256_;
206 #endif // HAVE_SHA256
207 
208 #if defined(HAVE_SHA384)
209  case CX_SHA384:
210  *len = sizeof(C_cx_oeap_sha384_);
211  return C_cx_oeap_sha384_;
212 #endif // HAVE_SHA384
213 
214 #if defined(HAVE_SHA512)
215  case CX_SHA512:
216  *len = sizeof(C_cx_oeap_sha512_);
217  return C_cx_oeap_sha512_;
218 #endif // HAVE_SHA512
219 
220  default:
221  break;
222  }
223  *len = 0;
224  return NULL;
225 }
226 
227 static cx_err_t cx_pkcs1_MGF1(cx_md_t hID,
228  uint8_t *seed,
229  size_t seed_len,
230  uint8_t *out,
231  size_t out_len)
232 {
233  size_t hLen;
234  size_t round_len;
235  uint8_t counter[4] = {0};
236  cx_hash_t *hash_ctx = &G_cx.pkcs1.hash_ctx.hash;
237  cx_err_t error = CX_OK;
238 
239  if (hID != CX_SHA224 && hID != CX_SHA256 && hID != CX_SHA384 && hID != CX_SHA512
240  && hID != CX_SHA3_256 && hID != CX_SHA3_512) {
241  return CX_INVALID_PARAMETER;
242  }
243  hLen = cx_pkcs1_get_hash_len(hID);
244 
245  while (out_len) {
246  round_len = (out_len < hLen) ? out_len : hLen;
247 
248  CX_CHECK(cx_hash_init_ex(hash_ctx, hID, hLen));
249  CX_CHECK(cx_hash_update(hash_ctx, seed, seed_len));
250  CX_CHECK(cx_hash_update(hash_ctx, counter, 4));
251  CX_CHECK(cx_hash_final(hash_ctx, G_cx.pkcs1.digest));
252 
253  memcpy(out, G_cx.pkcs1.digest, round_len);
254  out_len -= round_len;
255  out += round_len;
256  counter[3]++;
257  if (counter[3] == 0) {
258  counter[2]++;
259  }
260  }
261 end:
262  return error;
263 }
264 
265 /* ----------------------------------------------------------------------- */
266 /* EMSA: pkcs1 V1.5 */
267 /* ----------------------------------------------------------------------- */
268 
269 /*
270  * message: at ptr+size-msg_size
271  */
272 cx_err_t cx_pkcs1_emsa_v1o5_encode(cx_md_t hID,
273  uint8_t *em,
274  size_t emLen,
275  const uint8_t *mHash,
276  size_t mHashLen)
277 {
278  size_t PSLen;
279  size_t oid_len;
280  const uint8_t *oid;
281 
282  oid = cx_pkcs1_get_hash_oid(hID, &oid_len);
283  if (oid == NULL) {
284  return CX_INVALID_PARAMETER;
285  }
286 
287  if ((3 + oid_len + mHashLen) >= emLen) {
288  return CX_INVALID_PARAMETER;
289  }
290  PSLen = emLen - (3 + oid_len + mHashLen);
291 
292  memcpy(em + 2 + PSLen + 1 + oid_len, mHash, mHashLen);
293  memcpy(em + 2 + PSLen + 1, oid, oid_len);
294  em[0] = 0;
295  em[1] = 1;
296  memset(em + 2, 0xFF, PSLen);
297  em[2 + PSLen] = 0;
298 
299  return CX_OK;
300 }
301 
307 bool cx_pkcs1_emsa_v1o5_verify(cx_md_t hID,
308  uint8_t *em,
309  size_t emLen,
310  const uint8_t *mHash,
311  size_t mHashLen)
312 {
313  size_t PSLen;
314  size_t i;
315  size_t oid_len;
316  const uint8_t *oid;
317 
318  oid = cx_pkcs1_get_hash_oid(hID, &oid_len);
319  if (oid == NULL) {
320  return false;
321  }
322 
323  if ((3 + oid_len + mHashLen) >= emLen) {
324  return false;
325  }
326  PSLen = emLen - (3 + oid_len + mHashLen);
327 
328  // -> check 00 01 ... 00
329  if ((em[0]) || (em[1] != 1) || (em[2 + PSLen] != 0)) {
330  return 0;
331  }
332  // -> check .. .. FFFFFF ..
333  for (i = 2 + PSLen - 1; i >= 2; i--) {
334  if (em[i] != 0xFF) {
335  return false;
336  }
337  }
338  // check OID / hash
339  if (memcmp(em + 2 + PSLen + 1, oid, oid_len) != 0
340  || memcmp(em + 2 + PSLen + 1 + oid_len, mHash, mHashLen) != 0) {
341  return false;
342  }
343 
344  // OKAY
345  return true;
346 }
347 
348 /* ----------------------------------------------------------------------- */
349 /* EMSA: pkcs1 PSS */
350 /* ----------------------------------------------------------------------- */
351 static uint8_t const CX_PSS_MASK[] = {0, 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1};
352 
353 cx_err_t cx_pkcs1_emsa_pss_encode_with_salt_len(cx_md_t hID,
354  uint8_t *em,
355  size_t emBits,
356  const uint8_t *mHash,
357  size_t mHashLen,
358  size_t mSaltLen,
359  size_t *size)
360 {
361  uint8_t salt[64];
362  size_t hLen;
363  size_t mDBlen;
364  size_t PSLen;
365  size_t emLen;
366  cx_hash_t *hash_ctx = &G_cx.pkcs1.hash_ctx.hash;
367  cx_err_t error;
368 
369  if (hID != CX_SHA224 && hID != CX_SHA256 && hID != CX_SHA384 && hID != CX_SHA512) {
370  return CX_INVALID_PARAMETER;
371  }
372 
373  hLen = cx_pkcs1_get_hash_len(hID);
374  emLen = (emBits + 7) / 8;
375 
376  if ((1 + hLen) >= emLen) {
377  return CX_INVALID_PARAMETER;
378  }
379  mDBlen = emLen - (1 + hLen);
380 
381  if ((hLen + mSaltLen + 2) >= emLen) {
382  return CX_INVALID_PARAMETER;
383  }
384  PSLen = emLen - (mSaltLen + hLen + 2);
385 
386 #ifndef _CX_PKCS1_CONST_SEED_SALT
387  cx_rng_no_throw(salt, mSaltLen);
388 #endif
389 
390  CX_CHECK(cx_hash_init_ex(hash_ctx, hID, hLen));
391  CX_CHECK(cx_hash_update(hash_ctx, C_cx_pss_zeros, 8));
392  CX_CHECK(cx_hash_update(hash_ctx, mHash, mHashLen));
393  CX_CHECK(cx_hash_update(hash_ctx, salt, mSaltLen));
394  CX_CHECK(cx_hash_final(hash_ctx, em + mDBlen));
395 
396  em[emLen - 1] = 0xbc;
397  CX_CHECK(cx_pkcs1_MGF1(hID, em + mDBlen, hLen, em, mDBlen));
398  em[PSLen] ^= 1;
399  cx_memxor(em + PSLen + 1, salt, mSaltLen);
400  em[0] &= CX_PSS_MASK[8 * emLen - emBits];
401  *size = emLen;
402  explicit_bzero(&G_cx.pkcs1, sizeof(cx_pkcs1_t));
403 end:
404  return error;
405 }
406 
407 cx_err_t cx_pkcs1_emsa_pss_encode(cx_md_t hID,
408  uint8_t *em,
409  size_t emBits,
410  const uint8_t *mHash,
411  size_t mHashLen,
412  size_t *size)
413 {
414  size_t hLen = cx_pkcs1_get_hash_len(hID);
415  return cx_pkcs1_emsa_pss_encode_with_salt_len(hID, em, emBits, mHash, mHashLen, hLen, size);
416 }
417 
418 bool cx_pkcs1_emsa_pss_verify_with_salt_len(cx_md_t hID,
419  uint8_t *em,
420  size_t emBits,
421  const uint8_t *mHash,
422  size_t mHashLen,
423  size_t mSaltLen)
424 {
425  size_t mDBlen;
426  size_t PSLen;
427  size_t i;
428  size_t emLen;
429  size_t hLen;
430  cx_hash_t *hash_ctx = &G_cx.pkcs1.hash_ctx.hash;
431 
432  if (hID != CX_SHA224 && hID != CX_SHA256 && hID != CX_SHA384 && hID != CX_SHA512) {
433  return false;
434  }
435 
436  hLen = cx_pkcs1_get_hash_len(hID);
437  emLen = (emBits + 7) / 8;
438 
439  if ((1 + hLen) >= emLen) {
440  return false;
441  }
442  mDBlen = emLen - (1 + hLen);
443 
444  if ((mSaltLen + hLen + 2) >= emLen) {
445  return false;
446  }
447  PSLen = emLen - (mSaltLen + hLen + 2);
448 
449  if (em[emLen - 1] != 0xbc) {
450  return false;
451  }
452  if (em[0] & ~CX_PSS_MASK[8 * emLen - emBits]) {
453  return false;
454  }
455  if (cx_pkcs1_MGF1(hID, em + mDBlen, hLen, G_cx.pkcs1.MGF1, mDBlen) != CX_OK) {
456  return false;
457  }
458  cx_memxor(em, G_cx.pkcs1.MGF1, mDBlen);
459  em[0] &= CX_PSS_MASK[8 * emLen - emBits];
460  for (i = 0; i < PSLen; i++) {
461  if (em[i] != 0) {
462  return false;
463  }
464  }
465  if (em[PSLen] != 0x01) {
466  return false;
467  }
468 
469  if (cx_hash_init_ex(hash_ctx, hID, hLen) != CX_OK
470  || cx_hash_update(hash_ctx, C_cx_pss_zeros, 8) != CX_OK
471  || cx_hash_update(hash_ctx, mHash, mHashLen) != CX_OK
472  || cx_hash_update(hash_ctx, em + PSLen + 1, mSaltLen) != CX_OK
473  || cx_hash_final(hash_ctx, G_cx.pkcs1.digest) != CX_OK) {
474  return false;
475  }
476 
477  return memcmp(G_cx.pkcs1.digest, em + mDBlen, hLen) == 0;
478 }
479 
480 bool cx_pkcs1_emsa_pss_verify(cx_md_t hID,
481  uint8_t *em,
482  size_t emBits,
483  const uint8_t *mHash,
484  size_t mHashLen)
485 {
486  // By default and by convention, the salt length is the hash length.
487  // In order to verify a RSA PSS signature with a variable salt length,
488  // the 'cx_pkcs1_emsa_pss_verify_with_salt_len' function must be
489  // used directly.
490  size_t hLen = cx_pkcs1_get_hash_len(hID);
491  return cx_pkcs1_emsa_pss_verify_with_salt_len(hID, em, emBits, mHash, mHashLen, hLen);
492 }
493 
494 /* ----------------------------------------------------------------------- */
495 /* EME: pkcs1 V1.5 */
496 /* ----------------------------------------------------------------------- */
497 cx_err_t cx_pkcs1_eme_v1o5_encode(cx_md_t hID,
498  uint8_t *em,
499  size_t emLen,
500  const uint8_t *m,
501  size_t mLen)
502 {
503  size_t PSLen;
504  size_t offset;
505  (void) hID;
506 
507  if ((3 + mLen) >= emLen) {
508  return CX_INVALID_PARAMETER;
509  }
510  PSLen = emLen - (3 + mLen);
511 
512  memcpy(em + 2 + PSLen + 1, m, mLen);
513  em[0] = 0;
514  em[1] = 2;
515  cx_rng_no_throw(em + 2, PSLen);
516  for (offset = 2 + PSLen - 1; offset >= 2; offset--) {
517  if (em[offset] == 0) {
518  em[offset] = 0x24;
519  }
520  }
521  em[2 + PSLen] = 0;
522  return CX_OK;
523 }
524 
525 size_t cx_pkcs1_eme_v1o5_decode(cx_md_t hID, uint8_t *em, size_t emLen, uint8_t *m, size_t mLen)
526 {
527  size_t offset;
528  (void) hID;
529  // -> check 00 02 ... 00
530  if ((em[0]) || (em[1] != 2)) {
531  return -1;
532  }
533  // -> check .. .. FFFFFF ..
534  offset = 2;
535  while (offset < emLen) {
536  if (em[offset] == 0) {
537  break;
538  }
539  offset++;
540  }
541  if (offset == emLen) {
542  return -1;
543  }
544  offset++;
545  // copy M
546  if (mLen < emLen - offset) {
547  return -1;
548  }
549  mLen = emLen - offset;
550  memmove(m, em + offset, mLen);
551  return mLen;
552 }
553 
554 /* ----------------------------------------------------------------------- */
555 /* EME: pkcs1 OAEP */
556 /* ----------------------------------------------------------------------- */
557 cx_err_t cx_pkcs1_eme_oaep_encode(cx_md_t hID,
558  uint8_t *em,
559  size_t emLen,
560  const uint8_t *m,
561  size_t mLen)
562 {
563  size_t mDBlen;
564  size_t psLen;
565  size_t offset;
566  uint8_t seed[64];
567  size_t hLen;
568  const uint8_t *lHash;
569  size_t lHashLen;
570  cx_err_t error;
571 
572  hLen = cx_pkcs1_get_hash_len(hID);
573  lHash = cx_pkcs1_get_hash_oeap(hID, &lHashLen);
574  if (hLen == 0 || lHash == NULL) {
575  return CX_INVALID_PARAMETER;
576  }
577 
578  if ((hLen + 1) >= emLen) {
579  return CX_INVALID_PARAMETER;
580  }
581  mDBlen = emLen - (hLen + 1);
582  if ((mLen + 2 * hLen + 2) >= emLen) {
583  return CX_INVALID_PARAMETER;
584  }
585  psLen = emLen - (mLen + 2 * hLen + 2);
586 
587  // random seed
588  cx_rng_no_throw(seed, hLen);
589 
590  // DB = lHash || PS || 01 || M
591  offset = 1 + hLen;
592  memcpy(em + offset, lHash, lHashLen);
593  offset += lHashLen;
594  memset(em + offset, 0, psLen);
595  offset += psLen;
596  em[offset] = 0x01;
597  offset++;
598  memcpy(em + offset, m, mLen);
599 
600  // 00 | masked seed || maskedDB
601  em[0] = 0x00;
602 
603  CX_CHECK(cx_pkcs1_MGF1(hID, seed, hLen, G_cx.pkcs1.MGF1, mDBlen));
604  cx_memxor(em + 1 + hLen, G_cx.pkcs1.MGF1, mDBlen);
605 
606  CX_CHECK(cx_pkcs1_MGF1(hID, em + 1 + hLen, mDBlen, G_cx.pkcs1.MGF1, hLen));
607  memcpy(em + 1, seed, hLen);
608  cx_memxor(em + 1, G_cx.pkcs1.MGF1, hLen);
609 
610 end:
611  return error;
612 }
613 
614 cx_err_t cx_pkcs1_eme_oaep_decode(cx_md_t hID, uint8_t *em, size_t emLen, uint8_t *m, size_t *mLen)
615 {
616  size_t mDBlen;
617  size_t offset;
618  size_t hLen;
619  const uint8_t *lHash;
620  size_t lHashLen;
621  cx_err_t error;
622 
623  hLen = cx_pkcs1_get_hash_len(hID);
624  lHash = cx_pkcs1_get_hash_oeap(hID, &lHashLen);
625  if (hLen == 0 || lHash == NULL) {
626  return CX_INVALID_PARAMETER;
627  }
628  if ((hLen + 1) >= emLen) {
629  return CX_INVALID_PARAMETER;
630  }
631  mDBlen = emLen - (hLen + 1);
632 
633  // unmask all
634  CX_CHECK(cx_pkcs1_MGF1(hID, em + 1 + hLen, mDBlen, G_cx.pkcs1.MGF1, hLen));
635  cx_memxor(em + 1, G_cx.pkcs1.MGF1, hLen);
636  CX_CHECK(cx_pkcs1_MGF1(hID, em + 1, hLen, G_cx.pkcs1.MGF1, mDBlen));
637  cx_memxor(em + 1 + hLen, G_cx.pkcs1.MGF1, mDBlen);
638 
639  // Y||seed||lHash||PS||01||M
640  if (em[0] != 0x00) {
641  return CX_INVALID_PARAMETER;
642  }
643  if (memcmp(em + 1 + hLen, lHash, hLen) != 0) {
644  return CX_INVALID_PARAMETER;
645  }
646 
647  for (offset = 1 + hLen + lHashLen; offset < emLen; offset++) {
648  if (em[offset] != 0) {
649  break;
650  }
651  }
652  if ((offset == emLen) || (em[offset] != 0x01)) {
653  return CX_INVALID_PARAMETER;
654  }
655  offset++;
656 
657  // copy M
658  if (*mLen < emLen - offset) {
659  return CX_INVALID_PARAMETER;
660  }
661 
662  *mLen = emLen - offset;
663  memmove(m, em + offset, *mLen);
664 
665 end:
666  return error;
667 }
668 
669 #endif
670 
671 #endif // HAVE_RSA
union cx_u G_cx
Definition: cx_ram.c:21
void cx_memxor(uint8_t *buf1, const uint8_t *buf2, size_t len)
Definition: cx_utils.c:173
Random Number Generation.
unsigned char uint8_t
Definition: usbd_conf.h:53