blob: 48ef105ca9c6efb0ea99e1aa196b998613c68f43 [file] [log] [blame]
Damien Miller86687062014-07-02 15:28:02 +10001/* $OpenBSD: cipher.c,v 1.99 2014/06/24 01:13:21 djm Exp $ */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002/*
Damien Miller95def091999-11-25 00:26:21 +11003 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller95def091999-11-25 00:26:21 +11004 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
Damien Miller4af51302000-04-16 11:18:38 +10006 *
Damien Millere4340be2000-09-16 13:29:08 +11007 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose. Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
Damien Miller4af51302000-04-16 11:18:38 +100012 *
Damien Millere4340be2000-09-16 13:29:08 +110013 *
14 * Copyright (c) 1999 Niels Provos. All rights reserved.
Ben Lindstrom44697232001-07-04 03:32:30 +000015 * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +110016 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Damien Miller95def091999-11-25 00:26:21 +110036 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100037
38#include "includes.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100039
Damien Millerd7834352006-08-05 12:39:39 +100040#include <sys/types.h>
41
Damien Millere3476ed2006-07-24 14:13:33 +100042#include <string.h>
Damien Millerd7834352006-08-05 12:39:39 +100043#include <stdarg.h>
Damien Miller0fde8ac2013-11-21 14:12:23 +110044#include <stdio.h>
Damien Millere3476ed2006-07-24 14:13:33 +100045
Ben Lindstrom226cfa02001-01-22 05:34:40 +000046#include "cipher.h"
Damien Miller86687062014-07-02 15:28:02 +100047#include "misc.h"
48#include "sshbuf.h"
49#include "ssherr.h"
Damien Miller4a1c7aa2014-02-04 11:03:36 +110050#include "digest.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100051
Damien Miller1f0311c2014-05-15 14:24:09 +100052#ifdef WITH_SSH1
Damien Miller3a3261f2003-05-15 13:37:19 +100053extern const EVP_CIPHER *evp_ssh1_bf(void);
54extern const EVP_CIPHER *evp_ssh1_3des(void);
Damien Miller86687062014-07-02 15:28:02 +100055extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
Damien Miller1f0311c2014-05-15 14:24:09 +100056#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +100057
Damien Miller86687062014-07-02 15:28:02 +100058struct sshcipher {
Damien Miller963f6b22002-02-19 15:21:23 +110059 char *name;
60 int number; /* for ssh1 only */
61 u_int block_size;
62 u_int key_len;
Damien Millerd522c682013-01-09 16:42:47 +110063 u_int iv_len; /* defaults to block_size */
64 u_int auth_len;
Damien Miller3710f272005-05-26 12:19:17 +100065 u_int discard_len;
Damien Miller0fde8ac2013-11-21 14:12:23 +110066 u_int flags;
67#define CFLAG_CBC (1<<0)
68#define CFLAG_CHACHAPOLY (1<<1)
Damien Miller1f0311c2014-05-15 14:24:09 +100069#define CFLAG_AESCTR (1<<2)
70#define CFLAG_NONE (1<<3)
71#ifdef WITH_OPENSSL
Ben Lindstrom6a246412002-06-06 19:48:16 +000072 const EVP_CIPHER *(*evptype)(void);
Damien Miller1f0311c2014-05-15 14:24:09 +100073#else
74 void *ignored;
75#endif
Damien Millerea111192013-04-23 19:24:32 +100076};
77
Damien Miller86687062014-07-02 15:28:02 +100078static const struct sshcipher ciphers[] = {
Damien Miller1f0311c2014-05-15 14:24:09 +100079#ifdef WITH_SSH1
Damien Miller1d75abf2013-01-09 16:12:19 +110080 { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
81 { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
82 { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf },
Damien Miller86687062014-07-02 15:28:02 +100083#endif /* WITH_SSH1 */
Damien Miller1f0311c2014-05-15 14:24:09 +100084#ifdef WITH_OPENSSL
85 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
Damien Miller1d75abf2013-01-09 16:12:19 +110086 { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
87 { "blowfish-cbc",
88 SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc },
89 { "cast128-cbc",
90 SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_cast5_cbc },
91 { "arcfour", SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 0, EVP_rc4 },
92 { "arcfour128", SSH_CIPHER_SSH2, 8, 16, 0, 0, 1536, 0, EVP_rc4 },
93 { "arcfour256", SSH_CIPHER_SSH2, 8, 32, 0, 0, 1536, 0, EVP_rc4 },
94 { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc },
95 { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc },
96 { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
97 { "rijndael-cbc@lysator.liu.se",
98 SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
99 { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
100 { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
101 { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
Damien Miller86687062014-07-02 15:28:02 +1000102# ifdef OPENSSL_HAVE_EVPGCM
Damien Miller1d75abf2013-01-09 16:12:19 +1100103 { "aes128-gcm@openssh.com",
104 SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
105 { "aes256-gcm@openssh.com",
106 SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
Damien Miller86687062014-07-02 15:28:02 +1000107# endif /* OPENSSL_HAVE_EVPGCM */
Damien Miller1f0311c2014-05-15 14:24:09 +1000108#else /* WITH_OPENSSL */
109 { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL },
110 { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL },
111 { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL },
112 { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL },
113#endif /* WITH_OPENSSL */
Damien Miller0fde8ac2013-11-21 14:12:23 +1100114 { "chacha20-poly1305@openssh.com",
115 SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL },
Damien Miller86687062014-07-02 15:28:02 +1000116
Damien Miller1d75abf2013-01-09 16:12:19 +1100117 { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000118};
119
Damien Miller874d77b2000-10-14 16:23:11 +1100120/*--*/
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000121
Damien Miller86687062014-07-02 15:28:02 +1000122/* Returns a comma-separated list of supported ciphers. */
Damien Millerea111192013-04-23 19:24:32 +1000123char *
Damien Miller0fde8ac2013-11-21 14:12:23 +1100124cipher_alg_list(char sep, int auth_only)
Damien Millerea111192013-04-23 19:24:32 +1000125{
Damien Miller86687062014-07-02 15:28:02 +1000126 char *tmp, *ret = NULL;
Damien Millerea111192013-04-23 19:24:32 +1000127 size_t nlen, rlen = 0;
Damien Miller86687062014-07-02 15:28:02 +1000128 const struct sshcipher *c;
Damien Millerea111192013-04-23 19:24:32 +1000129
130 for (c = ciphers; c->name != NULL; c++) {
131 if (c->number != SSH_CIPHER_SSH2)
132 continue;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100133 if (auth_only && c->auth_len == 0)
134 continue;
Damien Millerea111192013-04-23 19:24:32 +1000135 if (ret != NULL)
Damien Miller690d9892013-11-08 12:16:49 +1100136 ret[rlen++] = sep;
Damien Millerea111192013-04-23 19:24:32 +1000137 nlen = strlen(c->name);
Damien Miller86687062014-07-02 15:28:02 +1000138 if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
139 free(ret);
140 return NULL;
141 }
142 ret = tmp;
Damien Millerea111192013-04-23 19:24:32 +1000143 memcpy(ret + rlen, c->name, nlen + 1);
144 rlen += nlen;
145 }
146 return ret;
147}
148
Ben Lindstrom6328ab32002-03-22 02:54:23 +0000149u_int
Damien Miller86687062014-07-02 15:28:02 +1000150cipher_blocksize(const struct sshcipher *c)
Damien Miller963f6b22002-02-19 15:21:23 +1100151{
152 return (c->block_size);
153}
Ben Lindstrom836f0e92002-06-23 21:21:30 +0000154
Ben Lindstrom6328ab32002-03-22 02:54:23 +0000155u_int
Damien Miller86687062014-07-02 15:28:02 +1000156cipher_keylen(const struct sshcipher *c)
Damien Miller963f6b22002-02-19 15:21:23 +1100157{
158 return (c->key_len);
159}
Ben Lindstrom836f0e92002-06-23 21:21:30 +0000160
Ben Lindstrom6328ab32002-03-22 02:54:23 +0000161u_int
Damien Miller86687062014-07-02 15:28:02 +1000162cipher_seclen(const struct sshcipher *c)
Damien Miller76eea4a2014-01-26 09:37:25 +1100163{
164 if (strcmp("3des-cbc", c->name) == 0)
165 return 14;
166 return cipher_keylen(c);
167}
168
169u_int
Damien Miller86687062014-07-02 15:28:02 +1000170cipher_authlen(const struct sshcipher *c)
Damien Miller1d75abf2013-01-09 16:12:19 +1100171{
172 return (c->auth_len);
173}
174
175u_int
Damien Miller86687062014-07-02 15:28:02 +1000176cipher_ivlen(const struct sshcipher *c)
Damien Miller1d75abf2013-01-09 16:12:19 +1100177{
Damien Miller0fde8ac2013-11-21 14:12:23 +1100178 /*
179 * Default is cipher block size, except for chacha20+poly1305 that
180 * needs no IV. XXX make iv_len == -1 default?
181 */
182 return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ?
183 c->iv_len : c->block_size;
Damien Miller1d75abf2013-01-09 16:12:19 +1100184}
185
186u_int
Damien Miller86687062014-07-02 15:28:02 +1000187cipher_get_number(const struct sshcipher *c)
Ben Lindstrom212faca2002-03-22 01:39:44 +0000188{
189 return (c->number);
190}
Damien Miller963f6b22002-02-19 15:21:23 +1100191
Ben Lindstrom46c16222000-12-22 01:43:59 +0000192u_int
Damien Miller86687062014-07-02 15:28:02 +1000193cipher_is_cbc(const struct sshcipher *c)
Damien Miller13ae44c2009-01-28 16:38:41 +1100194{
Damien Miller0fde8ac2013-11-21 14:12:23 +1100195 return (c->flags & CFLAG_CBC) != 0;
Damien Miller13ae44c2009-01-28 16:38:41 +1100196}
197
198u_int
Damien Miller874d77b2000-10-14 16:23:11 +1100199cipher_mask_ssh1(int client)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000200{
Ben Lindstrom46c16222000-12-22 01:43:59 +0000201 u_int mask = 0;
Damien Miller9f0f5c62001-12-21 14:45:46 +1100202 mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
Damien Miller95def091999-11-25 00:26:21 +1100203 mask |= 1 << SSH_CIPHER_BLOWFISH;
Damien Miller874d77b2000-10-14 16:23:11 +1100204 if (client) {
205 mask |= 1 << SSH_CIPHER_DES;
206 }
Damien Miller1383bd82000-04-06 12:32:37 +1000207 return mask;
208}
Damien Miller874d77b2000-10-14 16:23:11 +1100209
Damien Miller86687062014-07-02 15:28:02 +1000210const struct sshcipher *
Damien Miller874d77b2000-10-14 16:23:11 +1100211cipher_by_name(const char *name)
Damien Miller1383bd82000-04-06 12:32:37 +1000212{
Damien Miller86687062014-07-02 15:28:02 +1000213 const struct sshcipher *c;
Damien Miller874d77b2000-10-14 16:23:11 +1100214 for (c = ciphers; c->name != NULL; c++)
Darren Tucker660db782005-01-24 21:57:11 +1100215 if (strcmp(c->name, name) == 0)
Damien Miller874d77b2000-10-14 16:23:11 +1100216 return c;
217 return NULL;
Damien Miller1383bd82000-04-06 12:32:37 +1000218}
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000219
Damien Miller86687062014-07-02 15:28:02 +1000220const struct sshcipher *
Damien Miller874d77b2000-10-14 16:23:11 +1100221cipher_by_number(int id)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000222{
Damien Miller86687062014-07-02 15:28:02 +1000223 const struct sshcipher *c;
Damien Miller874d77b2000-10-14 16:23:11 +1100224 for (c = ciphers; c->name != NULL; c++)
225 if (c->number == id)
226 return c;
227 return NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000228}
229
Damien Miller78928792000-04-12 20:17:38 +1000230#define CIPHER_SEP ","
231int
232ciphers_valid(const char *names)
233{
Damien Miller86687062014-07-02 15:28:02 +1000234 const struct sshcipher *c;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000235 char *cipher_list, *cp;
Damien Miller78928792000-04-12 20:17:38 +1000236 char *p;
Damien Miller78928792000-04-12 20:17:38 +1000237
Damien Millerb1715dc2000-05-30 13:44:51 +1000238 if (names == NULL || strcmp(names, "") == 0)
Damien Miller78928792000-04-12 20:17:38 +1000239 return 0;
Damien Miller86687062014-07-02 15:28:02 +1000240 if ((cipher_list = cp = strdup(names)) == NULL)
241 return 0;
Damien Miller874d77b2000-10-14 16:23:11 +1100242 for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
Damien Miller9f0f5c62001-12-21 14:45:46 +1100243 (p = strsep(&cp, CIPHER_SEP))) {
Damien Miller874d77b2000-10-14 16:23:11 +1100244 c = cipher_by_name(p);
245 if (c == NULL || c->number != SSH_CIPHER_SSH2) {
Darren Tuckera627d422013-06-02 07:31:17 +1000246 free(cipher_list);
Damien Miller78928792000-04-12 20:17:38 +1000247 return 0;
248 }
249 }
Darren Tuckera627d422013-06-02 07:31:17 +1000250 free(cipher_list);
Damien Miller78928792000-04-12 20:17:38 +1000251 return 1;
252}
253
Damien Miller5428f641999-11-25 11:54:57 +1100254/*
255 * Parses the name of the cipher. Returns the number of the corresponding
256 * cipher, or -1 on error.
257 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000258
259int
260cipher_number(const char *name)
261{
Damien Miller86687062014-07-02 15:28:02 +1000262 const struct sshcipher *c;
Damien Millerb1715dc2000-05-30 13:44:51 +1000263 if (name == NULL)
264 return -1;
Darren Tucker660db782005-01-24 21:57:11 +1100265 for (c = ciphers; c->name != NULL; c++)
266 if (strcasecmp(c->name, name) == 0)
267 return c->number;
268 return -1;
Damien Miller874d77b2000-10-14 16:23:11 +1100269}
270
271char *
272cipher_name(int id)
273{
Damien Miller86687062014-07-02 15:28:02 +1000274 const struct sshcipher *c = cipher_by_number(id);
Damien Miller874d77b2000-10-14 16:23:11 +1100275 return (c==NULL) ? "<unknown>" : c->name;
276}
277
Damien Miller86687062014-07-02 15:28:02 +1000278const char *
279cipher_warning_message(const struct sshcipher_ctx *cc)
280{
281 if (cc == NULL || cc->cipher == NULL)
282 return NULL;
283 if (cc->cipher->number == SSH_CIPHER_DES)
284 return "use of DES is strongly discouraged due to "
285 "cryptographic weaknesses";
286 return NULL;
287}
288
289int
290cipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
Damien Miller21cf4e02002-02-19 15:26:42 +1100291 const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000292 int do_encrypt)
Damien Miller874d77b2000-10-14 16:23:11 +1100293{
Damien Miller1f0311c2014-05-15 14:24:09 +1000294#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000295 int ret = SSH_ERR_INTERNAL_ERROR;
Damien Miller21cf4e02002-02-19 15:26:42 +1100296 const EVP_CIPHER *type;
297 int klen;
Damien Miller3710f272005-05-26 12:19:17 +1000298 u_char *junk, *discard;
Damien Miller21cf4e02002-02-19 15:26:42 +1100299
300 if (cipher->number == SSH_CIPHER_DES) {
Damien Miller21cf4e02002-02-19 15:26:42 +1100301 if (keylen > 8)
302 keylen = 8;
303 }
Damien Miller1f0311c2014-05-15 14:24:09 +1000304#endif
Damien Miller21cf4e02002-02-19 15:26:42 +1100305 cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
Damien Miller1d75abf2013-01-09 16:12:19 +1100306 cc->encrypt = do_encrypt;
Damien Miller21cf4e02002-02-19 15:26:42 +1100307
Damien Miller86687062014-07-02 15:28:02 +1000308 if (keylen < cipher->key_len ||
309 (iv != NULL && ivlen < cipher_ivlen(cipher)))
310 return SSH_ERR_INVALID_ARGUMENT;
Damien Miller21cf4e02002-02-19 15:26:42 +1100311
Damien Miller86687062014-07-02 15:28:02 +1000312 cc->cipher = cipher;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100313 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
Damien Miller86687062014-07-02 15:28:02 +1000314 return chachapoly_init(&cc->cp_ctx, key, keylen);
Damien Miller0fde8ac2013-11-21 14:12:23 +1100315 }
Damien Miller1f0311c2014-05-15 14:24:09 +1000316#ifndef WITH_OPENSSL
317 if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
318 aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
319 aesctr_ivsetup(&cc->ac_ctx, iv);
Damien Miller86687062014-07-02 15:28:02 +1000320 return 0;
Damien Miller1f0311c2014-05-15 14:24:09 +1000321 }
322 if ((cc->cipher->flags & CFLAG_NONE) != 0)
Damien Miller86687062014-07-02 15:28:02 +1000323 return 0;
324 return SSH_ERR_INVALID_ARGUMENT;
Damien Miller1f0311c2014-05-15 14:24:09 +1000325#else
Damien Miller21cf4e02002-02-19 15:26:42 +1100326 type = (*cipher->evptype)();
Damien Miller21cf4e02002-02-19 15:26:42 +1100327 EVP_CIPHER_CTX_init(&cc->evp);
328 if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
Damien Miller86687062014-07-02 15:28:02 +1000329 (do_encrypt == CIPHER_ENCRYPT)) == 0) {
330 ret = SSH_ERR_LIBCRYPTO_ERROR;
331 goto bad;
332 }
Damien Miller1d75abf2013-01-09 16:12:19 +1100333 if (cipher_authlen(cipher) &&
334 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
Damien Miller86687062014-07-02 15:28:02 +1000335 -1, (u_char *)iv)) {
336 ret = SSH_ERR_LIBCRYPTO_ERROR;
337 goto bad;
338 }
Damien Miller21cf4e02002-02-19 15:26:42 +1100339 klen = EVP_CIPHER_CTX_key_length(&cc->evp);
Damien Millereccb9de2005-06-17 12:59:34 +1000340 if (klen > 0 && keylen != (u_int)klen) {
Damien Miller86687062014-07-02 15:28:02 +1000341 if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) {
342 ret = SSH_ERR_LIBCRYPTO_ERROR;
343 goto bad;
344 }
Damien Miller21cf4e02002-02-19 15:26:42 +1100345 }
Damien Miller86687062014-07-02 15:28:02 +1000346 if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
347 ret = SSH_ERR_LIBCRYPTO_ERROR;
348 goto bad;
349 }
Damien Miller3710f272005-05-26 12:19:17 +1000350
Damien Miller46d38de2005-07-17 17:02:09 +1000351 if (cipher->discard_len > 0) {
Damien Miller86687062014-07-02 15:28:02 +1000352 if ((junk = malloc(cipher->discard_len)) == NULL ||
353 (discard = malloc(cipher->discard_len)) == NULL) {
354 if (junk != NULL)
355 free(junk);
356 ret = SSH_ERR_ALLOC_FAIL;
357 goto bad;
358 }
359 ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len);
Damien Millera5103f42014-02-04 11:20:14 +1100360 explicit_bzero(discard, cipher->discard_len);
Darren Tuckera627d422013-06-02 07:31:17 +1000361 free(junk);
362 free(discard);
Damien Miller86687062014-07-02 15:28:02 +1000363 if (ret != 1) {
364 ret = SSH_ERR_LIBCRYPTO_ERROR;
365 bad:
366 EVP_CIPHER_CTX_cleanup(&cc->evp);
367 return ret;
368 }
Damien Miller3710f272005-05-26 12:19:17 +1000369 }
Damien Miller1f0311c2014-05-15 14:24:09 +1000370#endif
Damien Miller86687062014-07-02 15:28:02 +1000371 return 0;
Damien Miller874d77b2000-10-14 16:23:11 +1100372}
373
Damien Milleraf43a7a2012-12-12 10:46:31 +1100374/*
375 * cipher_crypt() operates as following:
376 * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'.
377 * Theses bytes are treated as additional authenticated data for
378 * authenticated encryption modes.
379 * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'.
Damien Miller1d75abf2013-01-09 16:12:19 +1100380 * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
381 * This tag is written on encryption and verified on decryption.
Damien Milleraf43a7a2012-12-12 10:46:31 +1100382 * Both 'aadlen' and 'authlen' can be set to 0.
383 */
Damien Millerbcd00ab2013-12-07 10:41:55 +1100384int
Damien Miller86687062014-07-02 15:28:02 +1000385cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
386 const u_char *src, u_int len, u_int aadlen, u_int authlen)
Damien Miller874d77b2000-10-14 16:23:11 +1100387{
Damien Miller86687062014-07-02 15:28:02 +1000388 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
389 return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src,
390 len, aadlen, authlen, cc->encrypt);
391 }
Damien Miller1f0311c2014-05-15 14:24:09 +1000392#ifndef WITH_OPENSSL
393 if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
394 if (aadlen)
395 memcpy(dest, src, aadlen);
396 aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
397 dest + aadlen, len);
398 return 0;
399 }
400 if ((cc->cipher->flags & CFLAG_NONE) != 0) {
401 memcpy(dest, src, aadlen + len);
402 return 0;
403 }
Damien Miller86687062014-07-02 15:28:02 +1000404 return SSH_ERR_INVALID_ARGUMENT;
Damien Miller1f0311c2014-05-15 14:24:09 +1000405#else
Damien Miller1d75abf2013-01-09 16:12:19 +1100406 if (authlen) {
407 u_char lastiv[1];
408
409 if (authlen != cipher_authlen(cc->cipher))
Damien Miller86687062014-07-02 15:28:02 +1000410 return SSH_ERR_INVALID_ARGUMENT;
Damien Miller1d75abf2013-01-09 16:12:19 +1100411 /* increment IV */
412 if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
413 1, lastiv))
Damien Miller86687062014-07-02 15:28:02 +1000414 return SSH_ERR_LIBCRYPTO_ERROR;
Damien Miller1d75abf2013-01-09 16:12:19 +1100415 /* set tag on decyption */
416 if (!cc->encrypt &&
417 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG,
418 authlen, (u_char *)src + aadlen + len))
Damien Miller86687062014-07-02 15:28:02 +1000419 return SSH_ERR_LIBCRYPTO_ERROR;
Damien Miller1d75abf2013-01-09 16:12:19 +1100420 }
421 if (aadlen) {
422 if (authlen &&
423 EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)
Damien Miller86687062014-07-02 15:28:02 +1000424 return SSH_ERR_LIBCRYPTO_ERROR;
Damien Milleraf43a7a2012-12-12 10:46:31 +1100425 memcpy(dest, src, aadlen);
Damien Miller1d75abf2013-01-09 16:12:19 +1100426 }
Damien Miller874d77b2000-10-14 16:23:11 +1100427 if (len % cc->cipher->block_size)
Damien Miller86687062014-07-02 15:28:02 +1000428 return SSH_ERR_INVALID_ARGUMENT;
Damien Milleraf43a7a2012-12-12 10:46:31 +1100429 if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen,
430 len) < 0)
Damien Miller86687062014-07-02 15:28:02 +1000431 return SSH_ERR_LIBCRYPTO_ERROR;
Damien Miller1d75abf2013-01-09 16:12:19 +1100432 if (authlen) {
433 /* compute tag (on encrypt) or verify tag (on decrypt) */
Damien Miller86687062014-07-02 15:28:02 +1000434 if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0)
435 return cc->encrypt ?
436 SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
Damien Miller1d75abf2013-01-09 16:12:19 +1100437 if (cc->encrypt &&
438 !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG,
439 authlen, dest + aadlen + len))
Damien Miller86687062014-07-02 15:28:02 +1000440 return SSH_ERR_LIBCRYPTO_ERROR;
Damien Miller1d75abf2013-01-09 16:12:19 +1100441 }
Damien Millerbcd00ab2013-12-07 10:41:55 +1100442 return 0;
Damien Miller1f0311c2014-05-15 14:24:09 +1000443#endif
Damien Miller874d77b2000-10-14 16:23:11 +1100444}
445
Damien Miller0fde8ac2013-11-21 14:12:23 +1100446/* Extract the packet length, including any decryption necessary beforehand */
447int
Damien Miller86687062014-07-02 15:28:02 +1000448cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
Damien Miller0fde8ac2013-11-21 14:12:23 +1100449 const u_char *cp, u_int len)
450{
451 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
452 return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr,
453 cp, len);
454 if (len < 4)
Damien Miller86687062014-07-02 15:28:02 +1000455 return SSH_ERR_MESSAGE_INCOMPLETE;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100456 *plenp = get_u32(cp);
457 return 0;
458}
459
Damien Miller86687062014-07-02 15:28:02 +1000460int
461cipher_cleanup(struct sshcipher_ctx *cc)
Damien Miller874d77b2000-10-14 16:23:11 +1100462{
Damien Miller86687062014-07-02 15:28:02 +1000463 if (cc == NULL || cc->cipher == NULL)
464 return 0;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100465 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
Damien Millera5103f42014-02-04 11:20:14 +1100466 explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));
Damien Miller1f0311c2014-05-15 14:24:09 +1000467 else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
468 explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
469#ifdef WITH_OPENSSL
Damien Miller0fde8ac2013-11-21 14:12:23 +1100470 else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
Damien Miller86687062014-07-02 15:28:02 +1000471 return SSH_ERR_LIBCRYPTO_ERROR;
Damien Miller1f0311c2014-05-15 14:24:09 +1000472#endif
Damien Miller86687062014-07-02 15:28:02 +1000473 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000474}
475
Damien Miller5428f641999-11-25 11:54:57 +1100476/*
477 * Selects the cipher, and keys if by computing the MD5 checksum of the
478 * passphrase and using the resulting 16 bytes as the key.
479 */
Damien Miller86687062014-07-02 15:28:02 +1000480int
481cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000482 const char *passphrase, int do_encrypt)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000483{
Ben Lindstrom46c16222000-12-22 01:43:59 +0000484 u_char digest[16];
Damien Miller86687062014-07-02 15:28:02 +1000485 int r = SSH_ERR_INTERNAL_ERROR;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000486
Damien Miller86687062014-07-02 15:28:02 +1000487 if ((r = ssh_digest_memory(SSH_DIGEST_MD5,
488 passphrase, strlen(passphrase),
489 digest, sizeof(digest))) != 0)
490 goto out;
Damien Miller95def091999-11-25 00:26:21 +1100491
Damien Miller86687062014-07-02 15:28:02 +1000492 r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
493 out:
Damien Millera5103f42014-02-04 11:20:14 +1100494 explicit_bzero(digest, sizeof(digest));
Damien Miller86687062014-07-02 15:28:02 +1000495 return r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000496}
Damien Miller21cf4e02002-02-19 15:26:42 +1100497
Ben Lindstrom6328ab32002-03-22 02:54:23 +0000498/*
Damien Miller86687062014-07-02 15:28:02 +1000499 * Exports an IV from the sshcipher_ctx required to export the key
Ben Lindstrom212faca2002-03-22 01:39:44 +0000500 * state back from the unprivileged child to the privileged parent
501 * process.
502 */
Ben Lindstrom212faca2002-03-22 01:39:44 +0000503int
Damien Miller86687062014-07-02 15:28:02 +1000504cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
Ben Lindstrom212faca2002-03-22 01:39:44 +0000505{
Damien Miller86687062014-07-02 15:28:02 +1000506 const struct sshcipher *c = cc->cipher;
Damien Miller1f0311c2014-05-15 14:24:09 +1000507 int ivlen = 0;
Ben Lindstrom212faca2002-03-22 01:39:44 +0000508
509 if (c->number == SSH_CIPHER_3DES)
510 ivlen = 24;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100511 else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
512 ivlen = 0;
Damien Miller1f0311c2014-05-15 14:24:09 +1000513#ifdef WITH_OPENSSL
Ben Lindstrom212faca2002-03-22 01:39:44 +0000514 else
515 ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
Damien Miller86687062014-07-02 15:28:02 +1000516#endif /* WITH_OPENSSL */
Ben Lindstrom212faca2002-03-22 01:39:44 +0000517 return (ivlen);
518}
519
Damien Miller86687062014-07-02 15:28:02 +1000520int
521cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
Ben Lindstrom212faca2002-03-22 01:39:44 +0000522{
Damien Miller86687062014-07-02 15:28:02 +1000523 const struct sshcipher *c = cc->cipher;
Damien Miller1f0311c2014-05-15 14:24:09 +1000524#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000525 int evplen;
Damien Miller1f0311c2014-05-15 14:24:09 +1000526#endif
Ben Lindstrom212faca2002-03-22 01:39:44 +0000527
Damien Miller0fde8ac2013-11-21 14:12:23 +1100528 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
529 if (len != 0)
Damien Miller86687062014-07-02 15:28:02 +1000530 return SSH_ERR_INVALID_ARGUMENT;
531 return 0;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100532 }
Damien Miller1f0311c2014-05-15 14:24:09 +1000533 if ((cc->cipher->flags & CFLAG_NONE) != 0)
Damien Miller86687062014-07-02 15:28:02 +1000534 return 0;
Damien Miller0fde8ac2013-11-21 14:12:23 +1100535
Ben Lindstrom212faca2002-03-22 01:39:44 +0000536 switch (c->number) {
Damien Miller1f0311c2014-05-15 14:24:09 +1000537#ifdef WITH_OPENSSL
Ben Lindstrom212faca2002-03-22 01:39:44 +0000538 case SSH_CIPHER_SSH2:
539 case SSH_CIPHER_DES:
540 case SSH_CIPHER_BLOWFISH:
541 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
542 if (evplen == 0)
Damien Miller86687062014-07-02 15:28:02 +1000543 return 0;
544 else if (evplen < 0)
545 return SSH_ERR_LIBCRYPTO_ERROR;
546 if ((u_int)evplen != len)
547 return SSH_ERR_INVALID_ARGUMENT;
Damien Millereae88742014-05-27 14:27:02 +1000548 if (cipher_authlen(c)) {
Damien Miller86687062014-07-02 15:28:02 +1000549 if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
550 len, iv))
551 return SSH_ERR_LIBCRYPTO_ERROR;
552 } else
553 memcpy(iv, cc->evp.iv, len);
Ben Lindstrom212faca2002-03-22 01:39:44 +0000554 break;
Damien Miller86687062014-07-02 15:28:02 +1000555#endif
Damien Miller1f0311c2014-05-15 14:24:09 +1000556#ifdef WITH_SSH1
Damien Millera201bb32003-05-14 13:41:23 +1000557 case SSH_CIPHER_3DES:
Damien Miller86687062014-07-02 15:28:02 +1000558 return ssh1_3des_iv(&cc->evp, 0, iv, 24);
559#endif
Ben Lindstrom212faca2002-03-22 01:39:44 +0000560 default:
Damien Miller86687062014-07-02 15:28:02 +1000561 return SSH_ERR_INVALID_ARGUMENT;
Ben Lindstrom212faca2002-03-22 01:39:44 +0000562 }
Damien Miller86687062014-07-02 15:28:02 +1000563 return 0;
Ben Lindstrom212faca2002-03-22 01:39:44 +0000564}
565
Ben Lindstrom212faca2002-03-22 01:39:44 +0000566int
Damien Miller86687062014-07-02 15:28:02 +1000567cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
568{
569 const struct sshcipher *c = cc->cipher;
570#ifdef WITH_OPENSSL
571 int evplen = 0;
572#endif
573
574 if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
575 return 0;
576 if ((cc->cipher->flags & CFLAG_NONE) != 0)
577 return 0;
578
579 switch (c->number) {
580#ifdef WITH_OPENSSL
581 case SSH_CIPHER_SSH2:
582 case SSH_CIPHER_DES:
583 case SSH_CIPHER_BLOWFISH:
584 evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
585 if (evplen <= 0)
586 return SSH_ERR_LIBCRYPTO_ERROR;
587 if (cipher_authlen(c)) {
588 /* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
589 if (!EVP_CIPHER_CTX_ctrl(&cc->evp,
590 EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
591 return SSH_ERR_LIBCRYPTO_ERROR;
592 } else
593 memcpy(cc->evp.iv, iv, evplen);
594 break;
595#endif
596#ifdef WITH_SSH1
597 case SSH_CIPHER_3DES:
598 return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);
599#endif
600 default:
601 return SSH_ERR_INVALID_ARGUMENT;
602 }
603 return 0;
604}
605
606#ifdef WITH_OPENSSL
607#define EVP_X_STATE(evp) (evp).cipher_data
608#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size
609#endif
610
611int
612cipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat)
Ben Lindstrom212faca2002-03-22 01:39:44 +0000613{
Damien Miller1f0311c2014-05-15 14:24:09 +1000614#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000615 const struct sshcipher *c = cc->cipher;
Ben Lindstrom402c6cc2002-06-21 00:43:42 +0000616 int plen = 0;
Ben Lindstrom212faca2002-03-22 01:39:44 +0000617
Damien Millerf0a8ded2013-02-12 11:00:34 +1100618 if (c->evptype == EVP_rc4) {
Ben Lindstrom402c6cc2002-06-21 00:43:42 +0000619 plen = EVP_X_STATE_LEN(cc->evp);
Ben Lindstrom212faca2002-03-22 01:39:44 +0000620 if (dat == NULL)
Ben Lindstrom402c6cc2002-06-21 00:43:42 +0000621 return (plen);
622 memcpy(dat, EVP_X_STATE(cc->evp), plen);
Ben Lindstrom212faca2002-03-22 01:39:44 +0000623 }
Ben Lindstrom212faca2002-03-22 01:39:44 +0000624 return (plen);
Damien Miller1f0311c2014-05-15 14:24:09 +1000625#else
Damien Miller86687062014-07-02 15:28:02 +1000626 return 0;
Damien Miller1f0311c2014-05-15 14:24:09 +1000627#endif
Ben Lindstrom212faca2002-03-22 01:39:44 +0000628}
629
630void
Damien Miller86687062014-07-02 15:28:02 +1000631cipher_set_keycontext(struct sshcipher_ctx *cc, const u_char *dat)
Ben Lindstrom212faca2002-03-22 01:39:44 +0000632{
Damien Miller1f0311c2014-05-15 14:24:09 +1000633#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000634 const struct sshcipher *c = cc->cipher;
Ben Lindstrom212faca2002-03-22 01:39:44 +0000635 int plen;
636
Damien Millerf0a8ded2013-02-12 11:00:34 +1100637 if (c->evptype == EVP_rc4) {
Ben Lindstrom212faca2002-03-22 01:39:44 +0000638 plen = EVP_X_STATE_LEN(cc->evp);
639 memcpy(EVP_X_STATE(cc->evp), dat, plen);
640 }
Damien Miller1f0311c2014-05-15 14:24:09 +1000641#endif
Damien Miller21cf4e02002-02-19 15:26:42 +1100642}