]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libfido2/src/aes256.c
zfs: merge openzfs/zfs@f795e90a1
[FreeBSD/FreeBSD.git] / contrib / libfido2 / src / aes256.c
1 /*
2  * Copyright (c) 2021 Yubico AB. All rights reserved.
3  * Use of this source code is governed by a BSD-style
4  * license that can be found in the LICENSE file.
5  * SPDX-License-Identifier: BSD-2-Clause
6  */
7
8 #include "fido.h"
9
10 static int
11 aes256_cbc(const fido_blob_t *key, const u_char *iv, const fido_blob_t *in,
12     fido_blob_t *out, int encrypt)
13 {
14         EVP_CIPHER_CTX *ctx = NULL;
15         const EVP_CIPHER *cipher;
16         int ok = -1;
17
18         memset(out, 0, sizeof(*out));
19
20         if (key->len != 32) {
21                 fido_log_debug("%s: invalid key len %zu", __func__, key->len);
22                 goto fail;
23         }
24         if (in->len > UINT_MAX || in->len % 16 || in->len == 0) {
25                 fido_log_debug("%s: invalid input len %zu", __func__, in->len);
26                 goto fail;
27         }
28         out->len = in->len;
29         if ((out->ptr = calloc(1, out->len)) == NULL) {
30                 fido_log_debug("%s: calloc", __func__);
31                 goto fail;
32         }
33         if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
34             (cipher = EVP_aes_256_cbc()) == NULL) {
35                 fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__);
36                 goto fail;
37         }
38         if (EVP_CipherInit(ctx, cipher, key->ptr, iv, encrypt) == 0 ||
39             EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)out->len) < 0) {
40                 fido_log_debug("%s: EVP_Cipher", __func__);
41                 goto fail;
42         }
43
44         ok = 0;
45 fail:
46         if (ctx != NULL)
47                 EVP_CIPHER_CTX_free(ctx);
48         if (ok < 0)
49                 fido_blob_reset(out);
50
51         return ok;
52 }
53
54 static int
55 aes256_cbc_proto1(const fido_blob_t *key, const fido_blob_t *in,
56     fido_blob_t *out, int encrypt)
57 {
58         u_char iv[16];
59
60         memset(&iv, 0, sizeof(iv));
61
62         return aes256_cbc(key, iv, in, out, encrypt);
63 }
64
65 static int
66 aes256_cbc_fips(const fido_blob_t *secret, const fido_blob_t *in,
67     fido_blob_t *out, int encrypt)
68 {
69         fido_blob_t key, cin, cout;
70         u_char iv[16];
71
72         memset(out, 0, sizeof(*out));
73
74         if (secret->len != 64) {
75                 fido_log_debug("%s: invalid secret len %zu", __func__,
76                     secret->len);
77                 return -1;
78         }
79         if (in->len < sizeof(iv)) {
80                 fido_log_debug("%s: invalid input len %zu", __func__, in->len);
81                 return -1;
82         }
83         if (encrypt) {
84                 if (fido_get_random(iv, sizeof(iv)) < 0) {
85                         fido_log_debug("%s: fido_get_random", __func__);
86                         return -1;
87                 }
88                 cin = *in;
89         } else {
90                 memcpy(iv, in->ptr, sizeof(iv));
91                 cin.ptr = in->ptr + sizeof(iv);
92                 cin.len = in->len - sizeof(iv);
93         }
94         key.ptr = secret->ptr + 32;
95         key.len = secret->len - 32;
96         if (aes256_cbc(&key, iv, &cin, &cout, encrypt) < 0)
97                 return -1;
98         if (encrypt) {
99                 if (cout.len > SIZE_MAX - sizeof(iv) ||
100                     (out->ptr = calloc(1, sizeof(iv) + cout.len)) == NULL) {
101                         fido_blob_reset(&cout);
102                         return -1;
103                 }
104                 out->len = sizeof(iv) + cout.len;
105                 memcpy(out->ptr, iv, sizeof(iv));
106                 memcpy(out->ptr + sizeof(iv), cout.ptr, cout.len);
107                 fido_blob_reset(&cout);
108         } else
109                 *out = cout;
110
111         return 0;
112 }
113
114 static int
115 aes256_gcm(const fido_blob_t *key, const fido_blob_t *nonce,
116     const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out,
117     int encrypt)
118 {
119         EVP_CIPHER_CTX *ctx = NULL;
120         const EVP_CIPHER *cipher;
121         size_t textlen;
122         int ok = -1;
123
124         memset(out, 0, sizeof(*out));
125
126         if (nonce->len != 12 || key->len != 32 || aad->len > UINT_MAX) {
127                 fido_log_debug("%s: invalid params %zu, %zu, %zu", __func__,
128                     nonce->len, key->len, aad->len);
129                 goto fail;
130         }
131         if (in->len > UINT_MAX || in->len > SIZE_MAX - 16 || in->len < 16) {
132                 fido_log_debug("%s: invalid input len %zu", __func__, in->len);
133                 goto fail;
134         }
135         /* add tag to (on encrypt) or trim tag from the output (on decrypt) */
136         out->len = encrypt ? in->len + 16 : in->len - 16;
137         if ((out->ptr = calloc(1, out->len)) == NULL) {
138                 fido_log_debug("%s: calloc", __func__);
139                 goto fail;
140         }
141         if ((ctx = EVP_CIPHER_CTX_new()) == NULL ||
142             (cipher = EVP_aes_256_gcm()) == NULL) {
143                 fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__);
144                 goto fail;
145         }
146         if (EVP_CipherInit(ctx, cipher, key->ptr, nonce->ptr, encrypt) == 0) {
147                 fido_log_debug("%s: EVP_CipherInit", __func__);
148                 goto fail;
149         }
150
151         if (encrypt)
152                 textlen = in->len;
153         else {
154                 textlen = in->len - 16;
155                 /* point openssl at the mac tag */
156                 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16,
157                     in->ptr + in->len - 16) == 0) {
158                         fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__);
159                         goto fail;
160                 }
161         }
162         /* the last EVP_Cipher() will either compute or verify the mac tag */
163         if (EVP_Cipher(ctx, NULL, aad->ptr, (u_int)aad->len) < 0 ||
164             EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)textlen) < 0 ||
165             EVP_Cipher(ctx, NULL, NULL, 0) < 0) {
166                 fido_log_debug("%s: EVP_Cipher", __func__);
167                 goto fail;
168         }
169         if (encrypt) {
170                 /* append the mac tag */
171                 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16,
172                     out->ptr + out->len - 16) == 0) {
173                         fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__);
174                         goto fail;
175                 }
176         }
177
178         ok = 0;
179 fail:
180         if (ctx != NULL)
181                 EVP_CIPHER_CTX_free(ctx);
182         if (ok < 0)
183                 fido_blob_reset(out);
184
185         return ok;
186 }
187
188 int
189 aes256_cbc_enc(const fido_dev_t *dev, const fido_blob_t *secret,
190     const fido_blob_t *in, fido_blob_t *out)
191 {
192         return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret,
193             in, out, 1) : aes256_cbc_proto1(secret, in, out, 1);
194 }
195
196 int
197 aes256_cbc_dec(const fido_dev_t *dev, const fido_blob_t *secret,
198     const fido_blob_t *in, fido_blob_t *out)
199 {
200         return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret,
201             in, out, 0) : aes256_cbc_proto1(secret, in, out, 0);
202 }
203
204 int
205 aes256_gcm_enc(const fido_blob_t *key, const fido_blob_t *nonce,
206     const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out)
207 {
208         return aes256_gcm(key, nonce, aad, in, out, 1);
209 }
210
211 int
212 aes256_gcm_dec(const fido_blob_t *key, const fido_blob_t *nonce,
213     const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out)
214 {
215         return aes256_gcm(key, nonce, aad, in, out, 0);
216 }