1 | /* Copyright (c) 2014, Google Inc. |
---|---|
2 | * |
3 | * Permission to use, copy, modify, and/or distribute this software for any |
4 | * purpose with or without fee is hereby granted, provided that the above |
5 | * copyright notice and this permission notice appear in all copies. |
6 | * |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
14 | |
15 | #include <openssl/aead.h> |
16 | |
17 | #include <assert.h> |
18 | #include <string.h> |
19 | |
20 | #include <openssl/cipher.h> |
21 | #include <openssl/err.h> |
22 | #include <openssl/mem.h> |
23 | |
24 | #include "internal.h" |
25 | #include "../../internal.h" |
26 | |
27 | |
28 | size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } |
29 | |
30 | size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; } |
31 | |
32 | size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } |
33 | |
34 | size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } |
35 | |
36 | void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) { |
37 | OPENSSL_memset(dst: ctx, c: 0, n: sizeof(EVP_AEAD_CTX)); |
38 | } |
39 | |
40 | EVP_AEAD_CTX *EVP_AEAD_CTX_new(const EVP_AEAD *aead, const uint8_t *key, |
41 | size_t key_len, size_t tag_len) { |
42 | EVP_AEAD_CTX *ctx = OPENSSL_malloc(size: sizeof(EVP_AEAD_CTX)); |
43 | EVP_AEAD_CTX_zero(ctx); |
44 | |
45 | if (EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, NULL)) { |
46 | return ctx; |
47 | } |
48 | |
49 | EVP_AEAD_CTX_free(ctx); |
50 | return NULL; |
51 | } |
52 | |
53 | void EVP_AEAD_CTX_free(EVP_AEAD_CTX *ctx) { |
54 | if (ctx == NULL) { |
55 | return; |
56 | } |
57 | EVP_AEAD_CTX_cleanup(ctx); |
58 | OPENSSL_free(ptr: ctx); |
59 | } |
60 | |
61 | int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, |
62 | const uint8_t *key, size_t key_len, size_t tag_len, |
63 | ENGINE *impl) { |
64 | if (!aead->init) { |
65 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET); |
66 | ctx->aead = NULL; |
67 | return 0; |
68 | } |
69 | return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len, |
70 | dir: evp_aead_open); |
71 | } |
72 | |
73 | int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, |
74 | const uint8_t *key, size_t key_len, |
75 | size_t tag_len, |
76 | enum evp_aead_direction_t dir) { |
77 | if (key_len != aead->key_len) { |
78 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE); |
79 | ctx->aead = NULL; |
80 | return 0; |
81 | } |
82 | |
83 | ctx->aead = aead; |
84 | |
85 | int ok; |
86 | if (aead->init) { |
87 | ok = aead->init(ctx, key, key_len, tag_len); |
88 | } else { |
89 | ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir); |
90 | } |
91 | |
92 | if (!ok) { |
93 | ctx->aead = NULL; |
94 | } |
95 | |
96 | return ok; |
97 | } |
98 | |
99 | void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { |
100 | if (ctx->aead == NULL) { |
101 | return; |
102 | } |
103 | ctx->aead->cleanup(ctx); |
104 | ctx->aead = NULL; |
105 | } |
106 | |
107 | // check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If |
108 | // |in| and |out| alias, we require that |in| == |out|. |
109 | static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out, |
110 | size_t out_len) { |
111 | if (!buffers_alias(a: in, a_len: in_len, b: out, b_len: out_len)) { |
112 | return 1; |
113 | } |
114 | |
115 | return in == out; |
116 | } |
117 | |
118 | int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, |
119 | size_t max_out_len, const uint8_t *nonce, |
120 | size_t nonce_len, const uint8_t *in, size_t in_len, |
121 | const uint8_t *ad, size_t ad_len) { |
122 | if (in_len + ctx->aead->overhead < in_len /* overflow */) { |
123 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); |
124 | goto error; |
125 | } |
126 | |
127 | if (max_out_len < in_len) { |
128 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); |
129 | goto error; |
130 | } |
131 | |
132 | if (!check_alias(in, in_len, out, out_len: max_out_len)) { |
133 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
134 | goto error; |
135 | } |
136 | |
137 | size_t out_tag_len; |
138 | if (ctx->aead->seal_scatter(ctx, out, out + in_len, &out_tag_len, |
139 | max_out_len - in_len, nonce, nonce_len, in, |
140 | in_len, NULL, 0, ad, ad_len)) { |
141 | *out_len = in_len + out_tag_len; |
142 | return 1; |
143 | } |
144 | |
145 | error: |
146 | // In the event of an error, clear the output buffer so that a caller |
147 | // that doesn't check the return value doesn't send raw data. |
148 | OPENSSL_memset(dst: out, c: 0, n: max_out_len); |
149 | *out_len = 0; |
150 | return 0; |
151 | } |
152 | |
153 | int EVP_AEAD_CTX_seal_scatter( |
154 | const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag, size_t |
155 | *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce, size_t |
156 | nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in, |
157 | size_t extra_in_len, const uint8_t *ad, size_t ad_len) { |
158 | // |in| and |out| may alias exactly, |out_tag| may not alias. |
159 | if (!check_alias(in, in_len, out, out_len: in_len) || |
160 | buffers_alias(a: out, a_len: in_len, b: out_tag, b_len: max_out_tag_len) || |
161 | buffers_alias(a: in, a_len: in_len, b: out_tag, b_len: max_out_tag_len)) { |
162 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
163 | goto error; |
164 | } |
165 | |
166 | if (!ctx->aead->seal_scatter_supports_extra_in && extra_in_len) { |
167 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); |
168 | goto error; |
169 | } |
170 | |
171 | if (ctx->aead->seal_scatter(ctx, out, out_tag, out_tag_len, max_out_tag_len, |
172 | nonce, nonce_len, in, in_len, extra_in, |
173 | extra_in_len, ad, ad_len)) { |
174 | return 1; |
175 | } |
176 | |
177 | error: |
178 | // In the event of an error, clear the output buffer so that a caller |
179 | // that doesn't check the return value doesn't send raw data. |
180 | OPENSSL_memset(dst: out, c: 0, n: in_len); |
181 | OPENSSL_memset(dst: out_tag, c: 0, n: max_out_tag_len); |
182 | *out_tag_len = 0; |
183 | return 0; |
184 | } |
185 | |
186 | int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, |
187 | size_t max_out_len, const uint8_t *nonce, |
188 | size_t nonce_len, const uint8_t *in, size_t in_len, |
189 | const uint8_t *ad, size_t ad_len) { |
190 | if (!check_alias(in, in_len, out, out_len: max_out_len)) { |
191 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
192 | goto error; |
193 | } |
194 | |
195 | if (ctx->aead->open) { |
196 | if (!ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in, |
197 | in_len, ad, ad_len)) { |
198 | goto error; |
199 | } |
200 | return 1; |
201 | } |
202 | |
203 | // AEADs that use the default implementation of open() must set |tag_len| at |
204 | // initialization time. |
205 | assert(ctx->tag_len); |
206 | |
207 | if (in_len < ctx->tag_len) { |
208 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); |
209 | goto error; |
210 | } |
211 | |
212 | size_t plaintext_len = in_len - ctx->tag_len; |
213 | if (max_out_len < plaintext_len) { |
214 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); |
215 | goto error; |
216 | } |
217 | if (EVP_AEAD_CTX_open_gather(ctx, out, nonce, nonce_len, in, in_len: plaintext_len, |
218 | in_tag: in + plaintext_len, in_tag_len: ctx->tag_len, ad, ad_len)) { |
219 | *out_len = plaintext_len; |
220 | return 1; |
221 | } |
222 | |
223 | error: |
224 | // In the event of an error, clear the output buffer so that a caller |
225 | // that doesn't check the return value doesn't try and process bad |
226 | // data. |
227 | OPENSSL_memset(dst: out, c: 0, n: max_out_len); |
228 | *out_len = 0; |
229 | return 0; |
230 | } |
231 | |
232 | int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out, |
233 | const uint8_t *nonce, size_t nonce_len, |
234 | const uint8_t *in, size_t in_len, |
235 | const uint8_t *in_tag, size_t in_tag_len, |
236 | const uint8_t *ad, size_t ad_len) { |
237 | if (!check_alias(in, in_len, out, out_len: in_len)) { |
238 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
239 | goto error; |
240 | } |
241 | |
242 | if (!ctx->aead->open_gather) { |
243 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED); |
244 | goto error; |
245 | } |
246 | |
247 | if (ctx->aead->open_gather(ctx, out, nonce, nonce_len, in, in_len, in_tag, |
248 | in_tag_len, ad, ad_len)) { |
249 | return 1; |
250 | } |
251 | |
252 | error: |
253 | // In the event of an error, clear the output buffer so that a caller |
254 | // that doesn't check the return value doesn't try and process bad |
255 | // data. |
256 | OPENSSL_memset(dst: out, c: 0, n: in_len); |
257 | return 0; |
258 | } |
259 | |
260 | const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; } |
261 | |
262 | int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, |
263 | size_t *out_len) { |
264 | if (ctx->aead->get_iv == NULL) { |
265 | return 0; |
266 | } |
267 | |
268 | return ctx->aead->get_iv(ctx, out_iv, out_len); |
269 | } |
270 | |
271 | int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len, |
272 | const size_t in_len, const size_t extra_in_len) { |
273 | assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len); |
274 | |
275 | if (ctx->aead->tag_len) { |
276 | *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len); |
277 | return 1; |
278 | } |
279 | |
280 | if (extra_in_len + ctx->tag_len < extra_in_len) { |
281 | OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW); |
282 | *out_tag_len = 0; |
283 | return 0; |
284 | } |
285 | *out_tag_len = extra_in_len + ctx->tag_len; |
286 | return 1; |
287 | } |
288 |
Definitions
- EVP_AEAD_key_length
- EVP_AEAD_nonce_length
- EVP_AEAD_max_overhead
- EVP_AEAD_max_tag_len
- EVP_AEAD_CTX_zero
- EVP_AEAD_CTX_new
- EVP_AEAD_CTX_free
- EVP_AEAD_CTX_init
- EVP_AEAD_CTX_init_with_direction
- EVP_AEAD_CTX_cleanup
- check_alias
- EVP_AEAD_CTX_seal
- EVP_AEAD_CTX_seal_scatter
- EVP_AEAD_CTX_open
- EVP_AEAD_CTX_open_gather
- EVP_AEAD_CTX_aead
- EVP_AEAD_CTX_get_iv
Learn more about Flutter for embedded and desktop on industrialflutter.com