1*9469f4f1Schristos /* $NetBSD: cipher.c,v 1.23 2024/09/24 21:32:18 christos Exp $ */ 2*9469f4f1Schristos /* $OpenBSD: cipher.c,v 1.123 2024/08/23 04:51:00 deraadt Exp $ */ 317418e98Schristos 4ca32bd8dSchristos /* 5ca32bd8dSchristos * Author: Tatu Ylonen <ylo@cs.hut.fi> 6ca32bd8dSchristos * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7ca32bd8dSchristos * All rights reserved 8ca32bd8dSchristos * 9ca32bd8dSchristos * As far as I am concerned, the code I have written for this software 10ca32bd8dSchristos * can be used freely for any purpose. Any derived versions of this 11ca32bd8dSchristos * software must be clearly marked as such, and if the derived work is 12ca32bd8dSchristos * incompatible with the protocol description in the RFC file, it must be 13ca32bd8dSchristos * called by a name other than "ssh" or "Secure Shell". 14ca32bd8dSchristos * 15ca32bd8dSchristos * 16ca32bd8dSchristos * Copyright (c) 1999 Niels Provos. All rights reserved. 17ca32bd8dSchristos * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. 18ca32bd8dSchristos * 19ca32bd8dSchristos * Redistribution and use in source and binary forms, with or without 20ca32bd8dSchristos * modification, are permitted provided that the following conditions 21ca32bd8dSchristos * are met: 22ca32bd8dSchristos * 1. Redistributions of source code must retain the above copyright 23ca32bd8dSchristos * notice, this list of conditions and the following disclaimer. 24ca32bd8dSchristos * 2. Redistributions in binary form must reproduce the above copyright 25ca32bd8dSchristos * notice, this list of conditions and the following disclaimer in the 26ca32bd8dSchristos * documentation and/or other materials provided with the distribution. 27ca32bd8dSchristos * 28ca32bd8dSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 29ca32bd8dSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 30ca32bd8dSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 31ca32bd8dSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 32ca32bd8dSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 33ca32bd8dSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34ca32bd8dSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35ca32bd8dSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36ca32bd8dSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 37ca32bd8dSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38ca32bd8dSchristos */ 39ca32bd8dSchristos 40313c6c94Schristos #include "includes.h" 41*9469f4f1Schristos __RCSID("$NetBSD: cipher.c,v 1.23 2024/09/24 21:32:18 christos Exp $"); 42ca32bd8dSchristos #include <sys/types.h> 43ca32bd8dSchristos 44ca32bd8dSchristos #include <string.h> 45ca32bd8dSchristos #include <stdarg.h> 468a4530f9Schristos #include <stdio.h> 47ca32bd8dSchristos 48ca32bd8dSchristos #include "cipher.h" 498a4530f9Schristos #include "misc.h" 508a4530f9Schristos #include "sshbuf.h" 518a4530f9Schristos #include "ssherr.h" 528a4530f9Schristos #include "digest.h" 53ca32bd8dSchristos 54cd4ada6aSchristos #ifndef WITH_OPENSSL 55cd4ada6aSchristos #define EVP_CIPHER_CTX void 56cd4ada6aSchristos #endif 57ca32bd8dSchristos 58e8c0841bSchristos // XXX: from libressl 59e8c0841bSchristos #define HAVE_EVP_CIPHER_CTX_IV 60e8c0841bSchristos 61e8c0841bSchristos static int 62e8c0841bSchristos EVP_CIPHER_CTX_get_iv(const EVP_CIPHER_CTX *ctx, unsigned char *iv, size_t len) 63e8c0841bSchristos { 64e8c0841bSchristos if (ctx == NULL) 65e8c0841bSchristos return 0; 66e8c0841bSchristos if (EVP_CIPHER_CTX_iv_length(ctx) < 0) 67e8c0841bSchristos return 0; 68e8c0841bSchristos if (len != (size_t)EVP_CIPHER_CTX_iv_length(ctx)) 69e8c0841bSchristos return 0; 70e8c0841bSchristos if (len > EVP_MAX_IV_LENGTH) 71e8c0841bSchristos return 0; /* sanity check; shouldn't happen */ 72e8c0841bSchristos /* 73e8c0841bSchristos * Skip the memcpy entirely when the requested IV length is zero, 74e8c0841bSchristos * since the iv pointer may be NULL or invalid. 75e8c0841bSchristos */ 76e8c0841bSchristos if (len != 0) { 77e8c0841bSchristos if (iv == NULL) 78e8c0841bSchristos return 0; 79e8c0841bSchristos # ifdef HAVE_EVP_CIPHER_CTX_IV 80e8c0841bSchristos memcpy(iv, EVP_CIPHER_CTX_iv(ctx), len); 81e8c0841bSchristos # else 82e8c0841bSchristos memcpy(iv, ctx->iv, len); 83e8c0841bSchristos # endif /* HAVE_EVP_CIPHER_CTX_IV */ 84e8c0841bSchristos } 85e8c0841bSchristos return 1; 86e8c0841bSchristos } 87e8c0841bSchristos // XXX: end 88e8c0841bSchristos 89ee85abc4Schristos struct sshcipher_ctx { 90ee85abc4Schristos int plaintext; 91ee85abc4Schristos int encrypt; 92ee85abc4Schristos EVP_CIPHER_CTX *evp; 938db691beSchristos struct chachapoly_ctx *cp_ctx; 94ee85abc4Schristos struct aesctr_ctx ac_ctx; /* XXX union with evp? */ 95ee85abc4Schristos const struct sshcipher *cipher; 96ee85abc4Schristos }; 97ee85abc4Schristos 988a4530f9Schristos struct sshcipher { 99185c8f97Schristos const char *name; 100ca32bd8dSchristos u_int block_size; 101ca32bd8dSchristos u_int key_len; 102ce11a51fSchristos u_int iv_len; /* defaults to block_size */ 103ce11a51fSchristos u_int auth_len; 1048a4530f9Schristos u_int flags; 1058a4530f9Schristos #define CFLAG_CBC (1<<0) 1068a4530f9Schristos #define CFLAG_CHACHAPOLY (1<<1) 1078a4530f9Schristos #define CFLAG_AESCTR (1<<2) 1088a4530f9Schristos #define CFLAG_NONE (1<<3) 1097a183406Schristos #define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ 1108a4530f9Schristos #ifdef WITH_OPENSSL 111ca32bd8dSchristos const EVP_CIPHER *(*evptype)(void); 1128a4530f9Schristos #else 1138a4530f9Schristos void *ignored; 1148a4530f9Schristos #endif 11500a838c4Schristos }; 11600a838c4Schristos 1178a4530f9Schristos static const struct sshcipher ciphers[] = { 1188a4530f9Schristos #ifdef WITH_OPENSSL 1197a183406Schristos { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, 1207a183406Schristos { "aes128-cbc", 16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc }, 1217a183406Schristos { "aes192-cbc", 16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc }, 1227a183406Schristos { "aes256-cbc", 16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc }, 1237a183406Schristos { "aes128-ctr", 16, 16, 0, 0, 0, EVP_aes_128_ctr }, 1247a183406Schristos { "aes192-ctr", 16, 24, 0, 0, 0, EVP_aes_192_ctr }, 1257a183406Schristos { "aes256-ctr", 16, 32, 0, 0, 0, EVP_aes_256_ctr }, 126ce11a51fSchristos { "aes128-gcm@openssh.com", 1277a183406Schristos 16, 16, 12, 16, 0, EVP_aes_128_gcm }, 128ce11a51fSchristos { "aes256-gcm@openssh.com", 1297a183406Schristos 16, 32, 12, 16, 0, EVP_aes_256_gcm }, 1308a4530f9Schristos #else 1317a183406Schristos { "aes128-ctr", 16, 16, 0, 0, CFLAG_AESCTR, NULL }, 1327a183406Schristos { "aes192-ctr", 16, 24, 0, 0, CFLAG_AESCTR, NULL }, 1337a183406Schristos { "aes256-ctr", 16, 32, 0, 0, CFLAG_AESCTR, NULL }, 1348a4530f9Schristos #endif 1358a4530f9Schristos { "chacha20-poly1305@openssh.com", 1367a183406Schristos 8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL }, 1377a183406Schristos { "none", 8, 0, 0, 0, CFLAG_NONE, NULL }, 1388a4530f9Schristos 1397a183406Schristos { NULL, 0, 0, 0, 0, 0, NULL } 140ca32bd8dSchristos }; 141ca32bd8dSchristos 142ca32bd8dSchristos /*--*/ 143ca32bd8dSchristos 14400a838c4Schristos /* Returns a comma-separated list of supported ciphers. */ 14500a838c4Schristos char * 1468a4530f9Schristos cipher_alg_list(char sep, int auth_only) 14700a838c4Schristos { 1488a4530f9Schristos char *tmp, *ret = NULL; 14900a838c4Schristos size_t nlen, rlen = 0; 1508a4530f9Schristos const struct sshcipher *c; 15100a838c4Schristos 15200a838c4Schristos for (c = ciphers; c->name != NULL; c++) { 1537a183406Schristos if ((c->flags & CFLAG_INTERNAL) != 0) 15400a838c4Schristos continue; 1558a4530f9Schristos if (auth_only && c->auth_len == 0) 1568a4530f9Schristos continue; 15700a838c4Schristos if (ret != NULL) 1588a4530f9Schristos ret[rlen++] = sep; 15900a838c4Schristos nlen = strlen(c->name); 1608a4530f9Schristos if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 1618a4530f9Schristos free(ret); 1628a4530f9Schristos return NULL; 1638a4530f9Schristos } 1648a4530f9Schristos ret = tmp; 16500a838c4Schristos memcpy(ret + rlen, c->name, nlen + 1); 16600a838c4Schristos rlen += nlen; 16700a838c4Schristos } 16800a838c4Schristos return ret; 16900a838c4Schristos } 17000a838c4Schristos 171ed75d7a8Schristos const char * 172ed75d7a8Schristos compression_alg_list(int compression) 173ed75d7a8Schristos { 174ed75d7a8Schristos #ifdef WITH_ZLIB 175*9469f4f1Schristos return compression ? "zlib@openssh.com,none" : 176*9469f4f1Schristos "none,zlib@openssh.com"; 177ed75d7a8Schristos #else 178ed75d7a8Schristos return "none"; 179ed75d7a8Schristos #endif 180ed75d7a8Schristos } 181ed75d7a8Schristos 182ca32bd8dSchristos u_int 1838a4530f9Schristos cipher_blocksize(const struct sshcipher *c) 184ca32bd8dSchristos { 185ca32bd8dSchristos return (c->block_size); 186ca32bd8dSchristos } 187ca32bd8dSchristos 188ca32bd8dSchristos u_int 1898a4530f9Schristos cipher_keylen(const struct sshcipher *c) 190ca32bd8dSchristos { 191ca32bd8dSchristos return (c->key_len); 192ca32bd8dSchristos } 193ca32bd8dSchristos 194ca32bd8dSchristos u_int 1958a4530f9Schristos cipher_seclen(const struct sshcipher *c) 1968a4530f9Schristos { 1978a4530f9Schristos if (strcmp("3des-cbc", c->name) == 0) 1988a4530f9Schristos return 14; 1998a4530f9Schristos return cipher_keylen(c); 2008a4530f9Schristos } 2018a4530f9Schristos 2028a4530f9Schristos u_int 2038a4530f9Schristos cipher_authlen(const struct sshcipher *c) 204ce11a51fSchristos { 205ce11a51fSchristos return (c->auth_len); 206ce11a51fSchristos } 207ce11a51fSchristos 208ce11a51fSchristos u_int 2098a4530f9Schristos cipher_ivlen(const struct sshcipher *c) 210ce11a51fSchristos { 2118a4530f9Schristos /* 2128a4530f9Schristos * Default is cipher block size, except for chacha20+poly1305 that 2138a4530f9Schristos * needs no IV. XXX make iv_len == -1 default? 2148a4530f9Schristos */ 2158a4530f9Schristos return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ? 2168a4530f9Schristos c->iv_len : c->block_size; 217ce11a51fSchristos } 218ce11a51fSchristos 219ce11a51fSchristos u_int 2208a4530f9Schristos cipher_is_cbc(const struct sshcipher *c) 221ca32bd8dSchristos { 2228a4530f9Schristos return (c->flags & CFLAG_CBC) != 0; 223ca32bd8dSchristos } 224ca32bd8dSchristos 225ca32bd8dSchristos u_int 226ee85abc4Schristos cipher_ctx_is_plaintext(struct sshcipher_ctx *cc) 227ee85abc4Schristos { 228ee85abc4Schristos return cc->plaintext; 229ee85abc4Schristos } 230ee85abc4Schristos 2318a4530f9Schristos const struct sshcipher * 232ca32bd8dSchristos cipher_by_name(const char *name) 233ca32bd8dSchristos { 2348a4530f9Schristos const struct sshcipher *c; 235ca32bd8dSchristos for (c = ciphers; c->name != NULL; c++) 236ca32bd8dSchristos if (strcmp(c->name, name) == 0) 237ca32bd8dSchristos return c; 238ca32bd8dSchristos return NULL; 239ca32bd8dSchristos } 240ca32bd8dSchristos 241ca32bd8dSchristos #define CIPHER_SEP "," 242ca32bd8dSchristos int 243ca32bd8dSchristos ciphers_valid(const char *names) 244ca32bd8dSchristos { 2458a4530f9Schristos const struct sshcipher *c; 246ca32bd8dSchristos char *cipher_list, *cp; 247ca32bd8dSchristos char *p; 248ca32bd8dSchristos 249ca32bd8dSchristos if (names == NULL || strcmp(names, "") == 0) 250ca32bd8dSchristos return 0; 2518a4530f9Schristos if ((cipher_list = cp = strdup(names)) == NULL) 2528a4530f9Schristos return 0; 253ca32bd8dSchristos for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; 254ca32bd8dSchristos (p = strsep(&cp, CIPHER_SEP))) { 255ca32bd8dSchristos c = cipher_by_name(p); 2567a183406Schristos if (c == NULL || (c->flags & (CFLAG_INTERNAL|CFLAG_NONE)) != 0) { 25700a838c4Schristos free(cipher_list); 258ca32bd8dSchristos return 0; 259ca32bd8dSchristos } 260ca32bd8dSchristos } 26100a838c4Schristos free(cipher_list); 262ca32bd8dSchristos return 1; 263ca32bd8dSchristos } 264ca32bd8dSchristos 2658a4530f9Schristos const char * 2668a4530f9Schristos cipher_warning_message(const struct sshcipher_ctx *cc) 2678a4530f9Schristos { 2688a4530f9Schristos if (cc == NULL || cc->cipher == NULL) 2698a4530f9Schristos return NULL; 2707a183406Schristos /* XXX repurpose for CBC warning */ 2718a4530f9Schristos return NULL; 2728a4530f9Schristos } 2738a4530f9Schristos 2748a4530f9Schristos int 275ee85abc4Schristos cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, 276ca32bd8dSchristos const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, 277ca32bd8dSchristos int do_encrypt) 278ca32bd8dSchristos { 279ee85abc4Schristos struct sshcipher_ctx *cc = NULL; 2808a4530f9Schristos int ret = SSH_ERR_INTERNAL_ERROR; 281ee85abc4Schristos #ifdef WITH_OPENSSL 282ca32bd8dSchristos const EVP_CIPHER *type; 283ca32bd8dSchristos int klen; 284ee85abc4Schristos #endif 285ee85abc4Schristos 286ee85abc4Schristos *ccp = NULL; 287*9469f4f1Schristos if ((cc = calloc(1, sizeof(*cc))) == NULL) 288ee85abc4Schristos return SSH_ERR_ALLOC_FAIL; 289ca32bd8dSchristos 2907a183406Schristos cc->plaintext = (cipher->flags & CFLAG_NONE) != 0; 291ce11a51fSchristos cc->encrypt = do_encrypt; 292ca32bd8dSchristos 2938a4530f9Schristos if (keylen < cipher->key_len || 294ee85abc4Schristos (iv != NULL && ivlen < cipher_ivlen(cipher))) { 295ee85abc4Schristos ret = SSH_ERR_INVALID_ARGUMENT; 296ee85abc4Schristos goto out; 297ee85abc4Schristos } 2988a4530f9Schristos 299ca32bd8dSchristos cc->cipher = cipher; 3008a4530f9Schristos if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { 3018db691beSchristos cc->cp_ctx = chachapoly_new(key, keylen); 3028db691beSchristos ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT; 303ee85abc4Schristos goto out; 3048a4530f9Schristos } 3057a183406Schristos if ((cc->cipher->flags & CFLAG_NONE) != 0) { 3067a183406Schristos ret = 0; 3077a183406Schristos goto out; 3087a183406Schristos } 3098a4530f9Schristos #ifndef WITH_OPENSSL 3108a4530f9Schristos if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { 3118a4530f9Schristos aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen); 3128a4530f9Schristos aesctr_ivsetup(&cc->ac_ctx, iv); 313ee85abc4Schristos ret = 0; 314ee85abc4Schristos goto out; 3158a4530f9Schristos } 316ee85abc4Schristos ret = SSH_ERR_INVALID_ARGUMENT; 317ee85abc4Schristos goto out; 318ee85abc4Schristos #else /* WITH_OPENSSL */ 319ca32bd8dSchristos type = (*cipher->evptype)(); 320ee85abc4Schristos if ((cc->evp = EVP_CIPHER_CTX_new()) == NULL) { 321ee85abc4Schristos ret = SSH_ERR_ALLOC_FAIL; 322ee85abc4Schristos goto out; 323ee85abc4Schristos } 324ee85abc4Schristos if (EVP_CipherInit(cc->evp, type, NULL, (const u_char *)iv, 3258a4530f9Schristos (do_encrypt == CIPHER_ENCRYPT)) == 0) { 3268a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 327ee85abc4Schristos goto out; 3288a4530f9Schristos } 329ce11a51fSchristos if (cipher_authlen(cipher) && 330ee85abc4Schristos !EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_IV_FIXED, 3318a4530f9Schristos -1, __UNCONST(iv))) { 3328a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 333ee85abc4Schristos goto out; 3348a4530f9Schristos } 335ee85abc4Schristos klen = EVP_CIPHER_CTX_key_length(cc->evp); 336ca32bd8dSchristos if (klen > 0 && keylen != (u_int)klen) { 337ee85abc4Schristos if (EVP_CIPHER_CTX_set_key_length(cc->evp, keylen) == 0) { 3388a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 339ee85abc4Schristos goto out; 340ca32bd8dSchristos } 3418a4530f9Schristos } 342b400d007Schristos /* in OpenSSL 1.1.0, EVP_CipherInit clears all previous setups; 343b400d007Schristos use EVP_CipherInit_ex for augmenting */ 344b400d007Schristos if (EVP_CipherInit_ex(cc->evp, NULL, NULL, __UNCONST(key), NULL, -1) == 0) { 3458a4530f9Schristos ret = SSH_ERR_LIBCRYPTO_ERROR; 346ee85abc4Schristos goto out; 3478a4530f9Schristos } 348ee85abc4Schristos ret = 0; 349ee85abc4Schristos #endif /* WITH_OPENSSL */ 350ee85abc4Schristos out: 351ee85abc4Schristos if (ret == 0) { 352ee85abc4Schristos /* success */ 353ee85abc4Schristos *ccp = cc; 354ee85abc4Schristos } else { 355ee85abc4Schristos if (cc != NULL) { 356ee85abc4Schristos #ifdef WITH_OPENSSL 357ee85abc4Schristos EVP_CIPHER_CTX_free(cc->evp); 358ee85abc4Schristos #endif /* WITH_OPENSSL */ 3598db691beSchristos freezero(cc, sizeof(*cc)); 360ee85abc4Schristos } 361ee85abc4Schristos } 3628a4530f9Schristos return ret; 363ca32bd8dSchristos } 364ca32bd8dSchristos 365ce11a51fSchristos /* 366ce11a51fSchristos * cipher_crypt() operates as following: 367ce11a51fSchristos * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. 3688db691beSchristos * These bytes are treated as additional authenticated data for 369ce11a51fSchristos * authenticated encryption modes. 370ce11a51fSchristos * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. 371ce11a51fSchristos * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. 372ce11a51fSchristos * This tag is written on encryption and verified on decryption. 373ce11a51fSchristos * Both 'aadlen' and 'authlen' can be set to 0. 374ce11a51fSchristos */ 3758a4530f9Schristos int 3768a4530f9Schristos cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest, 3778a4530f9Schristos const u_char *src, u_int len, u_int aadlen, u_int authlen) 378ca32bd8dSchristos { 3798a4530f9Schristos if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { 3808db691beSchristos return chachapoly_crypt(cc->cp_ctx, seqnr, dest, src, 3818a4530f9Schristos len, aadlen, authlen, cc->encrypt); 3828a4530f9Schristos } 3837a183406Schristos if ((cc->cipher->flags & CFLAG_NONE) != 0) { 3847a183406Schristos memcpy(dest, src, aadlen + len); 3857a183406Schristos return 0; 3867a183406Schristos } 3878a4530f9Schristos #ifndef WITH_OPENSSL 3888a4530f9Schristos if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { 3898a4530f9Schristos if (aadlen) 3908a4530f9Schristos memcpy(dest, src, aadlen); 3918a4530f9Schristos aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen, 3928a4530f9Schristos dest + aadlen, len); 3938a4530f9Schristos return 0; 3948a4530f9Schristos } 3958a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 3968a4530f9Schristos #else 397ce11a51fSchristos if (authlen) { 398ce11a51fSchristos u_char lastiv[1]; 399ce11a51fSchristos 400ce11a51fSchristos if (authlen != cipher_authlen(cc->cipher)) 4018a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 402ce11a51fSchristos /* increment IV */ 403ee85abc4Schristos if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, 404ce11a51fSchristos 1, lastiv)) 4058a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 4061c7715ddSchristos /* set tag on decryption */ 407ce11a51fSchristos if (!cc->encrypt && 408ee85abc4Schristos !EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_SET_TAG, 409ce11a51fSchristos authlen, __UNCONST(src + aadlen + len))) 4108a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 411ce11a51fSchristos } 412ce11a51fSchristos if (aadlen) { 413ce11a51fSchristos if (authlen && 414ee85abc4Schristos EVP_Cipher(cc->evp, NULL, (const u_char *)src, aadlen) < 0) 4158a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 416ce11a51fSchristos memcpy(dest, src, aadlen); 417ce11a51fSchristos } 418ca32bd8dSchristos if (len % cc->cipher->block_size) 4198a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 420ee85abc4Schristos if (EVP_Cipher(cc->evp, dest + aadlen, (const u_char *)src + aadlen, 421ce11a51fSchristos len) < 0) 4228a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 423ce11a51fSchristos if (authlen) { 424ce11a51fSchristos /* compute tag (on encrypt) or verify tag (on decrypt) */ 425ee85abc4Schristos if (EVP_Cipher(cc->evp, NULL, NULL, 0) < 0) 4268a4530f9Schristos return cc->encrypt ? 4278a4530f9Schristos SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID; 428ce11a51fSchristos if (cc->encrypt && 429ee85abc4Schristos !EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_GET_TAG, 430ce11a51fSchristos authlen, dest + aadlen + len)) 4318a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 432ce11a51fSchristos } 4338a4530f9Schristos return 0; 4348a4530f9Schristos #endif 435ca32bd8dSchristos } 436ca32bd8dSchristos 4378a4530f9Schristos /* Extract the packet length, including any decryption necessary beforehand */ 4388a4530f9Schristos int 4398a4530f9Schristos cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, 4408a4530f9Schristos const u_char *cp, u_int len) 441ca32bd8dSchristos { 4428a4530f9Schristos if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 4438db691beSchristos return chachapoly_get_length(cc->cp_ctx, plenp, seqnr, 4448a4530f9Schristos cp, len); 4458a4530f9Schristos if (len < 4) 4468a4530f9Schristos return SSH_ERR_MESSAGE_INCOMPLETE; 447ffae97bbSchristos *plenp = PEEK_U32(cp); 4488a4530f9Schristos return 0; 4498a4530f9Schristos } 4508a4530f9Schristos 451ee85abc4Schristos void 452ee85abc4Schristos cipher_free(struct sshcipher_ctx *cc) 4538a4530f9Schristos { 454ee85abc4Schristos if (cc == NULL) 455ee85abc4Schristos return; 4568db691beSchristos if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { 4578db691beSchristos chachapoly_free(cc->cp_ctx); 4588db691beSchristos cc->cp_ctx = NULL; 4598db691beSchristos } else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) 4608a4530f9Schristos explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx)); 4618a4530f9Schristos #ifdef WITH_OPENSSL 462ee85abc4Schristos EVP_CIPHER_CTX_free(cc->evp); 463ee85abc4Schristos cc->evp = NULL; 4648a4530f9Schristos #endif 4658db691beSchristos freezero(cc, sizeof(*cc)); 466ca32bd8dSchristos } 467ca32bd8dSchristos 4688a4530f9Schristos int 469aa36fcacSchristos cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, size_t len) 470ca32bd8dSchristos { 4718a4530f9Schristos #ifdef WITH_OPENSSL 472ffae97bbSchristos const struct sshcipher *c = cc->cipher; 473ca32bd8dSchristos int evplen; 4748a4530f9Schristos #endif 4758a4530f9Schristos 4768a4530f9Schristos if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { 4778a4530f9Schristos if (len != 0) 4788a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 4798a4530f9Schristos return 0; 4808a4530f9Schristos } 481e4d43b82Schristos if ((cc->cipher->flags & CFLAG_AESCTR) != 0) { 482e4d43b82Schristos if (len != sizeof(cc->ac_ctx.ctr)) 483e4d43b82Schristos return SSH_ERR_INVALID_ARGUMENT; 484e4d43b82Schristos memcpy(iv, cc->ac_ctx.ctr, len); 485e4d43b82Schristos return 0; 486e4d43b82Schristos } 4878a4530f9Schristos if ((cc->cipher->flags & CFLAG_NONE) != 0) 4888a4530f9Schristos return 0; 489ca32bd8dSchristos 4908a4530f9Schristos #ifdef WITH_OPENSSL 491ee85abc4Schristos evplen = EVP_CIPHER_CTX_iv_length(cc->evp); 492ca32bd8dSchristos if (evplen == 0) 4938a4530f9Schristos return 0; 4948a4530f9Schristos else if (evplen < 0) 4958a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 496aa36fcacSchristos if ((size_t)evplen != len) 4978a4530f9Schristos return SSH_ERR_INVALID_ARGUMENT; 498ce11a51fSchristos if (cipher_authlen(c)) { 499e8c0841bSchristos if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN, len, iv)) 5008a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 501e8c0841bSchristos } else if (!EVP_CIPHER_CTX_get_iv(cc->evp, iv, len)) 502e8c0841bSchristos return SSH_ERR_LIBCRYPTO_ERROR; 5038a4530f9Schristos #endif 5048a4530f9Schristos return 0; 5058a4530f9Schristos } 5068a4530f9Schristos 5078a4530f9Schristos int 508aa36fcacSchristos cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv, size_t len) 5098a4530f9Schristos { 5108a4530f9Schristos #ifdef WITH_OPENSSL 511ffae97bbSchristos const struct sshcipher *c = cc->cipher; 5128a4530f9Schristos int evplen = 0; 5138a4530f9Schristos #endif 5148a4530f9Schristos 5158a4530f9Schristos if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) 5168a4530f9Schristos return 0; 5178a4530f9Schristos if ((cc->cipher->flags & CFLAG_NONE) != 0) 5188a4530f9Schristos return 0; 5198a4530f9Schristos 5208a4530f9Schristos #ifdef WITH_OPENSSL 521ee85abc4Schristos evplen = EVP_CIPHER_CTX_iv_length(cc->evp); 5228a4530f9Schristos if (evplen <= 0) 5238a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 524aa36fcacSchristos if ((size_t)evplen != len) 525aa36fcacSchristos return SSH_ERR_INVALID_ARGUMENT; 5268a4530f9Schristos if (cipher_authlen(c)) { 5278a4530f9Schristos /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */ 528ee85abc4Schristos if (!EVP_CIPHER_CTX_ctrl(cc->evp, 5298a4530f9Schristos EVP_CTRL_GCM_SET_IV_FIXED, -1, __UNCONST(iv))) 5308a4530f9Schristos return SSH_ERR_LIBCRYPTO_ERROR; 531ce11a51fSchristos } else 532b400d007Schristos memcpy(EVP_CIPHER_CTX_iv_noconst(cc->evp), iv, evplen); 5338a4530f9Schristos #endif 5348a4530f9Schristos return 0; 535ca32bd8dSchristos } 536ca32bd8dSchristos 537