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