1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
5*0Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
6*0Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
7*0Sstevel@tonic-gate  *
8*0Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*0Sstevel@tonic-gate  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*0Sstevel@tonic-gate  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*0Sstevel@tonic-gate  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*0Sstevel@tonic-gate  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*0Sstevel@tonic-gate  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*0Sstevel@tonic-gate  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*0Sstevel@tonic-gate  */
16*0Sstevel@tonic-gate /*
17*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
18*0Sstevel@tonic-gate  * Use is subject to license terms.
19*0Sstevel@tonic-gate  */
20*0Sstevel@tonic-gate #include "includes.h"
21*0Sstevel@tonic-gate RCSID("$OpenBSD: cipher-ctr.c,v 1.4 2004/02/06 23:41:13 dtucker Exp $");
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate #include <openssl/evp.h>
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #include "log.h"
28*0Sstevel@tonic-gate #include "xmalloc.h"
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #if OPENSSL_VERSION_NUMBER < 0x00906000L
31*0Sstevel@tonic-gate #define SSH_OLD_EVP
32*0Sstevel@tonic-gate #endif
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #if (OPENSSL_VERSION_NUMBER < 0x00907000L)
35*0Sstevel@tonic-gate #include "rijndael.h"
36*0Sstevel@tonic-gate #define AES_KEY rijndael_ctx
37*0Sstevel@tonic-gate #define AES_BLOCK_SIZE 16
38*0Sstevel@tonic-gate #define AES_encrypt(a, b, c) rijndael_encrypt(c, a, b)
39*0Sstevel@tonic-gate #define AES_set_encrypt_key(a, b, c) rijndael_set_key(c, (u_char *)a, b, 1)
40*0Sstevel@tonic-gate #else
41*0Sstevel@tonic-gate #include <openssl/aes.h>
42*0Sstevel@tonic-gate #endif
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate const EVP_CIPHER *evp_aes_128_ctr(void);
45*0Sstevel@tonic-gate void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate struct ssh_aes_ctr_ctx
48*0Sstevel@tonic-gate {
49*0Sstevel@tonic-gate 	AES_KEY		aes_ctx;
50*0Sstevel@tonic-gate 	u_char		aes_counter[AES_BLOCK_SIZE];
51*0Sstevel@tonic-gate };
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate /*
54*0Sstevel@tonic-gate  * increment counter 'ctr',
55*0Sstevel@tonic-gate  * the counter is of size 'len' bytes and stored in network-byte-order.
56*0Sstevel@tonic-gate  * (LSB at ctr[len-1], MSB at ctr[0])
57*0Sstevel@tonic-gate  */
58*0Sstevel@tonic-gate static void
59*0Sstevel@tonic-gate ssh_ctr_inc(u_char *ctr, u_int len)
60*0Sstevel@tonic-gate {
61*0Sstevel@tonic-gate 	int i;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate 	for (i = len - 1; i >= 0; i--)
64*0Sstevel@tonic-gate 		if (++ctr[i])	/* continue on overflow */
65*0Sstevel@tonic-gate 			return;
66*0Sstevel@tonic-gate }
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate static int
69*0Sstevel@tonic-gate ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
70*0Sstevel@tonic-gate     u_int len)
71*0Sstevel@tonic-gate {
72*0Sstevel@tonic-gate 	struct ssh_aes_ctr_ctx *c;
73*0Sstevel@tonic-gate 	u_int n = 0;
74*0Sstevel@tonic-gate 	u_char buf[AES_BLOCK_SIZE];
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	if (len == 0)
77*0Sstevel@tonic-gate 		return (1);
78*0Sstevel@tonic-gate 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
79*0Sstevel@tonic-gate 		return (0);
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	while ((len--) > 0) {
82*0Sstevel@tonic-gate 		if (n == 0) {
83*0Sstevel@tonic-gate 			AES_encrypt(c->aes_counter, buf, &c->aes_ctx);
84*0Sstevel@tonic-gate 			ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE);
85*0Sstevel@tonic-gate 		}
86*0Sstevel@tonic-gate 		*(dest++) = *(src++) ^ buf[n];
87*0Sstevel@tonic-gate 		n = (n + 1) % AES_BLOCK_SIZE;
88*0Sstevel@tonic-gate 	}
89*0Sstevel@tonic-gate 	return (1);
90*0Sstevel@tonic-gate }
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate static int
93*0Sstevel@tonic-gate ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
94*0Sstevel@tonic-gate     int enc)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	struct ssh_aes_ctr_ctx *c;
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
99*0Sstevel@tonic-gate 		c = xmalloc(sizeof(*c));
100*0Sstevel@tonic-gate 		EVP_CIPHER_CTX_set_app_data(ctx, c);
101*0Sstevel@tonic-gate 	}
102*0Sstevel@tonic-gate 	if (key != NULL)
103*0Sstevel@tonic-gate 		AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
104*0Sstevel@tonic-gate 		     &c->aes_ctx);
105*0Sstevel@tonic-gate 	if (iv != NULL)
106*0Sstevel@tonic-gate 		memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
107*0Sstevel@tonic-gate 	return (1);
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate static int
111*0Sstevel@tonic-gate ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	struct ssh_aes_ctr_ctx *c;
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
116*0Sstevel@tonic-gate 		memset(c, 0, sizeof(*c));
117*0Sstevel@tonic-gate 		xfree(c);
118*0Sstevel@tonic-gate 		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
119*0Sstevel@tonic-gate 	}
120*0Sstevel@tonic-gate 	return (1);
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate void
124*0Sstevel@tonic-gate ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len)
125*0Sstevel@tonic-gate {
126*0Sstevel@tonic-gate 	struct ssh_aes_ctr_ctx *c;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
129*0Sstevel@tonic-gate 		fatal("ssh_aes_ctr_iv: no context");
130*0Sstevel@tonic-gate 	if (doset)
131*0Sstevel@tonic-gate 		memcpy(c->aes_counter, iv, len);
132*0Sstevel@tonic-gate 	else
133*0Sstevel@tonic-gate 		memcpy(iv, c->aes_counter, len);
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate const EVP_CIPHER *
137*0Sstevel@tonic-gate evp_aes_128_ctr(void)
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	static EVP_CIPHER aes_ctr;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
142*0Sstevel@tonic-gate 	aes_ctr.nid = NID_undef;
143*0Sstevel@tonic-gate 	aes_ctr.block_size = AES_BLOCK_SIZE;
144*0Sstevel@tonic-gate 	aes_ctr.iv_len = AES_BLOCK_SIZE;
145*0Sstevel@tonic-gate 	aes_ctr.key_len = 16;
146*0Sstevel@tonic-gate 	aes_ctr.init = ssh_aes_ctr_init;
147*0Sstevel@tonic-gate 	aes_ctr.cleanup = ssh_aes_ctr_cleanup;
148*0Sstevel@tonic-gate 	aes_ctr.do_cipher = ssh_aes_ctr;
149*0Sstevel@tonic-gate #ifndef SSH_OLD_EVP
150*0Sstevel@tonic-gate 	aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
151*0Sstevel@tonic-gate 	    EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
152*0Sstevel@tonic-gate #endif
153*0Sstevel@tonic-gate 	return (&aes_ctr);
154*0Sstevel@tonic-gate }
155