xref: /openssh-portable/cipher-ctr.c (revision 72ef7c14)
19a3d0dc0SDamien Miller /* $OpenBSD: cipher-ctr.c,v 1.11 2010/10/01 23:05:32 djm Exp $ */
2f5399c24SDamien Miller /*
30275b523SDamien Miller  * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
4f5399c24SDamien Miller  *
50275b523SDamien Miller  * Permission to use, copy, modify, and distribute this software for any
60275b523SDamien Miller  * purpose with or without fee is hereby granted, provided that the above
70275b523SDamien Miller  * copyright notice and this permission notice appear in all copies.
8f5399c24SDamien Miller  *
90275b523SDamien Miller  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100275b523SDamien Miller  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110275b523SDamien Miller  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120275b523SDamien Miller  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130275b523SDamien Miller  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140275b523SDamien Miller  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150275b523SDamien Miller  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f5399c24SDamien Miller  */
17f5399c24SDamien Miller #include "includes.h"
18f5399c24SDamien Miller 
19*72ef7c14SDamien Miller #if defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR)
20d7834353SDamien Miller #include <sys/types.h>
21d7834353SDamien Miller 
22ded319ccSDamien Miller #include <stdarg.h>
23e3476ed0SDamien Miller #include <string.h>
24e3476ed0SDamien Miller 
25f5399c24SDamien Miller #include <openssl/evp.h>
26f5399c24SDamien Miller 
27f5399c24SDamien Miller #include "xmalloc.h"
28d7834353SDamien Miller #include "log.h"
29f5399c24SDamien Miller 
30129d0bb6SDarren Tucker /* compatibility with old or broken OpenSSL versions */
31129d0bb6SDarren Tucker #include "openbsd-compat/openssl-compat.h"
325c3a5584SDamien Miller 
33cb52017aSDarren Tucker #ifndef USE_BUILTIN_RIJNDAEL
34f5399c24SDamien Miller #include <openssl/aes.h>
35f5399c24SDamien Miller #endif
36f5399c24SDamien Miller 
37f5399c24SDamien Miller struct ssh_aes_ctr_ctx
38f5399c24SDamien Miller {
39f5399c24SDamien Miller 	AES_KEY		aes_ctx;
40f5399c24SDamien Miller 	u_char		aes_counter[AES_BLOCK_SIZE];
41f5399c24SDamien Miller };
42f5399c24SDamien Miller 
43f5399c24SDamien Miller /*
44f5399c24SDamien Miller  * increment counter 'ctr',
45f5399c24SDamien Miller  * the counter is of size 'len' bytes and stored in network-byte-order.
46f5399c24SDamien Miller  * (LSB at ctr[len-1], MSB at ctr[0])
47f5399c24SDamien Miller  */
48f5399c24SDamien Miller static void
ssh_ctr_inc(u_char * ctr,size_t len)499a3d0dc0SDamien Miller ssh_ctr_inc(u_char *ctr, size_t len)
50f5399c24SDamien Miller {
51f5399c24SDamien Miller 	int i;
52f5399c24SDamien Miller 
53f5399c24SDamien Miller 	for (i = len - 1; i >= 0; i--)
54f5399c24SDamien Miller 		if (++ctr[i])	/* continue on overflow */
55f5399c24SDamien Miller 			return;
56f5399c24SDamien Miller }
57f5399c24SDamien Miller 
58f5399c24SDamien Miller static int
ssh_aes_ctr(EVP_CIPHER_CTX * ctx,u_char * dest,const u_char * src,LIBCRYPTO_EVP_INL_TYPE len)59f5399c24SDamien Miller ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
609a3d0dc0SDamien Miller     LIBCRYPTO_EVP_INL_TYPE len)
61f5399c24SDamien Miller {
62f5399c24SDamien Miller 	struct ssh_aes_ctr_ctx *c;
639a3d0dc0SDamien Miller 	size_t n = 0;
64f5399c24SDamien Miller 	u_char buf[AES_BLOCK_SIZE];
65f5399c24SDamien Miller 
66f5399c24SDamien Miller 	if (len == 0)
67f5399c24SDamien Miller 		return (1);
68f5399c24SDamien Miller 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
69f5399c24SDamien Miller 		return (0);
70f5399c24SDamien Miller 
71f5399c24SDamien Miller 	while ((len--) > 0) {
72f5399c24SDamien Miller 		if (n == 0) {
73f5399c24SDamien Miller 			AES_encrypt(c->aes_counter, buf, &c->aes_ctx);
74f5399c24SDamien Miller 			ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE);
75f5399c24SDamien Miller 		}
76f5399c24SDamien Miller 		*(dest++) = *(src++) ^ buf[n];
77f5399c24SDamien Miller 		n = (n + 1) % AES_BLOCK_SIZE;
78f5399c24SDamien Miller 	}
79f5399c24SDamien Miller 	return (1);
80f5399c24SDamien Miller }
81f5399c24SDamien Miller 
82f5399c24SDamien Miller static int
ssh_aes_ctr_init(EVP_CIPHER_CTX * ctx,const u_char * key,const u_char * iv,int enc)83f5399c24SDamien Miller ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
84f5399c24SDamien Miller     int enc)
85f5399c24SDamien Miller {
86f5399c24SDamien Miller 	struct ssh_aes_ctr_ctx *c;
87f5399c24SDamien Miller 
88f5399c24SDamien Miller 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
89f5399c24SDamien Miller 		c = xmalloc(sizeof(*c));
90f5399c24SDamien Miller 		EVP_CIPHER_CTX_set_app_data(ctx, c);
91f5399c24SDamien Miller 	}
92f5399c24SDamien Miller 	if (key != NULL)
93fc57f71fSDarren Tucker 		AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
94fc57f71fSDarren Tucker 		    &c->aes_ctx);
95f5399c24SDamien Miller 	if (iv != NULL)
96f5399c24SDamien Miller 		memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
97f5399c24SDamien Miller 	return (1);
98f5399c24SDamien Miller }
99f5399c24SDamien Miller 
100f5399c24SDamien Miller static int
ssh_aes_ctr_cleanup(EVP_CIPHER_CTX * ctx)101f5399c24SDamien Miller ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
102f5399c24SDamien Miller {
103f5399c24SDamien Miller 	struct ssh_aes_ctr_ctx *c;
104f5399c24SDamien Miller 
105f5399c24SDamien Miller 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
106f5399c24SDamien Miller 		memset(c, 0, sizeof(*c));
107f60845fdSDarren Tucker 		free(c);
108f5399c24SDamien Miller 		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
109f5399c24SDamien Miller 	}
110f5399c24SDamien Miller 	return (1);
111f5399c24SDamien Miller }
112f5399c24SDamien Miller 
113f5399c24SDamien Miller void
ssh_aes_ctr_iv(EVP_CIPHER_CTX * evp,int doset,u_char * iv,size_t len)1149a3d0dc0SDamien Miller ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, size_t len)
115f5399c24SDamien Miller {
116f5399c24SDamien Miller 	struct ssh_aes_ctr_ctx *c;
117f5399c24SDamien Miller 
118f5399c24SDamien Miller 	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
119f5399c24SDamien Miller 		fatal("ssh_aes_ctr_iv: no context");
120f5399c24SDamien Miller 	if (doset)
121f5399c24SDamien Miller 		memcpy(c->aes_counter, iv, len);
122f5399c24SDamien Miller 	else
123f5399c24SDamien Miller 		memcpy(iv, c->aes_counter, len);
124f5399c24SDamien Miller }
125f5399c24SDamien Miller 
126f5399c24SDamien Miller const EVP_CIPHER *
evp_aes_128_ctr(void)127f5399c24SDamien Miller evp_aes_128_ctr(void)
128f5399c24SDamien Miller {
129f5399c24SDamien Miller 	static EVP_CIPHER aes_ctr;
130f5399c24SDamien Miller 
131f5399c24SDamien Miller 	memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
132f5399c24SDamien Miller 	aes_ctr.nid = NID_undef;
133f5399c24SDamien Miller 	aes_ctr.block_size = AES_BLOCK_SIZE;
134f5399c24SDamien Miller 	aes_ctr.iv_len = AES_BLOCK_SIZE;
135f5399c24SDamien Miller 	aes_ctr.key_len = 16;
136f5399c24SDamien Miller 	aes_ctr.init = ssh_aes_ctr_init;
137f5399c24SDamien Miller 	aes_ctr.cleanup = ssh_aes_ctr_cleanup;
138f5399c24SDamien Miller 	aes_ctr.do_cipher = ssh_aes_ctr;
1395c3a5584SDamien Miller #ifndef SSH_OLD_EVP
140f5399c24SDamien Miller 	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
141f5399c24SDamien Miller 	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
1425c3a5584SDamien Miller #endif
143f5399c24SDamien Miller 	return (&aes_ctr);
144f5399c24SDamien Miller }
14525a02b0cSDamien Miller 
146*72ef7c14SDamien Miller #endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR) */
147