1d059297112922cabb0c674840589be8db821fd9aAdam Langley/* $OpenBSD: cipher.c,v 1.100 2015/01/14 10:29:45 djm Exp $ */
2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Author: Tatu Ylonen <ylo@cs.hut.fi>
4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *                    All rights reserved
6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * As far as I am concerned, the code I have written for this software
8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * can be used freely for any purpose.  Any derived versions of this
9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * software must be clearly marked as such, and if the derived work is
10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * incompatible with the protocol description in the RFC file, it must be
11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * called by a name other than "ssh" or "Secure Shell".
12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1999 Niels Provos.  All rights reserved.
15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1999, 2000 Markus Friedl.  All rights reserved.
16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without
18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions
19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met:
20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright
21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer.
22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright
23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer in the
24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    documentation and/or other materials provided with the distribution.
25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h"
39bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h>
41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h>
43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h>
44d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <stdio.h>
45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "cipher.h"
47d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "misc.h"
48d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h"
49d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h"
50d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "digest.h"
51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "openbsd-compat/openssl-compat.h"
53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
54d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern const EVP_CIPHER *evp_ssh1_bf(void);
56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanextern const EVP_CIPHER *evp_ssh1_3des(void);
57d059297112922cabb0c674840589be8db821fd9aAdam Langleyextern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
58d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
60d059297112922cabb0c674840589be8db821fd9aAdam Langleystruct sshcipher {
61bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char	*name;
62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int	number;		/* for ssh1 only */
63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int	block_size;
64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int	key_len;
65d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int	iv_len;		/* defaults to block_size */
66d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int	auth_len;
67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int	discard_len;
68d059297112922cabb0c674840589be8db821fd9aAdam Langley	u_int	flags;
69d059297112922cabb0c674840589be8db821fd9aAdam Langley#define CFLAG_CBC		(1<<0)
70d059297112922cabb0c674840589be8db821fd9aAdam Langley#define CFLAG_CHACHAPOLY	(1<<1)
71d059297112922cabb0c674840589be8db821fd9aAdam Langley#define CFLAG_AESCTR		(1<<2)
72d059297112922cabb0c674840589be8db821fd9aAdam Langley#define CFLAG_NONE		(1<<3)
73d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
74bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	const EVP_CIPHER	*(*evptype)(void);
75d059297112922cabb0c674840589be8db821fd9aAdam Langley#else
76d059297112922cabb0c674840589be8db821fd9aAdam Langley	void	*ignored;
77d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
78d059297112922cabb0c674840589be8db821fd9aAdam Langley};
79d059297112922cabb0c674840589be8db821fd9aAdam Langley
80d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic const struct sshcipher ciphers[] = {
81d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
82d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "des",	SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
83d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "3des",	SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
84d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "blowfish",	SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf },
85d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
86d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
87d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
88d059297112922cabb0c674840589be8db821fd9aAdam Langley#if !defined(ANDROID)
89d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "3des-cbc",	SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
90d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "blowfish-cbc",
91d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc },
92d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "cast128-cbc",
93d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_cast5_cbc },
94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
95d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "arcfour",	SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 0, EVP_rc4 },
96d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "arcfour128",	SSH_CIPHER_SSH2, 8, 16, 0, 0, 1536, 0, EVP_rc4 },
97d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "arcfour256",	SSH_CIPHER_SSH2, 8, 32, 0, 0, 1536, 0, EVP_rc4 },
98d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes128-cbc",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc },
99d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes192-cbc",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc },
100d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes256-cbc",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	{ "rijndael-cbc@lysator.liu.se",
102d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
103d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes128-ctr",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
104d059297112922cabb0c674840589be8db821fd9aAdam Langley#if !defined(ANDROID)
105d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes192-ctr",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
106bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
107d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes256-ctr",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
108d059297112922cabb0c674840589be8db821fd9aAdam Langley# ifdef OPENSSL_HAVE_EVPGCM
109d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes128-gcm@openssh.com",
110d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
111d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes256-gcm@openssh.com",
112d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
113d059297112922cabb0c674840589be8db821fd9aAdam Langley# endif /* OPENSSL_HAVE_EVPGCM */
114d059297112922cabb0c674840589be8db821fd9aAdam Langley#else /* WITH_OPENSSL */
115d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes128-ctr",	SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL },
116d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes192-ctr",	SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL },
117d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "aes256-ctr",	SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL },
118d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "none",	SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL },
119d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_OPENSSL */
120d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ "chacha20-poly1305@openssh.com",
121d059297112922cabb0c674840589be8db821fd9aAdam Langley			SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL },
122d059297112922cabb0c674840589be8db821fd9aAdam Langley
123d059297112922cabb0c674840589be8db821fd9aAdam Langley	{ NULL,		SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman};
125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
126bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*--*/
127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
128d059297112922cabb0c674840589be8db821fd9aAdam Langley/* Returns a comma-separated list of supported ciphers. */
129d059297112922cabb0c674840589be8db821fd9aAdam Langleychar *
130d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_alg_list(char sep, int auth_only)
131d059297112922cabb0c674840589be8db821fd9aAdam Langley{
132d059297112922cabb0c674840589be8db821fd9aAdam Langley	char *tmp, *ret = NULL;
133d059297112922cabb0c674840589be8db821fd9aAdam Langley	size_t nlen, rlen = 0;
134d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c;
135d059297112922cabb0c674840589be8db821fd9aAdam Langley
136d059297112922cabb0c674840589be8db821fd9aAdam Langley	for (c = ciphers; c->name != NULL; c++) {
137d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (c->number != SSH_CIPHER_SSH2)
138d059297112922cabb0c674840589be8db821fd9aAdam Langley			continue;
139d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (auth_only && c->auth_len == 0)
140d059297112922cabb0c674840589be8db821fd9aAdam Langley			continue;
141d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (ret != NULL)
142d059297112922cabb0c674840589be8db821fd9aAdam Langley			ret[rlen++] = sep;
143d059297112922cabb0c674840589be8db821fd9aAdam Langley		nlen = strlen(c->name);
144d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
145d059297112922cabb0c674840589be8db821fd9aAdam Langley			free(ret);
146d059297112922cabb0c674840589be8db821fd9aAdam Langley			return NULL;
147d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
148d059297112922cabb0c674840589be8db821fd9aAdam Langley		ret = tmp;
149d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(ret + rlen, c->name, nlen + 1);
150d059297112922cabb0c674840589be8db821fd9aAdam Langley		rlen += nlen;
151d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
152d059297112922cabb0c674840589be8db821fd9aAdam Langley	return ret;
153d059297112922cabb0c674840589be8db821fd9aAdam Langley}
154d059297112922cabb0c674840589be8db821fd9aAdam Langley
155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanu_int
156d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_blocksize(const struct sshcipher *c)
157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (c->block_size);
159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanu_int
162d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_keylen(const struct sshcipher *c)
163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (c->key_len);
165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanu_int
168d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_seclen(const struct sshcipher *c)
169d059297112922cabb0c674840589be8db821fd9aAdam Langley{
170d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (strcmp("3des-cbc", c->name) == 0)
171d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 14;
172d059297112922cabb0c674840589be8db821fd9aAdam Langley	return cipher_keylen(c);
173d059297112922cabb0c674840589be8db821fd9aAdam Langley}
174d059297112922cabb0c674840589be8db821fd9aAdam Langley
175d059297112922cabb0c674840589be8db821fd9aAdam Langleyu_int
176d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_authlen(const struct sshcipher *c)
177d059297112922cabb0c674840589be8db821fd9aAdam Langley{
178d059297112922cabb0c674840589be8db821fd9aAdam Langley	return (c->auth_len);
179d059297112922cabb0c674840589be8db821fd9aAdam Langley}
180d059297112922cabb0c674840589be8db821fd9aAdam Langley
181d059297112922cabb0c674840589be8db821fd9aAdam Langleyu_int
182d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_ivlen(const struct sshcipher *c)
183d059297112922cabb0c674840589be8db821fd9aAdam Langley{
184d059297112922cabb0c674840589be8db821fd9aAdam Langley	/*
185d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * Default is cipher block size, except for chacha20+poly1305 that
186d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * needs no IV. XXX make iv_len == -1 default?
187d059297112922cabb0c674840589be8db821fd9aAdam Langley	 */
188d059297112922cabb0c674840589be8db821fd9aAdam Langley	return (c->iv_len != 0 || (c->flags & CFLAG_CHACHAPOLY) != 0) ?
189d059297112922cabb0c674840589be8db821fd9aAdam Langley	    c->iv_len : c->block_size;
190d059297112922cabb0c674840589be8db821fd9aAdam Langley}
191d059297112922cabb0c674840589be8db821fd9aAdam Langley
192d059297112922cabb0c674840589be8db821fd9aAdam Langleyu_int
193d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_get_number(const struct sshcipher *c)
194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (c->number);
196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanu_int
199d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_is_cbc(const struct sshcipher *c)
200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
201d059297112922cabb0c674840589be8db821fd9aAdam Langley	return (c->flags & CFLAG_CBC) != 0;
202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanu_int
205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancipher_mask_ssh1(int client)
206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int mask = 0;
208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	mask |= 1 << SSH_CIPHER_3DES;		/* Mandatory */
209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	mask |= 1 << SSH_CIPHER_BLOWFISH;
210bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (client) {
211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		mask |= 1 << SSH_CIPHER_DES;
212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return mask;
214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
216d059297112922cabb0c674840589be8db821fd9aAdam Langleyconst struct sshcipher *
217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancipher_by_name(const char *name)
218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
219d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c;
220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (c = ciphers; c->name != NULL; c++)
221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (strcmp(c->name, name) == 0)
222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return c;
223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return NULL;
224bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
226d059297112922cabb0c674840589be8db821fd9aAdam Langleyconst struct sshcipher *
227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancipher_by_number(int id)
228bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
229d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c;
230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (c = ciphers; c->name != NULL; c++)
231bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (c->number == id)
232bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return c;
233bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return NULL;
234bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define	CIPHER_SEP	","
237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanciphers_valid(const char *names)
239bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
240d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c;
241bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *cipher_list, *cp;
242bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *p;
243bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
244bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (names == NULL || strcmp(names, "") == 0)
245bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
246d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cipher_list = cp = strdup(names)) == NULL)
247d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
248bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
249bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    (p = strsep(&cp, CIPHER_SEP))) {
250bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		c = cipher_by_name(p);
251bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (c == NULL || c->number != SSH_CIPHER_SSH2) {
252d059297112922cabb0c674840589be8db821fd9aAdam Langley			free(cipher_list);
253bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return 0;
254bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
255bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
256d059297112922cabb0c674840589be8db821fd9aAdam Langley	free(cipher_list);
257bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return 1;
258bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
259bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
260bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
261bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Parses the name of the cipher.  Returns the number of the corresponding
262bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * cipher, or -1 on error.
263bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
264bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
265bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
266bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancipher_number(const char *name)
267bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
268d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c;
269bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (name == NULL)
270bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return -1;
271bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (c = ciphers; c->name != NULL; c++)
272bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (strcasecmp(c->name, name) == 0)
273bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return c->number;
274bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return -1;
275bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
276bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
277bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanchar *
278bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmancipher_name(int id)
279bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
280d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c = cipher_by_number(id);
281bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (c==NULL) ? "<unknown>" : c->name;
282bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
283bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
284d059297112922cabb0c674840589be8db821fd9aAdam Langleyconst char *
285d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_warning_message(const struct sshcipher_ctx *cc)
286d059297112922cabb0c674840589be8db821fd9aAdam Langley{
287d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (cc == NULL || cc->cipher == NULL)
288d059297112922cabb0c674840589be8db821fd9aAdam Langley		return NULL;
289d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (cc->cipher->number == SSH_CIPHER_DES)
290d059297112922cabb0c674840589be8db821fd9aAdam Langley		return "use of DES is strongly discouraged due to "
291d059297112922cabb0c674840589be8db821fd9aAdam Langley		    "cryptographic weaknesses";
292d059297112922cabb0c674840589be8db821fd9aAdam Langley	return NULL;
293d059297112922cabb0c674840589be8db821fd9aAdam Langley}
294d059297112922cabb0c674840589be8db821fd9aAdam Langley
295d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
296d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_init(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
297bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman    const u_char *key, u_int keylen, const u_char *iv, u_int ivlen,
298bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman    int do_encrypt)
299bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
300d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
301d059297112922cabb0c674840589be8db821fd9aAdam Langley	int ret = SSH_ERR_INTERNAL_ERROR;
302bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	const EVP_CIPHER *type;
303bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int klen;
304bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char *junk, *discard;
305bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
306bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (cipher->number == SSH_CIPHER_DES) {
307bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (keylen > 8)
308bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			keylen = 8;
309bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
310d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
311bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
312d059297112922cabb0c674840589be8db821fd9aAdam Langley	cc->encrypt = do_encrypt;
313bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
314d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (keylen < cipher->key_len ||
315d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (iv != NULL && ivlen < cipher_ivlen(cipher)))
316d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_ARGUMENT;
317bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
318d059297112922cabb0c674840589be8db821fd9aAdam Langley	cc->cipher = cipher;
319d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
320d059297112922cabb0c674840589be8db821fd9aAdam Langley		return chachapoly_init(&cc->cp_ctx, key, keylen);
321d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
322d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifndef WITH_OPENSSL
323d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
324d059297112922cabb0c674840589be8db821fd9aAdam Langley		aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
325d059297112922cabb0c674840589be8db821fd9aAdam Langley		aesctr_ivsetup(&cc->ac_ctx, iv);
326d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
327bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
328d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_NONE) != 0)
329d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
330d059297112922cabb0c674840589be8db821fd9aAdam Langley	return SSH_ERR_INVALID_ARGUMENT;
331bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#else
332d059297112922cabb0c674840589be8db821fd9aAdam Langley	type = (*cipher->evptype)();
333d059297112922cabb0c674840589be8db821fd9aAdam Langley	EVP_CIPHER_CTX_init(&cc->evp);
334bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
335d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (do_encrypt == CIPHER_ENCRYPT)) == 0) {
336d059297112922cabb0c674840589be8db821fd9aAdam Langley		ret = SSH_ERR_LIBCRYPTO_ERROR;
337d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto bad;
338d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
339d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (cipher_authlen(cipher) &&
340d059297112922cabb0c674840589be8db821fd9aAdam Langley	    !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED,
341d059297112922cabb0c674840589be8db821fd9aAdam Langley	    -1, (u_char *)iv)) {
342d059297112922cabb0c674840589be8db821fd9aAdam Langley		ret = SSH_ERR_LIBCRYPTO_ERROR;
343d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto bad;
344d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
345bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	klen = EVP_CIPHER_CTX_key_length(&cc->evp);
346bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (klen > 0 && keylen != (u_int)klen) {
347d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) {
348d059297112922cabb0c674840589be8db821fd9aAdam Langley			ret = SSH_ERR_LIBCRYPTO_ERROR;
349d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto bad;
350d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
351d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
352d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
353d059297112922cabb0c674840589be8db821fd9aAdam Langley		ret = SSH_ERR_LIBCRYPTO_ERROR;
354d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto bad;
355bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
356bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
357bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (cipher->discard_len > 0) {
358d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((junk = malloc(cipher->discard_len)) == NULL ||
359d059297112922cabb0c674840589be8db821fd9aAdam Langley		    (discard = malloc(cipher->discard_len)) == NULL) {
360d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (junk != NULL)
361d059297112922cabb0c674840589be8db821fd9aAdam Langley				free(junk);
362d059297112922cabb0c674840589be8db821fd9aAdam Langley			ret = SSH_ERR_ALLOC_FAIL;
363d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto bad;
364d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
365d059297112922cabb0c674840589be8db821fd9aAdam Langley		ret = EVP_Cipher(&cc->evp, discard, junk, cipher->discard_len);
366d059297112922cabb0c674840589be8db821fd9aAdam Langley		explicit_bzero(discard, cipher->discard_len);
367d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(junk);
368d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(discard);
369d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (ret != 1) {
370d059297112922cabb0c674840589be8db821fd9aAdam Langley			ret = SSH_ERR_LIBCRYPTO_ERROR;
371d059297112922cabb0c674840589be8db821fd9aAdam Langley bad:
372d059297112922cabb0c674840589be8db821fd9aAdam Langley			EVP_CIPHER_CTX_cleanup(&cc->evp);
373d059297112922cabb0c674840589be8db821fd9aAdam Langley			return ret;
374d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
375bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
376d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
377d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
378bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
379bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
380d059297112922cabb0c674840589be8db821fd9aAdam Langley/*
381d059297112922cabb0c674840589be8db821fd9aAdam Langley * cipher_crypt() operates as following:
382d059297112922cabb0c674840589be8db821fd9aAdam Langley * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'.
383d059297112922cabb0c674840589be8db821fd9aAdam Langley * Theses bytes are treated as additional authenticated data for
384d059297112922cabb0c674840589be8db821fd9aAdam Langley * authenticated encryption modes.
385d059297112922cabb0c674840589be8db821fd9aAdam Langley * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'.
386d059297112922cabb0c674840589be8db821fd9aAdam Langley * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag.
387d059297112922cabb0c674840589be8db821fd9aAdam Langley * This tag is written on encryption and verified on decryption.
388d059297112922cabb0c674840589be8db821fd9aAdam Langley * Both 'aadlen' and 'authlen' can be set to 0.
389d059297112922cabb0c674840589be8db821fd9aAdam Langley */
390d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
391d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
392d059297112922cabb0c674840589be8db821fd9aAdam Langley   const u_char *src, u_int len, u_int aadlen, u_int authlen)
393bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
394d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
395d059297112922cabb0c674840589be8db821fd9aAdam Langley		return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src,
396d059297112922cabb0c674840589be8db821fd9aAdam Langley		    len, aadlen, authlen, cc->encrypt);
397d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
398d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifndef WITH_OPENSSL
399d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
400d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (aadlen)
401d059297112922cabb0c674840589be8db821fd9aAdam Langley			memcpy(dest, src, aadlen);
402d059297112922cabb0c674840589be8db821fd9aAdam Langley		aesctr_encrypt_bytes(&cc->ac_ctx, src + aadlen,
403d059297112922cabb0c674840589be8db821fd9aAdam Langley		    dest + aadlen, len);
404d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
405d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
406d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_NONE) != 0) {
407d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(dest, src, aadlen + len);
408d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
409d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
410d059297112922cabb0c674840589be8db821fd9aAdam Langley	return SSH_ERR_INVALID_ARGUMENT;
411d059297112922cabb0c674840589be8db821fd9aAdam Langley#else
412d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (authlen) {
413d059297112922cabb0c674840589be8db821fd9aAdam Langley		u_char lastiv[1];
414d059297112922cabb0c674840589be8db821fd9aAdam Langley
415d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (authlen != cipher_authlen(cc->cipher))
416d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_INVALID_ARGUMENT;
417d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* increment IV */
418d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
419d059297112922cabb0c674840589be8db821fd9aAdam Langley		    1, lastiv))
420d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_LIBCRYPTO_ERROR;
421d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* set tag on decyption */
422d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (!cc->encrypt &&
423d059297112922cabb0c674840589be8db821fd9aAdam Langley		    !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG,
424d059297112922cabb0c674840589be8db821fd9aAdam Langley		    authlen, (u_char *)src + aadlen + len))
425d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_LIBCRYPTO_ERROR;
426d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
427d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (aadlen) {
428d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (authlen &&
429d059297112922cabb0c674840589be8db821fd9aAdam Langley		    EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0)
430d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_LIBCRYPTO_ERROR;
431d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(dest, src, aadlen);
432d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
433bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (len % cc->cipher->block_size)
434d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_ARGUMENT;
435d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen,
436d059297112922cabb0c674840589be8db821fd9aAdam Langley	    len) < 0)
437d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_LIBCRYPTO_ERROR;
438d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (authlen) {
439d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* compute tag (on encrypt) or verify tag (on decrypt) */
440d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0)
441d059297112922cabb0c674840589be8db821fd9aAdam Langley			return cc->encrypt ?
442d059297112922cabb0c674840589be8db821fd9aAdam Langley			    SSH_ERR_LIBCRYPTO_ERROR : SSH_ERR_MAC_INVALID;
443d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (cc->encrypt &&
444d059297112922cabb0c674840589be8db821fd9aAdam Langley		    !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG,
445d059297112922cabb0c674840589be8db821fd9aAdam Langley		    authlen, dest + aadlen + len))
446d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_LIBCRYPTO_ERROR;
447d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
448d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
449d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
450bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
451bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
452d059297112922cabb0c674840589be8db821fd9aAdam Langley/* Extract the packet length, including any decryption necessary beforehand */
453d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
454d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
455d059297112922cabb0c674840589be8db821fd9aAdam Langley    const u_char *cp, u_int len)
456bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
457d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
458d059297112922cabb0c674840589be8db821fd9aAdam Langley		return chachapoly_get_length(&cc->cp_ctx, plenp, seqnr,
459d059297112922cabb0c674840589be8db821fd9aAdam Langley		    cp, len);
460d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (len < 4)
461d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_MESSAGE_INCOMPLETE;
462d059297112922cabb0c674840589be8db821fd9aAdam Langley	*plenp = get_u32(cp);
463d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
464d059297112922cabb0c674840589be8db821fd9aAdam Langley}
465d059297112922cabb0c674840589be8db821fd9aAdam Langley
466d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
467d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_cleanup(struct sshcipher_ctx *cc)
468d059297112922cabb0c674840589be8db821fd9aAdam Langley{
469d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (cc == NULL || cc->cipher == NULL)
470d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
471d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
472d059297112922cabb0c674840589be8db821fd9aAdam Langley		explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx));
473d059297112922cabb0c674840589be8db821fd9aAdam Langley	else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
474d059297112922cabb0c674840589be8db821fd9aAdam Langley		explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx));
475d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
476d059297112922cabb0c674840589be8db821fd9aAdam Langley	else if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
477d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_LIBCRYPTO_ERROR;
478d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
479d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
480bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
481bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
482bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
483bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Selects the cipher, and keys if by computing the MD5 checksum of the
484bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * passphrase and using the resulting 16 bytes as the key.
485bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
486d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
487d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher,
488bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman    const char *passphrase, int do_encrypt)
489bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
490bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char digest[16];
491d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r = SSH_ERR_INTERNAL_ERROR;
492bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
493d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = ssh_digest_memory(SSH_DIGEST_MD5,
494d059297112922cabb0c674840589be8db821fd9aAdam Langley	    passphrase, strlen(passphrase),
495d059297112922cabb0c674840589be8db821fd9aAdam Langley	    digest, sizeof(digest))) != 0)
496d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
497bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
498d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt);
499d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
500d059297112922cabb0c674840589be8db821fd9aAdam Langley	explicit_bzero(digest, sizeof(digest));
501d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
502bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
503bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
504bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
505d059297112922cabb0c674840589be8db821fd9aAdam Langley * Exports an IV from the sshcipher_ctx required to export the key
506bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * state back from the unprivileged child to the privileged parent
507bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * process.
508bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
509bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
510d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_get_keyiv_len(const struct sshcipher_ctx *cc)
511bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
512d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c = cc->cipher;
513d059297112922cabb0c674840589be8db821fd9aAdam Langley	int ivlen = 0;
514bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
515bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (c->number == SSH_CIPHER_3DES)
516bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		ivlen = 24;
517d059297112922cabb0c674840589be8db821fd9aAdam Langley	else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
518d059297112922cabb0c674840589be8db821fd9aAdam Langley		ivlen = 0;
519d059297112922cabb0c674840589be8db821fd9aAdam Langley	else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
520d059297112922cabb0c674840589be8db821fd9aAdam Langley		ivlen = sizeof(cc->ac_ctx.ctr);
521d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
522bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	else
523bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
524d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_OPENSSL */
525bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (ivlen);
526bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
527bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
528d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
529d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
530bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
531d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c = cc->cipher;
532d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
533d059297112922cabb0c674840589be8db821fd9aAdam Langley 	int evplen;
534d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
535d059297112922cabb0c674840589be8db821fd9aAdam Langley
536d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
537d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (len != 0)
538d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_INVALID_ARGUMENT;
539d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
540d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
541d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
542d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (len != sizeof(cc->ac_ctx.ctr))
543d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_INVALID_ARGUMENT;
544d059297112922cabb0c674840589be8db821fd9aAdam Langley		memcpy(iv, cc->ac_ctx.ctr, len);
545d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
546d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
547d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_NONE) != 0)
548d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
549bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
550bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	switch (c->number) {
551d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
552bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_SSH2:
553bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_DES:
554bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_BLOWFISH:
555bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
556d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (evplen == 0)
557d059297112922cabb0c674840589be8db821fd9aAdam Langley			return 0;
558d059297112922cabb0c674840589be8db821fd9aAdam Langley		else if (evplen < 0)
559d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_LIBCRYPTO_ERROR;
560bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if ((u_int)evplen != len)
561d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_INVALID_ARGUMENT;
562d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifndef OPENSSL_HAVE_EVPCTR
563bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (c->evptype == evp_aes_128_ctr)
564bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			ssh_aes_ctr_iv(&cc->evp, 0, iv, len);
565bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		else
566d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
567d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (cipher_authlen(c)) {
568d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
569d059297112922cabb0c674840589be8db821fd9aAdam Langley			   len, iv))
570d059297112922cabb0c674840589be8db821fd9aAdam Langley			       return SSH_ERR_LIBCRYPTO_ERROR;
571d059297112922cabb0c674840589be8db821fd9aAdam Langley		} else
572bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			memcpy(iv, cc->evp.iv, len);
573bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
574d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
575d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
576bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_3DES:
577d059297112922cabb0c674840589be8db821fd9aAdam Langley		return ssh1_3des_iv(&cc->evp, 0, iv, 24);
578d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
579bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	default:
580d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_ARGUMENT;
581bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
582d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
583bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
584bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
585d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
586d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
587bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
588d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c = cc->cipher;
589d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
590d059297112922cabb0c674840589be8db821fd9aAdam Langley 	int evplen = 0;
591d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
592d059297112922cabb0c674840589be8db821fd9aAdam Langley
593d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
594d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
595d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((cc->cipher->flags & CFLAG_NONE) != 0)
596d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
597bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
598bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	switch (c->number) {
599d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
600bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_SSH2:
601bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_DES:
602bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_BLOWFISH:
603bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
604d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (evplen <= 0)
605d059297112922cabb0c674840589be8db821fd9aAdam Langley			return SSH_ERR_LIBCRYPTO_ERROR;
606d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (cipher_authlen(c)) {
607d059297112922cabb0c674840589be8db821fd9aAdam Langley			/* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
608d059297112922cabb0c674840589be8db821fd9aAdam Langley			if (!EVP_CIPHER_CTX_ctrl(&cc->evp,
609d059297112922cabb0c674840589be8db821fd9aAdam Langley			    EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
610d059297112922cabb0c674840589be8db821fd9aAdam Langley				return SSH_ERR_LIBCRYPTO_ERROR;
611d059297112922cabb0c674840589be8db821fd9aAdam Langley		} else
612bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			memcpy(cc->evp.iv, iv, evplen);
613bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
614d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
615d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
616bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case SSH_CIPHER_3DES:
617d059297112922cabb0c674840589be8db821fd9aAdam Langley		return ssh1_3des_iv(&cc->evp, 1, (u_char *)iv, 24);
618d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
619bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	default:
620d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_ARGUMENT;
621bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
622d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
623bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
624bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
625d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
626bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define EVP_X_STATE(evp)	(evp).cipher_data
627bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define EVP_X_STATE_LEN(evp)	(evp).cipher->ctx_size
628bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
629bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
630bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
631d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_get_keycontext(const struct sshcipher_ctx *cc, u_char *dat)
632bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
633d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
634d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c = cc->cipher;
635bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int plen = 0;
636bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
637d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (c->evptype == EVP_rc4) {
638bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		plen = EVP_X_STATE_LEN(cc->evp);
639bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (dat == NULL)
640bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			return (plen);
641bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		memcpy(dat, EVP_X_STATE(cc->evp), plen);
642bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
643bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return (plen);
644d059297112922cabb0c674840589be8db821fd9aAdam Langley#else
645d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
646d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
647bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
648bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
649bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid
650d059297112922cabb0c674840589be8db821fd9aAdam Langleycipher_set_keycontext(struct sshcipher_ctx *cc, const u_char *dat)
651bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
652d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
653d059297112922cabb0c674840589be8db821fd9aAdam Langley	const struct sshcipher *c = cc->cipher;
654bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int plen;
655bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
656d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (c->evptype == EVP_rc4) {
657bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		plen = EVP_X_STATE_LEN(cc->evp);
658bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		memcpy(EVP_X_STATE(cc->evp), dat, plen);
659bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
660d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif
661bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
662