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