hammer2 - error out on enc/dec errors
[dragonfly.git] / sbin / hammer2 / crypto.c
CommitLineData
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>
766ad73f 7 * by Alex Hornung <alexh@dragonflybsd.org>
62efe6ec
MD
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#include "hammer2.h"
38
62efe6ec 39/*
02454b3e
MD
40 * Setup crypto for pthreads
41 */
42static pthread_mutex_t *crypto_locks;
43int crypto_count;
44
45static
46unsigned long
47hammer2_crypto_id_callback(void)
48{
49 return ((unsigned long)(uintptr_t)pthread_self());
50}
51
52static
53void
54hammer2_crypto_locking_callback(int mode, int type,
55 const char *file __unused, int line __unused)
56{
57 assert(type >= 0 && type < crypto_count);
58 if (mode & CRYPTO_LOCK) {
59 pthread_mutex_lock(&crypto_locks[type]);
60 } else {
61 pthread_mutex_unlock(&crypto_locks[type]);
62 }
63}
64
65void
66hammer2_crypto_setup(void)
67{
68 crypto_count = CRYPTO_num_locks();
69 crypto_locks = calloc(crypto_count, sizeof(crypto_locks[0]));
70 CRYPTO_set_id_callback(hammer2_crypto_id_callback);
71 CRYPTO_set_locking_callback(hammer2_crypto_locking_callback);
72}
73
766ad73f
AH
74static
75int
76_gcm_init(hammer2_ioq_t *ioq, char *key, int klen, char *iv_fixed, int ivlen,
77 int enc)
78{
79 int i, ok;
80
81 if (klen < 32 /* 256 bits */ || ivlen < 4 /* 32 bits */) {
82 if (DebugOpt)
83 fprintf(stderr, "Not enough key or iv material\n");
84 return -1;
85 }
86
87 printf("%s key: ", enc ? "Encryption" : "Decryption");
88 for (i = 0; i < HAMMER2_AES_KEY_SIZE; ++i)
89 printf("%02x", (unsigned char)key[i]);
90 printf("\n");
91
92 printf("%s iv: ", enc ? "Encryption" : "Decryption");
93 for (i = 0; i < HAMMER2_CRYPTO_IV_FIXED_SIZE; ++i)
94 printf("%02x", (unsigned char)iv_fixed[i]);
95 printf(" (fixed part only)\n");
96
97
98 EVP_CIPHER_CTX_init(&ioq->ctx);
99
100 if (enc)
101 ok = EVP_EncryptInit_ex(&ioq->ctx, EVP_aes_256_gcm(), NULL,
102 key, NULL);
103 else
104 ok = EVP_DecryptInit_ex(&ioq->ctx, EVP_aes_256_gcm(), NULL,
105 key, NULL);
106 if (!ok)
107 goto fail;
108
109 /*
110 * According to the original Galois/Counter Mode of Operation (GCM)
111 * proposal, only IVs that are exactly 96 bits get used without any
112 * further processing. Other IV sizes cause the GHASH() operation
113 * to be applied to the IV, which is more costly.
114 *
115 * The NIST SP 800-38D also recommends using a 96 bit IV for the same
116 * reasons. We actually follow the deterministic construction
117 * recommended in NIST SP 800-38D with a 64 bit invocation field as an
118 * integer counter and a random, session-specific fixed field.
119 *
120 * This means that we can essentially use the same session key and
121 * IV fixed field for up to 2^64 invocations of the authenticated
122 * encryption or decryption.
123 *
124 * With a chunk size of 64 bytes, this adds up to 1 zettabyte of
125 * traffic.
126 */
127 ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_IVLEN,
128 HAMMER2_CRYPTO_IV_SIZE, NULL);
129 if (!ok)
130 goto fail;
131
132 memset(ioq->iv, 0, HAMMER2_CRYPTO_IV_SIZE);
133 memcpy(ioq->iv, iv_fixed, HAMMER2_CRYPTO_IV_FIXED_SIZE);
134
135 /*
136 * Strictly speaking, padding is irrelevant with a counter mode
137 * encryption.
138 *
139 * However, setting padding to 0, even if using a counter mode such
140 * as GCM, will cause an error in _finish if the pt/ct size is not
141 * a multiple of the cipher block size.
142 */
143 EVP_CIPHER_CTX_set_padding(&ioq->ctx, 0);
144
145 return 0;
146
147fail:
148 if (DebugOpt)
149 fprintf(stderr, "Error during _gcm_init\n");
150 return -1;
151}
152
153static
154int
155_gcm_iv_increment(char *iv)
156{
157 /*
158 * Deterministic construction according to NIST SP 800-38D, with
159 * 64 bit invocation field as integer counter.
160 *
161 * In other words, our 96 bit IV consists of a 32 bit fixed field
162 * unique to the session and a 64 bit integer counter.
163 */
164
165 uint64_t *c = (uint64_t *)(&iv[HAMMER2_CRYPTO_IV_FIXED_SIZE]);
166
167 /* Increment invocation field integer counter */
168 /*
169 * XXX: this should ideally be an atomic update, but we don't have
170 * an atomic_fetchadd_64 for i386 yet
171 */
172 *c = (*c)+1;
173
174 /*
175 * Detect wrap-around, which means it is time to renegotiate
176 * the session to get a new key and/or fixed field.
177 */
fd1d02a5 178 return (c == 0) ? 0 : 1;
766ad73f
AH
179}
180
181static
182int
183hammer2_crypto_encrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
184 int in_size, int *out_size)
185{
186 int ok;
187#ifdef CRYPTO_DEBUG
188 int i;
189#endif
190 int u_len, f_len;
191
192 *out_size = 0;
193
194 /* Re-initialize with new IV (but without redoing the key schedule) */
195 ok = EVP_EncryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
196 if (!ok)
197 goto fail;
198
199 ok = EVP_EncryptUpdate(&ioq->ctx, ct, &u_len, pt, in_size);
200 if (!ok)
201 goto fail;
202
203 ok = EVP_EncryptFinal(&ioq->ctx, ct + u_len, &f_len);
204 if (!ok)
205 goto fail;
206
207 /* Retrieve auth tag */
208 ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_GET_TAG,
209 HAMMER2_CRYPTO_TAG_SIZE,
210 ct + u_len + f_len);
211 if (!ok)
212 goto fail;
213
214#ifdef CRYPTO_DEBUG
215 printf("enc_chunk iv: ");
216 for (i = 0; i < HAMMER2_CRYPTO_IV_SIZE; i++)
217 printf("%02x", (unsigned char)ioq->iv[i]);
218 printf("\n");
219
220 printf("enc_chunk pt: ");
221 for (i = 0; i < in_size; i++)
222 printf("%02x", (unsigned char)pt[i]);
223 printf("\n");
224
225 printf("enc_chunk ct: ");
226 for (i = 0; i < in_size; i++)
227 printf("%02x", (unsigned char)ct[i]);
228 printf("\n");
229
230 printf("enc_chunk tag: ");
231 for (i = 0; i < HAMMER2_CRYPTO_TAG_SIZE; i++)
232 printf("%02x", (unsigned char)ct[i + u_len + f_len]);
233 printf("\n");
234#endif
235
fd1d02a5
AH
236 ok = _gcm_iv_increment(ioq->iv);
237 if (!ok) {
238 ioq->error = HAMMER2_IOQ_ERROR_IVWRAP;
239 goto fail_out;
240 }
766ad73f
AH
241
242 *out_size = u_len + f_len + HAMMER2_CRYPTO_TAG_SIZE;
243
244 return 0;
245
246fail:
fd1d02a5
AH
247 ioq->error = HAMMER2_IOQ_ERROR_ALGO;
248fail_out:
766ad73f
AH
249 if (DebugOpt)
250 fprintf(stderr, "error during encrypt_chunk\n");
251 return -1;
252}
253
254static
255int
256hammer2_crypto_decrypt_chunk(hammer2_ioq_t *ioq, char *ct, char *pt,
257 int out_size, int *consume_size)
258{
259 int ok;
260#ifdef CRYPTO_DEBUG
261 int i;
262#endif
263 int u_len, f_len;
264
265 *consume_size = 0;
266
267 /* Re-initialize with new IV (but without redoing the key schedule) */
268 ok = EVP_DecryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
fd1d02a5
AH
269 if (!ok) {
270 ioq->error = HAMMER2_IOQ_ERROR_ALGO;
271 goto fail_out;
272 }
766ad73f
AH
273
274#ifdef CRYPTO_DEBUG
275 printf("dec_chunk iv: ");
276 for (i = 0; i < HAMMER2_CRYPTO_IV_SIZE; i++)
277 printf("%02x", (unsigned char)ioq->iv[i]);
278 printf("\n");
279
280 printf("dec_chunk ct: ");
281 for (i = 0; i < out_size; i++)
282 printf("%02x", (unsigned char)ct[i]);
283 printf("\n");
284
285 printf("dec_chunk tag: ");
286 for (i = 0; i < HAMMER2_CRYPTO_TAG_SIZE; i++)
287 printf("%02x", (unsigned char)ct[out_size + i]);
288 printf("\n");
289#endif
290
291 ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_TAG,
292 HAMMER2_CRYPTO_TAG_SIZE,
293 ct + out_size);
fd1d02a5
AH
294 if (!ok) {
295 ioq->error = HAMMER2_IOQ_ERROR_ALGO;
296 goto fail_out;
297 }
766ad73f
AH
298
299 ok = EVP_DecryptUpdate(&ioq->ctx, pt, &u_len, ct, out_size);
300 if (!ok)
301 goto fail;
302
303 ok = EVP_DecryptFinal(&ioq->ctx, pt + u_len, &f_len);
304 if (!ok)
305 goto fail;
306
fd1d02a5
AH
307 ok = _gcm_iv_increment(ioq->iv);
308 if (!ok) {
309 ioq->error = HAMMER2_IOQ_ERROR_IVWRAP;
310 goto fail_out;
311 }
766ad73f
AH
312
313 *consume_size = u_len + f_len + HAMMER2_CRYPTO_TAG_SIZE;
314
315#ifdef CRYPTO_DEBUG
316 printf("dec_chunk pt: ");
317 for (i = 0; i < out_size; i++)
318 printf("%02x", (unsigned char)pt[i]);
319 printf("\n");
320#endif
321
322 return 0;
323
324fail:
fd1d02a5
AH
325 ioq->error = HAMMER2_IOQ_ERROR_MACFAIL;
326fail_out:
766ad73f
AH
327 if (DebugOpt)
328 fprintf(stderr, "error during decrypt_chunk (likely authentication error)\n");
329 return -1;
330}
331
02454b3e 332/*
62efe6ec
MD
333 * Synchronously negotiate crypto for a new session. This must occur
334 * within 10 seconds or the connection is error'd out.
335 *
336 * We work off the IP address and/or reverse DNS. The IP address is
337 * checked first, followed by the IP address at various levels of granularity,
338 * followed by the full domain name and domain names at various levels of
339 * granularity.
340 *
341 * /etc/hammer2/remote/<name>.pub - Contains a public key
342 * /etc/hammer2/remote/<name>.none - Indicates no encryption (empty file)
343 * (e.g. localhost.none).
344 *
345 * We first attempt to locate a public key file based on the peer address or
346 * peer FQDN.
347 *
348 * <name>.none - No further negotiation is needed. We simply return.
349 * All communication proceeds without encryption.
350 * No public key handshake occurs in this situation.
351 * (both ends must match).
352 *
353 * <name>.pub - We have located the public key for the peer. Both
354 * sides transmit a block encrypted with their private
355 * keys and the peer's public key.
356 *
357 * Both sides receive a block and decrypt it.
358 *
359 * Both sides formulate a reply using the decrypted
360 * block and transmit it.
361 *
362 * communication proceeds with the negotiated session
363 * key (typically AES-256-CBC).
364 *
365 * If we fail to locate the appropriate file and no floating.db exists the
366 * connection is terminated without further action.
367 *
368 * If floating.db exists the connection proceeds with a floating negotiation.
369 */
370typedef union {
371 struct sockaddr sa;
372 struct sockaddr_in sa_in;
373 struct sockaddr_in6 sa_in6;
374} sockaddr_any_t;
375
376void
377hammer2_crypto_negotiate(hammer2_iocom_t *iocom)
378{
379 sockaddr_any_t sa;
380 socklen_t salen = sizeof(sa);
381 char peername[128];
382 char realname[128];
383 hammer2_handshake_t handtx;
384 hammer2_handshake_t handrx;
5cf97ec5
MD
385 char buf1[sizeof(handtx)];
386 char buf2[sizeof(handtx)];
62efe6ec
MD
387 char *ptr;
388 char *path;
389 struct stat st;
390 FILE *fp;
391 RSA *keys[3] = { NULL, NULL, NULL };
392 size_t i;
393 size_t blksize;
394 size_t blkmask;
395 ssize_t n;
396 int fd;
766ad73f 397 int error;
62efe6ec
MD
398
399 /*
400 * Get the peer IP address for the connection as a string.
401 */
402 if (getpeername(iocom->sock_fd, &sa.sa, &salen) < 0) {
403 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOPEER;
404 iocom->flags |= HAMMER2_IOCOMF_EOF;
405 if (DebugOpt)
406 fprintf(stderr, "accept: getpeername() failed\n");
407 goto done;
408 }
409 if (getnameinfo(&sa.sa, salen, peername, sizeof(peername),
410 NULL, 0, NI_NUMERICHOST) < 0) {
411 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOPEER;
412 iocom->flags |= HAMMER2_IOCOMF_EOF;
413 if (DebugOpt)
414 fprintf(stderr, "accept: cannot decode sockaddr\n");
415 goto done;
416 }
417 if (DebugOpt) {
418 if (realhostname_sa(realname, sizeof(realname),
419 &sa.sa, salen) == HOSTNAME_FOUND) {
420 fprintf(stderr, "accept from %s (%s)\n",
421 peername, realname);
422 } else {
423 fprintf(stderr, "accept from %s\n", peername);
424 }
425 }
426
427 /*
428 * Find the remote host's public key
9b8b748f
MD
429 *
430 * If the link is not to be encrypted (<ip>.none located) we shortcut
431 * the handshake entirely. No buffers are exchanged.
62efe6ec
MD
432 */
433 asprintf(&path, "%s/%s.pub", HAMMER2_PATH_REMOTE, peername);
434 if ((fp = fopen(path, "r")) == NULL) {
435 free(path);
436 asprintf(&path, "%s/%s.none",
437 HAMMER2_PATH_REMOTE, peername);
438 if (stat(path, &st) < 0) {
439 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NORKEY;
440 iocom->flags |= HAMMER2_IOCOMF_EOF;
441 if (DebugOpt)
442 fprintf(stderr, "auth failure: unknown host\n");
443 goto done;
444 }
445 if (DebugOpt)
446 fprintf(stderr, "auth succeeded, unencrypted link\n");
9b8b748f 447 goto done;
62efe6ec
MD
448 }
449 if (fp) {
450 keys[0] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
451 fclose(fp);
452 if (keys[0] == NULL) {
453 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT;
454 iocom->flags |= HAMMER2_IOCOMF_EOF;
455 if (DebugOpt)
456 fprintf(stderr,
457 "auth failure: bad key format\n");
458 goto done;
459 }
460 }
461
462 /*
463 * Get our public and private keys
464 */
465 free(path);
466 asprintf(&path, HAMMER2_DEFAULT_DIR "/rsa.pub");
467 if ((fp = fopen(path, "r")) == NULL) {
468 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOLKEY;
469 iocom->flags |= HAMMER2_IOCOMF_EOF;
470 goto done;
471 }
472 keys[1] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
473 fclose(fp);
474 if (keys[1] == NULL) {
475 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT;
476 iocom->flags |= HAMMER2_IOCOMF_EOF;
477 if (DebugOpt)
478 fprintf(stderr, "auth failure: bad host key format\n");
479 goto done;
480 }
481
482 free(path);
483 asprintf(&path, HAMMER2_DEFAULT_DIR "/rsa.prv");
484 if ((fp = fopen(path, "r")) == NULL) {
485 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_NOLKEY;
486 iocom->flags |= HAMMER2_IOCOMF_EOF;
487 if (DebugOpt)
488 fprintf(stderr, "auth failure: bad host key format\n");
489 goto done;
490 }
491 keys[2] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
492 fclose(fp);
493 if (keys[2] == NULL) {
494 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT;
495 iocom->flags |= HAMMER2_IOCOMF_EOF;
496 if (DebugOpt)
497 fprintf(stderr, "auth failure: bad host key format\n");
498 goto done;
499 }
500 free(path);
501 path = NULL;
502
503 /*
504 * public key encrypt/decrypt block size.
505 */
506 if (keys[0]) {
507 blksize = (size_t)RSA_size(keys[0]);
508 if (blksize != (size_t)RSA_size(keys[1]) ||
509 blksize != (size_t)RSA_size(keys[2]) ||
510 sizeof(handtx) % blksize != 0) {
511 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYFMT;
512 iocom->flags |= HAMMER2_IOCOMF_EOF;
513 if (DebugOpt)
514 fprintf(stderr, "auth failure: "
515 "key size mismatch\n");
516 goto done;
517 }
518 } else {
519 blksize = sizeof(handtx);
520 }
521 blkmask = blksize - 1;
522
523 bzero(&handrx, sizeof(handrx));
524 bzero(&handtx, sizeof(handtx));
525
526 /*
527 * Fill all unused fields (particular all junk fields) with random
528 * data, and also set the session key.
529 */
530 fd = open("/dev/urandom", O_RDONLY);
531 if (fd < 0 ||
532 fstat(fd, &st) < 0 || /* something wrong */
533 S_ISREG(st.st_mode) || /* supposed to be a RNG dev! */
534 read(fd, &handtx, sizeof(handtx)) != sizeof(handtx)) {
535urandfail:
536 if (fd >= 0)
537 close(fd);
538 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_BADURANDOM;
539 iocom->flags |= HAMMER2_IOCOMF_EOF;
540 if (DebugOpt)
541 fprintf(stderr, "auth failure: bad rng\n");
542 goto done;
543 }
544 if (bcmp(&handrx, &handtx, sizeof(handtx)) == 0)
545 goto urandfail; /* read all zeros */
546 close(fd);
5cf97ec5 547 /* ERR_load_crypto_strings(); openssl debugging */
62efe6ec
MD
548
549 /*
550 * Handshake with the remote.
551 *
552 * Encrypt with my private and remote's public
553 * Decrypt with my private and remote's public
554 *
555 * When encrypting we have to make sure our buffer fits within the
556 * modulus, which typically requires bit 7 o the first byte to be
557 * zero. To be safe make sure that bit 7 and bit 6 is zero.
558 */
559 snprintf(handtx.quickmsg, sizeof(handtx.quickmsg), "Testing 1 2 3");
560 handtx.magic = HAMMER2_MSGHDR_MAGIC;
561 handtx.version = 1;
562 handtx.flags = 0;
563 assert(sizeof(handtx.verf) * 4 == sizeof(handtx.sess));
564 bzero(handtx.verf, sizeof(handtx.verf));
565
566 handtx.pad1[0] &= 0x3f; /* message must fit within modulus */
567 handtx.pad2[0] &= 0x3f; /* message must fit within modulus */
568
569 for (i = 0; i < sizeof(handtx.sess); ++i)
570 handtx.verf[i / 4] ^= handtx.sess[i];
571
572 /*
573 * Write handshake buffer to remote
574 */
575 for (i = 0; i < sizeof(handtx); i += blksize) {
576 ptr = (char *)&handtx + i;
577 if (keys[0]) {
578 /*
579 * Since we are double-encrypting we have to make
580 * sure that the result of the first stage does
581 * not blow out the modulus for the second stage.
582 *
583 * The pointer is pointing to the pad*[] area so
584 * we can mess with that until the first stage
585 * is legal.
586 */
587 do {
588 ++*(int *)(ptr + 4);
5cf97ec5 589 if (RSA_private_encrypt(blksize, ptr, buf1,
62efe6ec
MD
590 keys[2], RSA_NO_PADDING) < 0) {
591 iocom->ioq_rx.error =
592 HAMMER2_IOQ_ERROR_KEYXCHGFAIL;
593 }
5cf97ec5 594 } while (buf1[0] & 0xC0);
62efe6ec 595
5cf97ec5 596 if (RSA_public_encrypt(blksize, buf1, buf2,
62efe6ec
MD
597 keys[0], RSA_NO_PADDING) < 0) {
598 iocom->ioq_rx.error =
599 HAMMER2_IOQ_ERROR_KEYXCHGFAIL;
600 }
601 }
5cf97ec5 602 if (write(iocom->sock_fd, buf2, blksize) != (ssize_t)blksize) {
62efe6ec
MD
603 fprintf(stderr, "WRITE ERROR\n");
604 }
605 }
606 if (iocom->ioq_rx.error) {
607 iocom->flags |= HAMMER2_IOCOMF_EOF;
608 if (DebugOpt)
609 fprintf(stderr, "auth failure: key exchange failure "
610 "during encryption\n");
611 goto done;
612 }
613
614 /*
615 * Read handshake buffer from remote
616 */
617 i = 0;
618 while (i < sizeof(handrx)) {
619 ptr = (char *)&handrx + i;
620 n = read(iocom->sock_fd, ptr, blksize - (i & blkmask));
621 if (n <= 0)
622 break;
623 ptr -= (i & blkmask);
624 i += n;
625 if (keys[0] && (i & blkmask) == 0) {
5cf97ec5 626 if (RSA_private_decrypt(blksize, ptr, buf1,
62efe6ec
MD
627 keys[2], RSA_NO_PADDING) < 0)
628 iocom->ioq_rx.error =
629 HAMMER2_IOQ_ERROR_KEYXCHGFAIL;
5cf97ec5 630 if (RSA_public_decrypt(blksize, buf1, ptr,
62efe6ec
MD
631 keys[0], RSA_NO_PADDING) < 0)
632 iocom->ioq_rx.error =
633 HAMMER2_IOQ_ERROR_KEYXCHGFAIL;
634 }
635 }
636 if (iocom->ioq_rx.error) {
637 iocom->flags |= HAMMER2_IOCOMF_EOF;
638 if (DebugOpt)
639 fprintf(stderr, "auth failure: key exchange failure "
640 "during decryption\n");
641 goto done;
642 }
643
644 /*
645 * Validate the received data. Try to make this a constant-time
646 * algorithm.
647 */
648 if (i != sizeof(handrx)) {
649keyxchgfail:
650 iocom->ioq_rx.error = HAMMER2_IOQ_ERROR_KEYXCHGFAIL;
651 iocom->flags |= HAMMER2_IOCOMF_EOF;
652 if (DebugOpt)
653 fprintf(stderr, "auth failure: key exchange failure\n");
654 goto done;
655 }
656
657 if (handrx.magic == HAMMER2_MSGHDR_MAGIC_REV) {
658 handrx.version = bswap16(handrx.version);
659 handrx.flags = bswap32(handrx.flags);
660 }
661 for (i = 0; i < sizeof(handrx.sess); ++i)
662 handrx.verf[i / 4] ^= handrx.sess[i];
663 n = 0;
664 for (i = 0; i < sizeof(handrx.verf); ++i)
665 n += handrx.verf[i];
666 if (handrx.version != 1)
667 ++n;
668 if (n != 0)
669 goto keyxchgfail;
670
766ad73f 671 assert(HAMMER2_AES_KEY_SIZE * 2 == sizeof(handrx.sess));
5cf97ec5 672 /*
766ad73f
AH
673 * Use separate session keys and session fixed IVs for receive and
674 * transmit.
5cf97ec5 675 */
766ad73f
AH
676 error = _gcm_init(&iocom->ioq_rx, handrx.sess, HAMMER2_AES_KEY_SIZE,
677 handrx.sess + HAMMER2_AES_KEY_SIZE,
678 sizeof(handrx.sess) - HAMMER2_AES_KEY_SIZE,
679 0 /* decryption */);
680 if (error)
681 goto keyxchgfail;
5cf97ec5 682
766ad73f
AH
683 error = _gcm_init(&iocom->ioq_tx, handtx.sess, HAMMER2_AES_KEY_SIZE,
684 handtx.sess + HAMMER2_AES_KEY_SIZE,
685 sizeof(handtx.sess) - HAMMER2_AES_KEY_SIZE,
686 1 /* encryption */);
687 if (error)
688 goto keyxchgfail;
5cf97ec5
MD
689
690 iocom->flags |= HAMMER2_IOCOMF_CRYPTED;
691
692 if (DebugOpt)
693 fprintf(stderr, "auth success: %s\n", handrx.quickmsg);
62efe6ec
MD
694done:
695 if (path)
696 free(path);
697 if (keys[0])
698 RSA_free(keys[0]);
699 if (keys[1])
700 RSA_free(keys[1]);
701 if (keys[1])
702 RSA_free(keys[2]);
703}
5cf97ec5
MD
704
705/*
706 * Decrypt pending data in the ioq's fifo. The data is decrypted in-place.
707 */
708void
3033ecc8 709hammer2_crypto_decrypt(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq)
5cf97ec5
MD
710{
711 int p_len;
766ad73f
AH
712 int used;
713 int error;
5cf97ec5
MD
714 char buf[512];
715
766ad73f
AH
716 /*
717 * fifo_beg to fifo_cdx is data already decrypted.
718 * fifo_cdn to fifo_end is data not yet decrypted.
719 */
720 p_len = ioq->fifo_end - ioq->fifo_cdn; /* data not yet decrypted */
3033ecc8 721
5cf97ec5
MD
722 if (p_len == 0)
723 return;
766ad73f
AH
724
725 while (p_len >= HAMMER2_CRYPTO_TAG_SIZE + HAMMER2_CRYPTO_CHUNK_SIZE) {
726 bcopy(ioq->buf + ioq->fifo_cdn, buf,
727 HAMMER2_CRYPTO_TAG_SIZE + HAMMER2_CRYPTO_CHUNK_SIZE);
728 error = hammer2_crypto_decrypt_chunk(ioq, buf,
729 ioq->buf + ioq->fifo_cdx,
730 HAMMER2_CRYPTO_CHUNK_SIZE,
731 &used);
732#ifdef CRYPTO_DEBUG
733 printf("dec: p_len: %d, used: %d, fifo_cdn: %ju, fifo_cdx: %ju\n",
734 p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
735#endif
736 p_len -= used;
737 ioq->fifo_cdn += used;
738 ioq->fifo_cdx += HAMMER2_CRYPTO_CHUNK_SIZE;
739#ifdef CRYPTO_DEBUG
740 printf("dec: p_len: %d, used: %d, fifo_cdn: %ju, fifo_cdx: %ju\n",
741 p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
742#endif
5cf97ec5 743 }
5cf97ec5
MD
744}
745
746/*
3033ecc8
MD
747 * *nactp is set to the number of ORIGINAL bytes consumed by the encrypter.
748 * The FIFO may contain more data.
5cf97ec5 749 */
5cf97ec5 750int
3033ecc8
MD
751hammer2_crypto_encrypt(hammer2_iocom_t *iocom __unused, hammer2_ioq_t *ioq,
752 struct iovec *iov, int n, size_t *nactp)
5cf97ec5 753{
766ad73f 754 int p_len, used, ct_used;
5cf97ec5 755 int i;
766ad73f 756 int error;
3033ecc8 757 size_t nmax;
5cf97ec5 758
3033ecc8 759 nmax = sizeof(ioq->buf) - ioq->fifo_end; /* max new bytes */
5cf97ec5 760
3033ecc8
MD
761 *nactp = 0;
762 for (i = 0; i < n && nmax; ++i) {
766ad73f 763 used = 0;
5cf97ec5 764 p_len = iov[i].iov_len;
3033ecc8 765 assert((p_len & HAMMER2_AES_KEY_MASK) == 0);
766ad73f
AH
766
767 while (p_len >= HAMMER2_CRYPTO_CHUNK_SIZE &&
768 nmax >= HAMMER2_CRYPTO_CHUNK_SIZE + HAMMER2_CRYPTO_TAG_SIZE) {
769 error = hammer2_crypto_encrypt_chunk(ioq,
770 ioq->buf + ioq->fifo_cdx,
771 (char *)iov[i].iov_base + used,
772 HAMMER2_CRYPTO_CHUNK_SIZE, &ct_used);
773#ifdef CRYPTO_DEBUG
774 printf("nactp: %ju, p_len: %d, ct_used: %d, used: %d, nmax: %ju\n",
775 *nactp, p_len, ct_used, used, nmax);
776#endif
777
778 *nactp += (size_t)HAMMER2_CRYPTO_CHUNK_SIZE; /* plaintext count */
779 used += HAMMER2_CRYPTO_CHUNK_SIZE;
780 p_len -= HAMMER2_CRYPTO_CHUNK_SIZE;
781
782 ioq->fifo_cdx += (size_t)ct_used; /* crypted count */
783 ioq->fifo_cdn += (size_t)ct_used; /* crypted count */
784 ioq->fifo_end += (size_t)ct_used;
785 nmax -= (size_t)ct_used;
786#ifdef CRYPTO_DEBUG
787 printf("nactp: %ju, p_len: %d, ct_used: %d, used: %d, nmax: %ju\n",
788 *nactp, p_len, ct_used, used, nmax);
789#endif
790 }
5cf97ec5
MD
791 }
792 iov[0].iov_base = ioq->buf + ioq->fifo_beg;
793 iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg;
794
795 return (1);
796}