Commit | Line | Data |
---|---|---|
62efe6ec MD |
1 | /* |
2 | * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved. | |
3 | * | |
4 | * This code is derived from software contributed to The DragonFly Project | |
5 | * by Matthew Dillon <dillon@dragonflybsd.org> | |
6 | * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in | |
16 | * the documentation and/or other materials provided with the | |
17 | * distribution. | |
18 | * 3. Neither the name of The DragonFly Project nor the names of its | |
19 | * contributors may be used to endorse or promote products derived | |
20 | * from this software without specific, prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
25 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
26 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
27 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
30 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
32 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
33 | * SUCH DAMAGE. | |
34 | */ | |
35 | ||
36 | #include "hammer2.h" | |
37 | ||
02454b3e MD |
38 | /* |
39 | * Setup crypto for pthreads | |
40 | */ | |
41 | static pthread_mutex_t *crypto_locks; | |
42 | int crypto_count; | |
43 | ||
44 | static | |
45 | unsigned long | |
46 | hammer2_crypto_id_callback(void) | |
47 | { | |
48 | return ((unsigned long)(uintptr_t)pthread_self()); | |
49 | } | |
50 | ||
51 | static | |
52 | void | |
53 | hammer2_crypto_locking_callback(int mode, int type, | |
54 | const char *file __unused, int line __unused) | |
55 | { | |
56 | assert(type >= 0 && type < crypto_count); | |
57 | if (mode & CRYPTO_LOCK) { | |
58 | pthread_mutex_lock(&crypto_locks[type]); | |
59 | } else { | |
60 | pthread_mutex_unlock(&crypto_locks[type]); | |
61 | } | |
62 | } | |
63 | ||
64 | void | |
65 | hammer2_crypto_setup(void) | |
66 | { | |
67 | crypto_count = CRYPTO_num_locks(); | |
68 | crypto_locks = calloc(crypto_count, sizeof(crypto_locks[0])); | |
69 | CRYPTO_set_id_callback(hammer2_crypto_id_callback); | |
70 | CRYPTO_set_locking_callback(hammer2_crypto_locking_callback); | |
71 | } | |
72 | ||
62efe6ec MD |
73 | /* |
74 | * Synchronously negotiate crypto for a new session. This must occur | |
75 | * within 10 seconds or the connection is error'd out. | |
76 | * | |
77 | * We work off the IP address and/or reverse DNS. The IP address is | |
78 | * checked first, followed by the IP address at various levels of granularity, | |
79 | * followed by the full domain name and domain names at various levels of | |
80 | * granularity. | |
81 | * | |
82 | * /etc/hammer2/remote/<name>.pub - Contains a public key | |
83 | * /etc/hammer2/remote/<name>.none - Indicates no encryption (empty file) | |
84 | * (e.g. localhost.none). | |
85 | * | |
86 | * We first attempt to locate a public key file based on the peer address or | |
87 | * peer FQDN. | |
88 | * | |
89 | * <name>.none - No further negotiation is needed. We simply return. | |
90 | * All communication proceeds without encryption. | |
91 | * No public key handshake occurs in this situation. | |
92 | * (both ends must match). | |
93 | * | |
94 | * <name>.pub - We have located the public key for the peer. Both | |
95 | * sides transmit a block encrypted with their private | |
96 | * keys and the peer's public key. | |
97 | * | |
98 | * Both sides receive a block and decrypt it. | |
99 | * | |
100 | * Both sides formulate a reply using the decrypted | |
101 | * block and transmit it. | |
102 | * | |
103 | * communication proceeds with the negotiated session | |
104 | * key (typically AES-256-CBC). | |
105 | * | |
106 | * If we fail to locate the appropriate file and no floating.db exists the | |
107 | * connection is terminated without further action. | |
108 | * | |
109 | * If floating.db exists the connection proceeds with a floating negotiation. | |
110 | */ | |
111 | typedef union { | |
112 | struct sockaddr sa; | |
113 | struct sockaddr_in sa_in; | |
114 | struct sockaddr_in6 sa_in6; | |
115 | } sockaddr_any_t; | |
116 | ||
117 | void | |
118 | hammer2_crypto_negotiate(hammer2_iocom_t *iocom) | |
119 | { | |
120 | sockaddr_any_t sa; | |
121 | socklen_t salen = sizeof(sa); | |
122 | char peername[128]; | |
123 | char realname[128]; | |
124 | hammer2_handshake_t handtx; | |
125 | hammer2_handshake_t handrx; | |
5cf97ec5 MD |
126 | char buf1[sizeof(handtx)]; |
127 | char buf2[sizeof(handtx)]; | |
62efe6ec MD |
128 | char *ptr; |
129 | char *path; | |
130 | struct stat st; | |
131 | FILE *fp; | |
132 | RSA *keys[3] = { NULL, NULL, NULL }; | |
133 | size_t i; | |
134 | size_t blksize; | |
135 | size_t blkmask; | |
136 | ssize_t n; | |
137 | int fd; | |
138 | ||
139 | /* | |
140 | * Get the peer IP address for the connection as a string. | |
141 | */ | |
142 | if (getpeername(iocom->sock_fd, &sa.sa, &salen) < 0) { | |
143 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOPEER; | |
144 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
145 | if (DebugOpt) | |
146 | fprintf(stderr, "accept: getpeername() failed\n"); | |
147 | goto done; | |
148 | } | |
149 | if (getnameinfo(&sa.sa, salen, peername, sizeof(peername), | |
150 | NULL, 0, NI_NUMERICHOST) < 0) { | |
151 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOPEER; | |
152 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
153 | if (DebugOpt) | |
154 | fprintf(stderr, "accept: cannot decode sockaddr\n"); | |
155 | goto done; | |
156 | } | |
157 | if (DebugOpt) { | |
158 | if (realhostname_sa(realname, sizeof(realname), | |
159 | &sa.sa, salen) == HOSTNAME_FOUND) { | |
160 | fprintf(stderr, "accept from %s (%s)\n", | |
161 | peername, realname); | |
162 | } else { | |
163 | fprintf(stderr, "accept from %s\n", peername); | |
164 | } | |
165 | } | |
166 | ||
167 | /* | |
168 | * Find the remote host's public key | |
9b8b748f MD |
169 | * |
170 | * If the link is not to be encrypted (<ip>.none located) we shortcut | |
171 | * the handshake entirely. No buffers are exchanged. | |
62efe6ec MD |
172 | */ |
173 | asprintf(&path, "%s/%s.pub", HAMMER2_PATH_REMOTE, peername); | |
174 | if ((fp = fopen(path, "r")) == NULL) { | |
175 | free(path); | |
176 | asprintf(&path, "%s/%s.none", | |
177 | HAMMER2_PATH_REMOTE, peername); | |
178 | if (stat(path, &st) < 0) { | |
179 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NORKEY; | |
180 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
181 | if (DebugOpt) | |
182 | fprintf(stderr, "auth failure: unknown host\n"); | |
183 | goto done; | |
184 | } | |
185 | if (DebugOpt) | |
186 | fprintf(stderr, "auth succeeded, unencrypted link\n"); | |
9b8b748f | 187 | goto done; |
62efe6ec MD |
188 | } |
189 | if (fp) { | |
190 | keys[0] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); | |
191 | fclose(fp); | |
192 | if (keys[0] == NULL) { | |
193 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
194 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
195 | if (DebugOpt) | |
196 | fprintf(stderr, | |
197 | "auth failure: bad key format\n"); | |
198 | goto done; | |
199 | } | |
200 | } | |
201 | ||
202 | /* | |
203 | * Get our public and private keys | |
204 | */ | |
205 | free(path); | |
206 | asprintf(&path, HAMMER2_DEFAULT_DIR "/rsa.pub"); | |
207 | if ((fp = fopen(path, "r")) == NULL) { | |
208 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOLKEY; | |
209 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
210 | goto done; | |
211 | } | |
212 | keys[1] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL); | |
213 | fclose(fp); | |
214 | if (keys[1] == NULL) { | |
215 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
216 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
217 | if (DebugOpt) | |
218 | fprintf(stderr, "auth failure: bad host key format\n"); | |
219 | goto done; | |
220 | } | |
221 | ||
222 | free(path); | |
223 | asprintf(&path, HAMMER2_DEFAULT_DIR "/rsa.prv"); | |
224 | if ((fp = fopen(path, "r")) == NULL) { | |
225 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOLKEY; | |
226 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
227 | if (DebugOpt) | |
228 | fprintf(stderr, "auth failure: bad host key format\n"); | |
229 | goto done; | |
230 | } | |
231 | keys[2] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); | |
232 | fclose(fp); | |
233 | if (keys[2] == NULL) { | |
234 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
235 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
236 | if (DebugOpt) | |
237 | fprintf(stderr, "auth failure: bad host key format\n"); | |
238 | goto done; | |
239 | } | |
240 | free(path); | |
241 | path = NULL; | |
242 | ||
243 | /* | |
244 | * public key encrypt/decrypt block size. | |
245 | */ | |
246 | if (keys[0]) { | |
247 | blksize = (size_t)RSA_size(keys[0]); | |
248 | if (blksize != (size_t)RSA_size(keys[1]) || | |
249 | blksize != (size_t)RSA_size(keys[2]) || | |
250 | sizeof(handtx) % blksize != 0) { | |
251 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT; | |
252 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
253 | if (DebugOpt) | |
254 | fprintf(stderr, "auth failure: " | |
255 | "key size mismatch\n"); | |
256 | goto done; | |
257 | } | |
258 | } else { | |
259 | blksize = sizeof(handtx); | |
260 | } | |
261 | blkmask = blksize - 1; | |
262 | ||
263 | bzero(&handrx, sizeof(handrx)); | |
264 | bzero(&handtx, sizeof(handtx)); | |
265 | ||
266 | /* | |
267 | * Fill all unused fields (particular all junk fields) with random | |
268 | * data, and also set the session key. | |
269 | */ | |
270 | fd = open("/dev/urandom", O_RDONLY); | |
271 | if (fd < 0 || | |
272 | fstat(fd, &st) < 0 || /* something wrong */ | |
273 | S_ISREG(st.st_mode) || /* supposed to be a RNG dev! */ | |
274 | read(fd, &handtx, sizeof(handtx)) != sizeof(handtx)) { | |
275 | urandfail: | |
276 | if (fd >= 0) | |
277 | close(fd); | |
278 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_BADURANDOM; | |
279 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
280 | if (DebugOpt) | |
281 | fprintf(stderr, "auth failure: bad rng\n"); | |
282 | goto done; | |
283 | } | |
284 | if (bcmp(&handrx, &handtx, sizeof(handtx)) == 0) | |
285 | goto urandfail; /* read all zeros */ | |
286 | close(fd); | |
5cf97ec5 | 287 | /* ERR_load_crypto_strings(); openssl debugging */ |
62efe6ec MD |
288 | |
289 | /* | |
290 | * Handshake with the remote. | |
291 | * | |
292 | * Encrypt with my private and remote's public | |
293 | * Decrypt with my private and remote's public | |
294 | * | |
295 | * When encrypting we have to make sure our buffer fits within the | |
296 | * modulus, which typically requires bit 7 o the first byte to be | |
297 | * zero. To be safe make sure that bit 7 and bit 6 is zero. | |
298 | */ | |
299 | snprintf(handtx.quickmsg, sizeof(handtx.quickmsg), "Testing 1 2 3"); | |
300 | handtx.magic = HAMMER2_MSGHDR_MAGIC; | |
301 | handtx.version = 1; | |
302 | handtx.flags = 0; | |
303 | assert(sizeof(handtx.verf) * 4 == sizeof(handtx.sess)); | |
304 | bzero(handtx.verf, sizeof(handtx.verf)); | |
305 | ||
306 | handtx.pad1[0] &= 0x3f; /* message must fit within modulus */ | |
307 | handtx.pad2[0] &= 0x3f; /* message must fit within modulus */ | |
308 | ||
309 | for (i = 0; i < sizeof(handtx.sess); ++i) | |
310 | handtx.verf[i / 4] ^= handtx.sess[i]; | |
311 | ||
312 | /* | |
313 | * Write handshake buffer to remote | |
314 | */ | |
315 | for (i = 0; i < sizeof(handtx); i += blksize) { | |
316 | ptr = (char *)&handtx + i; | |
317 | if (keys[0]) { | |
318 | /* | |
319 | * Since we are double-encrypting we have to make | |
320 | * sure that the result of the first stage does | |
321 | * not blow out the modulus for the second stage. | |
322 | * | |
323 | * The pointer is pointing to the pad*[] area so | |
324 | * we can mess with that until the first stage | |
325 | * is legal. | |
326 | */ | |
327 | do { | |
328 | ++*(int *)(ptr + 4); | |
5cf97ec5 | 329 | if (RSA_private_encrypt(blksize, ptr, buf1, |
62efe6ec MD |
330 | keys[2], RSA_NO_PADDING) < 0) { |
331 | iocom->ioq_rx.error = | |
332 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
333 | } | |
5cf97ec5 | 334 | } while (buf1[0] & 0xC0); |
62efe6ec | 335 | |
5cf97ec5 | 336 | if (RSA_public_encrypt(blksize, buf1, buf2, |
62efe6ec MD |
337 | keys[0], RSA_NO_PADDING) < 0) { |
338 | iocom->ioq_rx.error = | |
339 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
340 | } | |
341 | } | |
5cf97ec5 | 342 | if (write(iocom->sock_fd, buf2, blksize) != (ssize_t)blksize) { |
62efe6ec MD |
343 | fprintf(stderr, "WRITE ERROR\n"); |
344 | } | |
345 | } | |
346 | if (iocom->ioq_rx.error) { | |
347 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
348 | if (DebugOpt) | |
349 | fprintf(stderr, "auth failure: key exchange failure " | |
350 | "during encryption\n"); | |
351 | goto done; | |
352 | } | |
353 | ||
354 | /* | |
355 | * Read handshake buffer from remote | |
356 | */ | |
357 | i = 0; | |
358 | while (i < sizeof(handrx)) { | |
359 | ptr = (char *)&handrx + i; | |
360 | n = read(iocom->sock_fd, ptr, blksize - (i & blkmask)); | |
361 | if (n <= 0) | |
362 | break; | |
363 | ptr -= (i & blkmask); | |
364 | i += n; | |
365 | if (keys[0] && (i & blkmask) == 0) { | |
5cf97ec5 | 366 | if (RSA_private_decrypt(blksize, ptr, buf1, |
62efe6ec MD |
367 | keys[2], RSA_NO_PADDING) < 0) |
368 | iocom->ioq_rx.error = | |
369 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
5cf97ec5 | 370 | if (RSA_public_decrypt(blksize, buf1, ptr, |
62efe6ec MD |
371 | keys[0], RSA_NO_PADDING) < 0) |
372 | iocom->ioq_rx.error = | |
373 | HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
374 | } | |
375 | } | |
376 | if (iocom->ioq_rx.error) { | |
377 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
378 | if (DebugOpt) | |
379 | fprintf(stderr, "auth failure: key exchange failure " | |
380 | "during decryption\n"); | |
381 | goto done; | |
382 | } | |
383 | ||
384 | /* | |
385 | * Validate the received data. Try to make this a constant-time | |
386 | * algorithm. | |
387 | */ | |
388 | if (i != sizeof(handrx)) { | |
389 | keyxchgfail: | |
390 | iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYXCHGFAIL; | |
391 | iocom->flags |= HAMMER2_IOCOMF_EOF; | |
392 | if (DebugOpt) | |
393 | fprintf(stderr, "auth failure: key exchange failure\n"); | |
394 | goto done; | |
395 | } | |
396 | ||
397 | if (handrx.magic == HAMMER2_MSGHDR_MAGIC_REV) { | |
398 | handrx.version = bswap16(handrx.version); | |
399 | handrx.flags = bswap32(handrx.flags); | |
400 | } | |
401 | for (i = 0; i < sizeof(handrx.sess); ++i) | |
402 | handrx.verf[i / 4] ^= handrx.sess[i]; | |
403 | n = 0; | |
404 | for (i = 0; i < sizeof(handrx.verf); ++i) | |
405 | n += handrx.verf[i]; | |
406 | if (handrx.version != 1) | |
407 | ++n; | |
408 | if (n != 0) | |
409 | goto keyxchgfail; | |
410 | ||
5cf97ec5 MD |
411 | /* |
412 | * Calculate the session key and initialize the iv[]. | |
413 | */ | |
414 | assert(HAMMER2_AES_KEY_SIZE * 2 == sizeof(handrx.sess)); | |
415 | for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i) { | |
416 | iocom->sess[i] = handrx.sess[i] ^ handtx.sess[i]; | |
417 | iocom->ioq_rx.iv[i] = handrx.sess[HAMMER2_AES_KEY_SIZE + i] ^ | |
418 | handtx.sess[HAMMER2_AES_KEY_SIZE + i]; | |
419 | iocom->ioq_tx.iv[i] = handrx.sess[HAMMER2_AES_KEY_SIZE + i] ^ | |
420 | handtx.sess[HAMMER2_AES_KEY_SIZE + i]; | |
62efe6ec | 421 | } |
5cf97ec5 MD |
422 | printf("sess: "); |
423 | for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i) | |
424 | printf("%02x", (unsigned char)iocom->sess[i]); | |
425 | printf("\n"); | |
426 | printf("iv: "); | |
427 | for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i) | |
428 | printf("%02x", (unsigned char)iocom->ioq_rx.iv[i]); | |
429 | printf("\n"); | |
430 | ||
431 | EVP_CIPHER_CTX_init(&iocom->ioq_rx.ctx); | |
432 | EVP_DecryptInit_ex(&iocom->ioq_rx.ctx, HAMMER2_AES_TYPE_EVP, NULL, | |
433 | iocom->sess, iocom->ioq_rx.iv); | |
434 | EVP_CIPHER_CTX_set_padding(&iocom->ioq_rx.ctx, 0); | |
435 | ||
436 | EVP_CIPHER_CTX_init(&iocom->ioq_tx.ctx); | |
437 | EVP_EncryptInit_ex(&iocom->ioq_tx.ctx, HAMMER2_AES_TYPE_EVP, NULL, | |
438 | iocom->sess, iocom->ioq_tx.iv); | |
439 | EVP_CIPHER_CTX_set_padding(&iocom->ioq_tx.ctx, 0); | |
440 | ||
441 | iocom->flags |= HAMMER2_IOCOMF_CRYPTED; | |
442 | ||
443 | if (DebugOpt) | |
444 | fprintf(stderr, "auth success: %s\n", handrx.quickmsg); | |
62efe6ec MD |
445 | done: |
446 | if (path) | |
447 | free(path); | |
448 | if (keys[0]) | |
449 | RSA_free(keys[0]); | |
450 | if (keys[1]) | |
451 | RSA_free(keys[1]); | |
452 | if (keys[1]) | |
453 | RSA_free(keys[2]); | |
454 | } | |
5cf97ec5 MD |
455 | |
456 | /* | |
457 | * Decrypt pending data in the ioq's fifo. The data is decrypted in-place. | |
458 | */ | |
459 | void | |
3033ecc8 | 460 | hammer2_crypto_decrypt(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq) |
5cf97ec5 MD |
461 | { |
462 | int p_len; | |
463 | int n; | |
464 | int i; | |
465 | char buf[512]; | |
466 | ||
3033ecc8 | 467 | p_len = ioq->fifo_end - ioq->fifo_cdn; |
5cf97ec5 | 468 | p_len &= ~HAMMER2_AES_KEY_MASK; |
3033ecc8 | 469 | |
5cf97ec5 MD |
470 | if (p_len == 0) |
471 | return; | |
472 | for (i = 0; i < p_len; i += n) { | |
473 | n = (p_len - i > (int)sizeof(buf)) ? | |
474 | (int)sizeof(buf) : p_len - i; | |
475 | bcopy(ioq->buf + ioq->fifo_cdx + i, buf, n); | |
476 | EVP_DecryptUpdate(&ioq->ctx, | |
477 | ioq->buf + ioq->fifo_cdx + i, &n, | |
478 | buf, n); | |
479 | } | |
480 | ioq->fifo_cdx += p_len; | |
3033ecc8 | 481 | ioq->fifo_cdn += p_len; |
5cf97ec5 MD |
482 | } |
483 | ||
484 | /* | |
3033ecc8 MD |
485 | * *nactp is set to the number of ORIGINAL bytes consumed by the encrypter. |
486 | * The FIFO may contain more data. | |
5cf97ec5 | 487 | */ |
5cf97ec5 | 488 | int |
3033ecc8 MD |
489 | hammer2_crypto_encrypt(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq, |
490 | struct iovec *iov, int n, size_t *nactp) | |
5cf97ec5 MD |
491 | { |
492 | int p_len; | |
493 | int i; | |
3033ecc8 | 494 | size_t nmax; |
5cf97ec5 | 495 | |
3033ecc8 | 496 | nmax = sizeof(ioq->buf) - ioq->fifo_end; /* max new bytes */ |
5cf97ec5 | 497 | |
3033ecc8 MD |
498 | *nactp = 0; |
499 | for (i = 0; i < n && nmax; ++i) { | |
5cf97ec5 | 500 | p_len = iov[i].iov_len; |
3033ecc8 MD |
501 | assert((p_len & HAMMER2_AES_KEY_MASK) == 0); |
502 | if ((size_t)p_len > nmax) | |
503 | p_len = (int)nmax; | |
504 | *nactp += (size_t)p_len; /* plaintext count */ | |
5cf97ec5 MD |
505 | EVP_EncryptUpdate(&ioq->ctx, |
506 | ioq->buf + ioq->fifo_cdx, &p_len, | |
3033ecc8 MD |
507 | (char *)iov[i].iov_base, p_len); |
508 | assert((size_t)p_len == iov[i].iov_len); | |
509 | ioq->fifo_cdx += (size_t)p_len; /* crypted count */ | |
510 | ioq->fifo_cdn += (size_t)p_len; /* crypted count */ | |
511 | ioq->fifo_end += (size_t)p_len; | |
512 | nmax -= (size_t)p_len; | |
5cf97ec5 MD |
513 | if (nmax == 0) |
514 | break; | |
5cf97ec5 MD |
515 | } |
516 | iov[0].iov_base = ioq->buf + ioq->fifo_beg; | |
517 | iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg; | |
518 | ||
519 | return (1); | |
520 | } |