10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any
50Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above
60Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
90Sstevel@tonic-gate * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
100Sstevel@tonic-gate * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
110Sstevel@tonic-gate * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
120Sstevel@tonic-gate * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
130Sstevel@tonic-gate * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
140Sstevel@tonic-gate * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
150Sstevel@tonic-gate */
160Sstevel@tonic-gate /*
17*7574SJan.Pechanec@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
180Sstevel@tonic-gate * Use is subject to license terms.
190Sstevel@tonic-gate */
20*7574SJan.Pechanec@Sun.COM
210Sstevel@tonic-gate #include "includes.h"
220Sstevel@tonic-gate RCSID("$OpenBSD: cipher-ctr.c,v 1.4 2004/02/06 23:41:13 dtucker Exp $");
230Sstevel@tonic-gate
240Sstevel@tonic-gate #include <openssl/evp.h>
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include "log.h"
270Sstevel@tonic-gate #include "xmalloc.h"
280Sstevel@tonic-gate #include <openssl/aes.h>
290Sstevel@tonic-gate
300Sstevel@tonic-gate const EVP_CIPHER *evp_aes_128_ctr(void);
310Sstevel@tonic-gate void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
320Sstevel@tonic-gate
330Sstevel@tonic-gate struct ssh_aes_ctr_ctx
340Sstevel@tonic-gate {
350Sstevel@tonic-gate AES_KEY aes_ctx;
360Sstevel@tonic-gate u_char aes_counter[AES_BLOCK_SIZE];
370Sstevel@tonic-gate };
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate * increment counter 'ctr',
410Sstevel@tonic-gate * the counter is of size 'len' bytes and stored in network-byte-order.
420Sstevel@tonic-gate * (LSB at ctr[len-1], MSB at ctr[0])
430Sstevel@tonic-gate */
440Sstevel@tonic-gate static void
ssh_ctr_inc(u_char * ctr,u_int len)450Sstevel@tonic-gate ssh_ctr_inc(u_char *ctr, u_int len)
460Sstevel@tonic-gate {
470Sstevel@tonic-gate int i;
480Sstevel@tonic-gate
490Sstevel@tonic-gate for (i = len - 1; i >= 0; i--)
500Sstevel@tonic-gate if (++ctr[i]) /* continue on overflow */
510Sstevel@tonic-gate return;
520Sstevel@tonic-gate }
530Sstevel@tonic-gate
540Sstevel@tonic-gate static int
ssh_aes_ctr(EVP_CIPHER_CTX * ctx,u_char * dest,const u_char * src,u_int len)550Sstevel@tonic-gate ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
560Sstevel@tonic-gate u_int len)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate struct ssh_aes_ctr_ctx *c;
590Sstevel@tonic-gate u_int n = 0;
600Sstevel@tonic-gate u_char buf[AES_BLOCK_SIZE];
610Sstevel@tonic-gate
620Sstevel@tonic-gate if (len == 0)
630Sstevel@tonic-gate return (1);
640Sstevel@tonic-gate if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
650Sstevel@tonic-gate return (0);
660Sstevel@tonic-gate
670Sstevel@tonic-gate while ((len--) > 0) {
680Sstevel@tonic-gate if (n == 0) {
690Sstevel@tonic-gate AES_encrypt(c->aes_counter, buf, &c->aes_ctx);
700Sstevel@tonic-gate ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate *(dest++) = *(src++) ^ buf[n];
730Sstevel@tonic-gate n = (n + 1) % AES_BLOCK_SIZE;
740Sstevel@tonic-gate }
750Sstevel@tonic-gate return (1);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate
780Sstevel@tonic-gate static int
ssh_aes_ctr_init(EVP_CIPHER_CTX * ctx,const u_char * key,const u_char * iv,int enc)790Sstevel@tonic-gate ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
800Sstevel@tonic-gate int enc)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate struct ssh_aes_ctr_ctx *c;
830Sstevel@tonic-gate
840Sstevel@tonic-gate if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
850Sstevel@tonic-gate c = xmalloc(sizeof(*c));
860Sstevel@tonic-gate EVP_CIPHER_CTX_set_app_data(ctx, c);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate if (key != NULL)
890Sstevel@tonic-gate AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
900Sstevel@tonic-gate &c->aes_ctx);
910Sstevel@tonic-gate if (iv != NULL)
920Sstevel@tonic-gate memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
930Sstevel@tonic-gate return (1);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate
960Sstevel@tonic-gate static int
ssh_aes_ctr_cleanup(EVP_CIPHER_CTX * ctx)970Sstevel@tonic-gate ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate struct ssh_aes_ctr_ctx *c;
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
1020Sstevel@tonic-gate memset(c, 0, sizeof(*c));
1030Sstevel@tonic-gate xfree(c);
1040Sstevel@tonic-gate EVP_CIPHER_CTX_set_app_data(ctx, NULL);
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate return (1);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate void
ssh_aes_ctr_iv(EVP_CIPHER_CTX * evp,int doset,u_char * iv,u_int len)1100Sstevel@tonic-gate ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate struct ssh_aes_ctr_ctx *c;
1130Sstevel@tonic-gate
1140Sstevel@tonic-gate if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
1150Sstevel@tonic-gate fatal("ssh_aes_ctr_iv: no context");
1160Sstevel@tonic-gate if (doset)
1170Sstevel@tonic-gate memcpy(c->aes_counter, iv, len);
1180Sstevel@tonic-gate else
1190Sstevel@tonic-gate memcpy(iv, c->aes_counter, len);
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate
122*7574SJan.Pechanec@Sun.COM /*
123*7574SJan.Pechanec@Sun.COM * Function fills an EVP_CIPHER structure for AES CTR functions based on the NID
124*7574SJan.Pechanec@Sun.COM * and the key length.
125*7574SJan.Pechanec@Sun.COM */
126*7574SJan.Pechanec@Sun.COM static const EVP_CIPHER *
evp_aes_ctr(const char * nid,int key_len,EVP_CIPHER * aes_ctr)127*7574SJan.Pechanec@Sun.COM evp_aes_ctr(const char *nid, int key_len, EVP_CIPHER *aes_ctr)
128*7574SJan.Pechanec@Sun.COM {
129*7574SJan.Pechanec@Sun.COM memset(aes_ctr, 0, sizeof(EVP_CIPHER));
130*7574SJan.Pechanec@Sun.COM /*
131*7574SJan.Pechanec@Sun.COM * If the PKCS#11 engine is used the AES CTR NIDs were dynamically
132*7574SJan.Pechanec@Sun.COM * created during the engine initialization. If the engine is not used
133*7574SJan.Pechanec@Sun.COM * we work with NID_undef's which is OK since in that case OpenSSL
134*7574SJan.Pechanec@Sun.COM * doesn't use NIDs at all.
135*7574SJan.Pechanec@Sun.COM */
136*7574SJan.Pechanec@Sun.COM if ((aes_ctr->nid = OBJ_ln2nid(nid)) != NID_undef)
137*7574SJan.Pechanec@Sun.COM debug3("%s NID found", nid);
138*7574SJan.Pechanec@Sun.COM
139*7574SJan.Pechanec@Sun.COM aes_ctr->block_size = AES_BLOCK_SIZE;
140*7574SJan.Pechanec@Sun.COM aes_ctr->iv_len = AES_BLOCK_SIZE;
141*7574SJan.Pechanec@Sun.COM aes_ctr->key_len = key_len;
142*7574SJan.Pechanec@Sun.COM aes_ctr->init = ssh_aes_ctr_init;
143*7574SJan.Pechanec@Sun.COM aes_ctr->cleanup = ssh_aes_ctr_cleanup;
144*7574SJan.Pechanec@Sun.COM aes_ctr->do_cipher = ssh_aes_ctr;
145*7574SJan.Pechanec@Sun.COM aes_ctr->flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
146*7574SJan.Pechanec@Sun.COM EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
147*7574SJan.Pechanec@Sun.COM return (aes_ctr);
148*7574SJan.Pechanec@Sun.COM }
149*7574SJan.Pechanec@Sun.COM
1500Sstevel@tonic-gate const EVP_CIPHER *
evp_aes_128_ctr(void)1510Sstevel@tonic-gate evp_aes_128_ctr(void)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate static EVP_CIPHER aes_ctr;
1540Sstevel@tonic-gate
155*7574SJan.Pechanec@Sun.COM return (evp_aes_ctr("aes-128-ctr", 16, &aes_ctr));
1560Sstevel@tonic-gate }
157*7574SJan.Pechanec@Sun.COM
158*7574SJan.Pechanec@Sun.COM const EVP_CIPHER *
evp_aes_192_ctr(void)159*7574SJan.Pechanec@Sun.COM evp_aes_192_ctr(void)
160*7574SJan.Pechanec@Sun.COM {
161*7574SJan.Pechanec@Sun.COM static EVP_CIPHER aes_ctr;
162*7574SJan.Pechanec@Sun.COM
163*7574SJan.Pechanec@Sun.COM return (evp_aes_ctr("aes-192-ctr", 24, &aes_ctr));
164*7574SJan.Pechanec@Sun.COM }
165*7574SJan.Pechanec@Sun.COM
166*7574SJan.Pechanec@Sun.COM const EVP_CIPHER *
evp_aes_256_ctr(void)167*7574SJan.Pechanec@Sun.COM evp_aes_256_ctr(void)
168*7574SJan.Pechanec@Sun.COM {
169*7574SJan.Pechanec@Sun.COM static EVP_CIPHER aes_ctr;
170*7574SJan.Pechanec@Sun.COM
171*7574SJan.Pechanec@Sun.COM return (evp_aes_ctr("aes-256-ctr", 32, &aes_ctr));
172*7574SJan.Pechanec@Sun.COM }
173