File: | src/usr.sbin/smtpd/smtpd/../crypto.c |
Warning: | line 155, column 7 Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: crypto.c,v 1.10 2021/06/14 17:58:15 eric Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2013 Gilles Chehade <gilles@openbsd.org> |
5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. |
9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ |
18 | |
19 | #include <sys/stat.h> |
20 | |
21 | #include <openssl/evp.h> |
22 | #include <string.h> |
23 | |
24 | #define CRYPTO_BUFFER_SIZE16384 16384 |
25 | |
26 | #define GCM_TAG_SIZE16 16 |
27 | #define IV_SIZE12 12 |
28 | #define KEY_SIZE32 32 |
29 | |
30 | /* bump if we ever switch from aes-256-gcm to anything else */ |
31 | #define API_VERSION1 1 |
32 | |
33 | |
34 | int crypto_setup(const char *, size_t); |
35 | int crypto_encrypt_file(FILE *, FILE *); |
36 | int crypto_decrypt_file(FILE *, FILE *); |
37 | size_t crypto_encrypt_buffer(const char *, size_t, char *, size_t); |
38 | size_t crypto_decrypt_buffer(const char *, size_t, char *, size_t); |
39 | |
40 | static struct crypto_ctx { |
41 | unsigned char key[KEY_SIZE32]; |
42 | } cp; |
43 | |
44 | int |
45 | crypto_setup(const char *key, size_t len) |
46 | { |
47 | if (len != KEY_SIZE32) |
48 | return 0; |
49 | |
50 | memset(&cp, 0, sizeof cp); |
51 | |
52 | /* openssl rand -hex 16 */ |
53 | memcpy(cp.key, key, sizeof cp.key); |
54 | |
55 | return 1; |
56 | } |
57 | |
58 | int |
59 | crypto_encrypt_file(FILE * in, FILE * out) |
60 | { |
61 | EVP_CIPHER_CTX *ctx; |
62 | uint8_t ibuf[CRYPTO_BUFFER_SIZE16384]; |
63 | uint8_t obuf[CRYPTO_BUFFER_SIZE16384]; |
64 | uint8_t iv[IV_SIZE12]; |
65 | uint8_t tag[GCM_TAG_SIZE16]; |
66 | uint8_t version = API_VERSION1; |
67 | size_t r; |
68 | int len; |
69 | int ret = 0; |
70 | struct stat sb; |
71 | |
72 | /* XXX - Do NOT encrypt files bigger than 64GB */ |
73 | if (fstat(fileno(in)(!__isthreaded ? ((in)->_file) : (fileno)(in)), &sb) == -1) |
74 | return 0; |
75 | if (sb.st_size >= 0x1000000000LL) |
76 | return 0; |
77 | |
78 | /* prepend version byte*/ |
79 | if (fwrite(&version, 1, sizeof version, out) != sizeof version) |
80 | return 0; |
81 | |
82 | /* generate and prepend IV */ |
83 | memset(iv, 0, sizeof iv); |
84 | arc4random_buf(iv, sizeof iv); |
85 | if (fwrite(iv, 1, sizeof iv, out) != sizeof iv) |
86 | return 0; |
87 | |
88 | ctx = EVP_CIPHER_CTX_new(); |
89 | if (ctx == NULL((void *)0)) |
90 | return 0; |
91 | |
92 | EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL((void *)0), cp.key, iv); |
93 | |
94 | /* encrypt until end of file */ |
95 | while ((r = fread(ibuf, 1, CRYPTO_BUFFER_SIZE16384, in)) != 0) { |
96 | if (!EVP_EncryptUpdate(ctx, obuf, &len, ibuf, r)) |
97 | goto end; |
98 | if (len && fwrite(obuf, len, 1, out) != 1) |
99 | goto end; |
100 | } |
101 | if (!feof(in)(!__isthreaded ? (((in)->_flags & 0x0020) != 0) : (feof )(in))) |
102 | goto end; |
103 | |
104 | /* finalize and write last chunk if any */ |
105 | if (!EVP_EncryptFinal_ex(ctx, obuf, &len)) |
106 | goto end; |
107 | if (len && fwrite(obuf, len, 1, out) != 1) |
108 | goto end; |
109 | |
110 | /* get and append tag */ |
111 | EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG0x10, sizeof tag, tag); |
112 | if (fwrite(tag, sizeof tag, 1, out) != 1) |
113 | goto end; |
114 | |
115 | fflush(out); |
116 | ret = 1; |
117 | |
118 | end: |
119 | EVP_CIPHER_CTX_free(ctx); |
120 | return ret; |
121 | } |
122 | |
123 | int |
124 | crypto_decrypt_file(FILE * in, FILE * out) |
125 | { |
126 | EVP_CIPHER_CTX *ctx; |
127 | uint8_t ibuf[CRYPTO_BUFFER_SIZE16384]; |
128 | uint8_t obuf[CRYPTO_BUFFER_SIZE16384]; |
129 | uint8_t iv[IV_SIZE12]; |
130 | uint8_t tag[GCM_TAG_SIZE16]; |
131 | uint8_t version; |
132 | size_t r; |
133 | off_t sz; |
134 | int len; |
135 | int ret = 0; |
136 | struct stat sb; |
137 | |
138 | /* input file too small to be an encrypted file */ |
139 | if (fstat(fileno(in)(!__isthreaded ? ((in)->_file) : (fileno)(in)), &sb) == -1) |
140 | return 0; |
141 | if (sb.st_size <= (off_t) (sizeof version + sizeof tag + sizeof iv)) |
142 | return 0; |
143 | sz = sb.st_size; |
144 | |
145 | /* extract tag */ |
146 | if (fseek(in, -sizeof(tag), SEEK_END2) == -1) |
147 | return 0; |
148 | if ((r = fread(tag, 1, sizeof tag, in)) != sizeof tag) |
149 | return 0; |
150 | |
151 | if (fseek(in, 0, SEEK_SET0) == -1) |
152 | return 0; |
153 | |
154 | /* extract version */ |
155 | if ((r = fread(&version, 1, sizeof version, in)) != sizeof version) |
Although the value stored to 'r' is used in the enclosing expression, the value is never actually read from 'r' | |
156 | return 0; |
157 | if (version != API_VERSION1) |
158 | return 0; |
159 | |
160 | /* extract IV */ |
161 | memset(iv, 0, sizeof iv); |
162 | if ((r = fread(iv, 1, sizeof iv, in)) != sizeof iv) |
163 | return 0; |
164 | |
165 | /* real ciphertext length */ |
166 | sz -= sizeof version; |
167 | sz -= sizeof iv; |
168 | sz -= sizeof tag; |
169 | |
170 | ctx = EVP_CIPHER_CTX_new(); |
171 | if (ctx == NULL((void *)0)) |
172 | return 0; |
173 | |
174 | EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL((void *)0), cp.key, iv); |
175 | |
176 | /* set expected tag */ |
177 | EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG0x11, sizeof tag, tag); |
178 | |
179 | /* decrypt until end of ciphertext */ |
180 | while (sz) { |
181 | if (sz > CRYPTO_BUFFER_SIZE16384) |
182 | r = fread(ibuf, 1, CRYPTO_BUFFER_SIZE16384, in); |
183 | else |
184 | r = fread(ibuf, 1, sz, in); |
185 | if (!r) |
186 | break; |
187 | if (!EVP_DecryptUpdate(ctx, obuf, &len, ibuf, r)) |
188 | goto end; |
189 | if (len && fwrite(obuf, len, 1, out) != 1) |
190 | goto end; |
191 | sz -= r; |
192 | } |
193 | if (ferror(in)(!__isthreaded ? (((in)->_flags & 0x0040) != 0) : (ferror )(in))) |
194 | goto end; |
195 | |
196 | /* finalize, write last chunk if any and perform authentication check */ |
197 | if (!EVP_DecryptFinal_ex(ctx, obuf, &len)) |
198 | goto end; |
199 | if (len && fwrite(obuf, len, 1, out) != 1) |
200 | goto end; |
201 | |
202 | fflush(out); |
203 | ret = 1; |
204 | |
205 | end: |
206 | EVP_CIPHER_CTX_free(ctx); |
207 | return ret; |
208 | } |
209 | |
210 | size_t |
211 | crypto_encrypt_buffer(const char *in, size_t inlen, char *out, size_t outlen) |
212 | { |
213 | EVP_CIPHER_CTX *ctx; |
214 | uint8_t iv[IV_SIZE12]; |
215 | uint8_t tag[GCM_TAG_SIZE16]; |
216 | uint8_t version = API_VERSION1; |
217 | off_t sz; |
218 | int olen; |
219 | int len = 0; |
220 | int ret = 0; |
221 | |
222 | /* output buffer does not have enough room */ |
223 | if (outlen < inlen + sizeof version + sizeof tag + sizeof iv) |
224 | return 0; |
225 | |
226 | /* input should not exceed 64GB */ |
227 | sz = inlen; |
228 | if (sz >= 0x1000000000LL) |
229 | return 0; |
230 | |
231 | /* prepend version */ |
232 | *out = version; |
233 | len++; |
234 | |
235 | /* generate IV */ |
236 | memset(iv, 0, sizeof iv); |
237 | arc4random_buf(iv, sizeof iv); |
238 | memcpy(out + len, iv, sizeof iv); |
239 | len += sizeof iv; |
240 | |
241 | ctx = EVP_CIPHER_CTX_new(); |
242 | if (ctx == NULL((void *)0)) |
243 | return 0; |
244 | |
245 | EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL((void *)0), cp.key, iv); |
246 | |
247 | /* encrypt buffer */ |
248 | if (!EVP_EncryptUpdate(ctx, out + len, &olen, in, inlen)) |
249 | goto end; |
250 | len += olen; |
251 | |
252 | /* finalize and write last chunk if any */ |
253 | if (!EVP_EncryptFinal_ex(ctx, out + len, &olen)) |
254 | goto end; |
255 | len += olen; |
256 | |
257 | /* get and append tag */ |
258 | EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG0x10, sizeof tag, tag); |
259 | memcpy(out + len, tag, sizeof tag); |
260 | ret = len + sizeof tag; |
261 | |
262 | end: |
263 | EVP_CIPHER_CTX_free(ctx); |
264 | return ret; |
265 | } |
266 | |
267 | size_t |
268 | crypto_decrypt_buffer(const char *in, size_t inlen, char *out, size_t outlen) |
269 | { |
270 | EVP_CIPHER_CTX *ctx; |
271 | uint8_t iv[IV_SIZE12]; |
272 | uint8_t tag[GCM_TAG_SIZE16]; |
273 | int olen; |
274 | int len = 0; |
275 | int ret = 0; |
276 | |
277 | /* out does not have enough room */ |
278 | if (outlen < inlen - sizeof tag + sizeof iv) |
279 | return 0; |
280 | |
281 | /* extract tag */ |
282 | memcpy(tag, in + inlen - sizeof tag, sizeof tag); |
283 | inlen -= sizeof tag; |
284 | |
285 | /* check version */ |
286 | if (*in != API_VERSION1) |
287 | return 0; |
288 | in++; |
289 | inlen--; |
290 | |
291 | /* extract IV */ |
292 | memset(iv, 0, sizeof iv); |
293 | memcpy(iv, in, sizeof iv); |
294 | inlen -= sizeof iv; |
295 | in += sizeof iv; |
296 | |
297 | ctx = EVP_CIPHER_CTX_new(); |
298 | if (ctx == NULL((void *)0)) |
299 | return 0; |
300 | |
301 | EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL((void *)0), cp.key, iv); |
302 | |
303 | /* set expected tag */ |
304 | EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG0x11, sizeof tag, tag); |
305 | |
306 | /* decrypt buffer */ |
307 | if (!EVP_DecryptUpdate(ctx, out, &olen, in, inlen)) |
308 | goto end; |
309 | len += olen; |
310 | |
311 | /* finalize, write last chunk if any and perform authentication check */ |
312 | if (!EVP_DecryptFinal_ex(ctx, out + len, &olen)) |
313 | goto end; |
314 | ret = len + olen; |
315 | |
316 | end: |
317 | EVP_CIPHER_CTX_free(ctx); |
318 | return ret; |
319 | } |
320 | |
321 | #if 0 |
322 | int |
323 | main(int argc, char *argv[]) |
324 | { |
325 | if (argc != 3) { |
326 | printf("usage: crypto <key> <buffer>\n"); |
327 | return 1; |
328 | } |
329 | |
330 | if (!crypto_setup(argv[1], strlen(argv[1]))) { |
331 | printf("crypto_setup failed\n"); |
332 | return 1; |
333 | } |
334 | |
335 | { |
336 | char encbuffer[4096]; |
337 | size_t enclen; |
338 | char decbuffer[4096]; |
339 | size_t declen; |
340 | |
341 | printf("encrypt/decrypt buffer: "); |
342 | enclen = crypto_encrypt_buffer(argv[2], strlen(argv[2]), |
343 | encbuffer, sizeof encbuffer); |
344 | |
345 | /* uncomment below to provoke integrity check failure */ |
346 | /* |
347 | * encbuffer[13] = 0x42; |
348 | * encbuffer[14] = 0x42; |
349 | * encbuffer[15] = 0x42; |
350 | * encbuffer[16] = 0x42; |
351 | */ |
352 | |
353 | declen = crypto_decrypt_buffer(encbuffer, enclen, |
354 | decbuffer, sizeof decbuffer); |
355 | if (declen != 0 && !strncmp(argv[2], decbuffer, declen)) |
356 | printf("ok\n"); |
357 | else |
358 | printf("nope\n"); |
359 | } |
360 | |
361 | { |
362 | FILE *fpin; |
363 | FILE *fpout; |
364 | printf("encrypt/decrypt file: "); |
365 | |
366 | fpin = fopen("/etc/passwd", "r"); |
367 | fpout = fopen("/tmp/passwd.enc", "w"); |
368 | if (!crypto_encrypt_file(fpin, fpout)) { |
369 | printf("encryption failed\n"); |
370 | return 1; |
371 | } |
372 | fclose(fpin); |
373 | fclose(fpout); |
374 | |
375 | /* uncomment below to provoke integrity check failure */ |
376 | /* |
377 | * fpin = fopen("/tmp/passwd.enc", "a"); |
378 | * fprintf(fpin, "borken"); |
379 | * fclose(fpin); |
380 | */ |
381 | fpin = fopen("/tmp/passwd.enc", "r"); |
382 | fpout = fopen("/tmp/passwd.dec", "w"); |
383 | if (!crypto_decrypt_file(fpin, fpout)) |
384 | printf("nope\n"); |
385 | else |
386 | printf("ok\n"); |
387 | fclose(fpin); |
388 | fclose(fpout); |
389 | } |
390 | |
391 | |
392 | return 0; |
393 | } |
394 | #endif |