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