Embedded SDK
Embedded SDK
cx_pbkdf2.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_PBKDF2
20 
21 #include <string.h>
22 
23 #include "errors.h"
24 #include "exceptions.h"
25 #include "cx_pbkdf2.h"
26 #include "cx_hash.h"
27 #include "cx_ram.h"
28 
29 cx_err_t cx_pbkdf2_hmac(cx_md_t md_type,
30  const uint8_t *password,
31  size_t password_len,
32  const uint8_t *salt,
33  size_t salt_len,
34  uint32_t iterations,
35  uint8_t *key,
36  size_t key_len)
37 {
38  cx_hmac_t *hmac_ctx = &G_cx.pbkdf2.hmac_ctx;
39  uint8_t counter[4];
40  uint8_t *work = G_cx.pbkdf2.work;
41  size_t work_size;
42  uint8_t *md1 = G_cx.pbkdf2.md1;
43  size_t copy_len;
44  size_t digest_size;
45  cx_err_t error = CX_OK;
46 
47  if (password == NULL || salt == NULL || key == NULL) {
48  return CX_INVALID_PARAMETER;
49  }
50 
51  const cx_hash_info_t *info = cx_hash_get_info(md_type);
52  digest_size = info->output_size;
53 
54  memset(counter, 0, sizeof(counter));
55  counter[sizeof(counter) - 1] = 1;
56 
57  while (key_len) {
58  CX_CHECK(cx_hmac_init(hmac_ctx, md_type, password, password_len));
59  CX_CHECK(cx_hmac_update(hmac_ctx, salt, salt_len));
60  CX_CHECK(cx_hmac_update(hmac_ctx, counter, 4));
61 
62  work_size = digest_size;
63  CX_CHECK(cx_hmac_final(hmac_ctx, work, &work_size));
64 
65  memcpy(md1, work, digest_size);
66  for (uint32_t i = 1; i < iterations; i++) {
67  CX_CHECK(cx_hmac_init(hmac_ctx, md_type, password, password_len));
68  CX_CHECK(cx_hmac_update(hmac_ctx, md1, digest_size));
69  work_size = digest_size;
70  CX_CHECK(cx_hmac_final(hmac_ctx, md1, &work_size));
71 
72  for (unsigned int j = 0; j < digest_size; j++) {
73  work[j] ^= md1[j];
74  }
75  }
76 
77  if (key_len < digest_size) {
78  copy_len = key_len;
79  }
80  else {
81  copy_len = digest_size;
82  }
83  memcpy(key, work, copy_len);
84  key += copy_len;
85  key_len -= copy_len;
86 
87  // Increment counter
88  for (int i = 3; i >= 0; i--) {
89  if (++counter[i] != 0) {
90  break;
91  }
92  }
93  }
94 end:
95  return error;
96 }
97 
98 cx_err_t cx_pbkdf2_no_throw(cx_md_t md_type,
99  const uint8_t *password,
100  size_t password_len,
101  uint8_t *salt,
102  size_t salt_len,
103  uint32_t iterations,
104  uint8_t *out,
105  size_t out_len)
106 {
107  return cx_pbkdf2_hmac(
108  md_type, password, password_len, salt, salt_len, iterations, out, out_len);
109 }
110 
111 #endif // HAVE_PBKDF2
union cx_u G_cx
Definition: cx_ram.c:21
unsigned char uint8_t
Definition: usbd_conf.h:53