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