diff options
Diffstat (limited to 'cipher.c')
-rw-r--r-- | cipher.c | 81 |
1 files changed, 69 insertions, 12 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.c,v 1.89 2013/05/17 00:13:13 djm Exp $ */ | 1 | /* $OpenBSD: cipher.c,v 1.94 2014/01/25 10:12:50 dtucker Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -43,9 +43,11 @@ | |||
43 | 43 | ||
44 | #include <string.h> | 44 | #include <string.h> |
45 | #include <stdarg.h> | 45 | #include <stdarg.h> |
46 | #include <stdio.h> | ||
46 | 47 | ||
47 | #include "xmalloc.h" | 48 | #include "xmalloc.h" |
48 | #include "log.h" | 49 | #include "log.h" |
50 | #include "misc.h" | ||
49 | #include "cipher.h" | 51 | #include "cipher.h" |
50 | 52 | ||
51 | /* compatibility with old or broken OpenSSL versions */ | 53 | /* compatibility with old or broken OpenSSL versions */ |
@@ -63,7 +65,9 @@ struct Cipher { | |||
63 | u_int iv_len; /* defaults to block_size */ | 65 | u_int iv_len; /* defaults to block_size */ |
64 | u_int auth_len; | 66 | u_int auth_len; |
65 | u_int discard_len; | 67 | u_int discard_len; |
66 | u_int cbc_mode; | 68 | u_int flags; |
69 | #define CFLAG_CBC (1<<0) | ||
70 | #define CFLAG_CHACHAPOLY (1<<1) | ||
67 | const EVP_CIPHER *(*evptype)(void); | 71 | const EVP_CIPHER *(*evptype)(void); |
68 | }; | 72 | }; |
69 | 73 | ||
@@ -95,14 +99,16 @@ static const struct Cipher ciphers[] = { | |||
95 | { "aes256-gcm@openssh.com", | 99 | { "aes256-gcm@openssh.com", |
96 | SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, | 100 | SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, |
97 | #endif | 101 | #endif |
102 | { "chacha20-poly1305@openssh.com", | ||
103 | SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, | ||
98 | { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } | 104 | { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } |
99 | }; | 105 | }; |
100 | 106 | ||
101 | /*--*/ | 107 | /*--*/ |
102 | 108 | ||
103 | /* Returns a comma-separated list of supported ciphers. */ | 109 | /* Returns a list of supported ciphers separated by the specified char. */ |
104 | char * | 110 | char * |
105 | cipher_alg_list(void) | 111 | cipher_alg_list(char sep, int auth_only) |
106 | { | 112 | { |
107 | char *ret = NULL; | 113 | char *ret = NULL; |
108 | size_t nlen, rlen = 0; | 114 | size_t nlen, rlen = 0; |
@@ -111,8 +117,10 @@ cipher_alg_list(void) | |||
111 | for (c = ciphers; c->name != NULL; c++) { | 117 | for (c = ciphers; c->name != NULL; c++) { |
112 | if (c->number != SSH_CIPHER_SSH2) | 118 | if (c->number != SSH_CIPHER_SSH2) |
113 | continue; | 119 | continue; |
120 | if (auth_only && c->auth_len == 0) | ||
121 | continue; | ||
114 | if (ret != NULL) | 122 | if (ret != NULL) |
115 | ret[rlen++] = '\n'; | 123 | ret[rlen++] = sep; |
116 | nlen = strlen(c->name); | 124 | nlen = strlen(c->name); |
117 | ret = xrealloc(ret, 1, rlen + nlen + 2); | 125 | ret = xrealloc(ret, 1, rlen + nlen + 2); |
118 | memcpy(ret + rlen, c->name, nlen + 1); | 126 | memcpy(ret + rlen, c->name, nlen + 1); |
@@ -134,6 +142,14 @@ cipher_keylen(const Cipher *c) | |||
134 | } | 142 | } |
135 | 143 | ||
136 | u_int | 144 | u_int |
145 | cipher_seclen(const Cipher *c) | ||
146 | { | ||
147 | if (strcmp("3des-cbc", c->name) == 0) | ||
148 | return 14; | ||
149 | return cipher_keylen(c); | ||
150 | } | ||
151 | |||
152 | u_int | ||
137 | cipher_authlen(const Cipher *c) | 153 | cipher_authlen(const Cipher *c) |
138 | { | 154 | { |
139 | return (c->auth_len); | 155 | return (c->auth_len); |
@@ -142,7 +158,12 @@ cipher_authlen(const Cipher *c) | |||
142 | u_int | 158 | u_int |
143 | cipher_ivlen(const Cipher *c) | 159 | cipher_ivlen(const Cipher *c) |
144 | { | 160 | { |
145 | return (c->iv_len ? c->iv_len : c->block_size); | 161 | /* |
162 | * Default is cipher block size, except for chacha20+poly1305 that | ||
163 | * needs no IV. XXX make iv_len == -1 default? | ||
164 | */ | ||
165 | return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ? | ||
166 | c->iv_len : c->block_size; | ||
146 | } | 167 | } |
147 | 168 | ||
148 | u_int | 169 | u_int |
@@ -154,7 +175,7 @@ cipher_get_number(const Cipher *c) | |||
154 | u_int | 175 | u_int |
155 | cipher_is_cbc(const Cipher *c) | 176 | cipher_is_cbc(const Cipher *c) |
156 | { | 177 | { |
157 | return (c->cbc_mode); | 178 | return (c->flags & CFLAG_CBC) != 0; |
158 | } | 179 | } |
159 | 180 | ||
160 | u_int | 181 | u_int |
@@ -274,8 +295,11 @@ cipher_init(CipherContext *cc, const Cipher *cipher, | |||
274 | ivlen, cipher->name); | 295 | ivlen, cipher->name); |
275 | cc->cipher = cipher; | 296 | cc->cipher = cipher; |
276 | 297 | ||
298 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { | ||
299 | chachapoly_init(&cc->cp_ctx, key, keylen); | ||
300 | return; | ||
301 | } | ||
277 | type = (*cipher->evptype)(); | 302 | type = (*cipher->evptype)(); |
278 | |||
279 | EVP_CIPHER_CTX_init(&cc->evp); | 303 | EVP_CIPHER_CTX_init(&cc->evp); |
280 | #ifdef SSH_OLD_EVP | 304 | #ifdef SSH_OLD_EVP |
281 | if (type->key_len > 0 && type->key_len != keylen) { | 305 | if (type->key_len > 0 && type->key_len != keylen) { |
@@ -328,11 +352,16 @@ cipher_init(CipherContext *cc, const Cipher *cipher, | |||
328 | * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. | 352 | * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. |
329 | * This tag is written on encryption and verified on decryption. | 353 | * This tag is written on encryption and verified on decryption. |
330 | * Both 'aadlen' and 'authlen' can be set to 0. | 354 | * Both 'aadlen' and 'authlen' can be set to 0. |
355 | * cipher_crypt() returns 0 on success and -1 if the decryption integrity | ||
356 | * check fails. | ||
331 | */ | 357 | */ |
332 | void | 358 | int |
333 | cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, | 359 | cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, |
334 | u_int len, u_int aadlen, u_int authlen) | 360 | u_int len, u_int aadlen, u_int authlen) |
335 | { | 361 | { |
362 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | ||
363 | return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, | ||
364 | aadlen, authlen, cc->encrypt); | ||
336 | if (authlen) { | 365 | if (authlen) { |
337 | u_char lastiv[1]; | 366 | u_char lastiv[1]; |
338 | 367 | ||
@@ -365,19 +394,36 @@ cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, | |||
365 | if (cc->encrypt) | 394 | if (cc->encrypt) |
366 | fatal("%s: EVP_Cipher(final) failed", __func__); | 395 | fatal("%s: EVP_Cipher(final) failed", __func__); |
367 | else | 396 | else |
368 | fatal("Decryption integrity check failed"); | 397 | return -1; |
369 | } | 398 | } |
370 | if (cc->encrypt && | 399 | if (cc->encrypt && |
371 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, | 400 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, |
372 | authlen, dest + aadlen + len)) | 401 | authlen, dest + aadlen + len)) |
373 | fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); | 402 | fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); |
374 | } | 403 | } |
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* Extract the packet length, including any decryption necessary beforehand */ | ||
408 | int | ||
409 | cipher_get_length(CipherContext *cc, u_int *plenp, u_int seqnr, | ||
410 | const u_char *cp, u_int len) | ||
411 | { | ||
412 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | ||
413 | return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr, | ||
414 | cp, len); | ||
415 | if (len < 4) | ||
416 | return -1; | ||
417 | *plenp = get_u32(cp); | ||
418 | return 0; | ||
375 | } | 419 | } |
376 | 420 | ||
377 | void | 421 | void |
378 | cipher_cleanup(CipherContext *cc) | 422 | cipher_cleanup(CipherContext *cc) |
379 | { | 423 | { |
380 | if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) | 424 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
425 | memset(&cc->cp_ctx, 0, sizeof(cc->cp_ctx)); | ||
426 | else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) | ||
381 | error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); | 427 | error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); |
382 | } | 428 | } |
383 | 429 | ||
@@ -417,6 +463,8 @@ cipher_get_keyiv_len(const CipherContext *cc) | |||
417 | 463 | ||
418 | if (c->number == SSH_CIPHER_3DES) | 464 | if (c->number == SSH_CIPHER_3DES) |
419 | ivlen = 24; | 465 | ivlen = 24; |
466 | else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | ||
467 | ivlen = 0; | ||
420 | else | 468 | else |
421 | ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); | 469 | ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); |
422 | return (ivlen); | 470 | return (ivlen); |
@@ -428,6 +476,12 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) | |||
428 | const Cipher *c = cc->cipher; | 476 | const Cipher *c = cc->cipher; |
429 | int evplen; | 477 | int evplen; |
430 | 478 | ||
479 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { | ||
480 | if (len != 0) | ||
481 | fatal("%s: wrong iv length %d != %d", __func__, len, 0); | ||
482 | return; | ||
483 | } | ||
484 | |||
431 | switch (c->number) { | 485 | switch (c->number) { |
432 | case SSH_CIPHER_SSH2: | 486 | case SSH_CIPHER_SSH2: |
433 | case SSH_CIPHER_DES: | 487 | case SSH_CIPHER_DES: |
@@ -464,6 +518,9 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv) | |||
464 | const Cipher *c = cc->cipher; | 518 | const Cipher *c = cc->cipher; |
465 | int evplen = 0; | 519 | int evplen = 0; |
466 | 520 | ||
521 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) | ||
522 | return; | ||
523 | |||
467 | switch (c->number) { | 524 | switch (c->number) { |
468 | case SSH_CIPHER_SSH2: | 525 | case SSH_CIPHER_SSH2: |
469 | case SSH_CIPHER_DES: | 526 | case SSH_CIPHER_DES: |