xref: /freebsd-src/contrib/wpa/src/crypto/crypto_internal-cipher.c (revision 0bfd163f522701b486e066fa2e56624c02f5081a)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * Crypto wrapper for internal crypto implementation - Cipher wrappers
3e28a4053SRui Paulo  * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5*f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6*f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "common.h"
12e28a4053SRui Paulo #include "crypto.h"
13e28a4053SRui Paulo #include "aes.h"
14e28a4053SRui Paulo #include "des_i.h"
15e28a4053SRui Paulo 
16e28a4053SRui Paulo 
17e28a4053SRui Paulo struct crypto_cipher {
18e28a4053SRui Paulo 	enum crypto_cipher_alg alg;
19e28a4053SRui Paulo 	union {
20e28a4053SRui Paulo 		struct {
21e28a4053SRui Paulo 			size_t used_bytes;
22e28a4053SRui Paulo 			u8 key[16];
23e28a4053SRui Paulo 			size_t keylen;
24e28a4053SRui Paulo 		} rc4;
25e28a4053SRui Paulo 		struct {
26e28a4053SRui Paulo 			u8 cbc[32];
27e28a4053SRui Paulo 			void *ctx_enc;
28e28a4053SRui Paulo 			void *ctx_dec;
29e28a4053SRui Paulo 		} aes;
30e28a4053SRui Paulo 		struct {
31e28a4053SRui Paulo 			struct des3_key_s key;
32e28a4053SRui Paulo 			u8 cbc[8];
33e28a4053SRui Paulo 		} des3;
34e28a4053SRui Paulo 		struct {
35e28a4053SRui Paulo 			u32 ek[32];
36e28a4053SRui Paulo 			u32 dk[32];
37e28a4053SRui Paulo 			u8 cbc[8];
38e28a4053SRui Paulo 		} des;
39e28a4053SRui Paulo 	} u;
40e28a4053SRui Paulo };
41e28a4053SRui Paulo 
42e28a4053SRui Paulo 
crypto_cipher_init(enum crypto_cipher_alg alg,const u8 * iv,const u8 * key,size_t key_len)43e28a4053SRui Paulo struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
44e28a4053SRui Paulo 					  const u8 *iv, const u8 *key,
45e28a4053SRui Paulo 					  size_t key_len)
46e28a4053SRui Paulo {
47e28a4053SRui Paulo 	struct crypto_cipher *ctx;
48e28a4053SRui Paulo 
49e28a4053SRui Paulo 	ctx = os_zalloc(sizeof(*ctx));
50e28a4053SRui Paulo 	if (ctx == NULL)
51e28a4053SRui Paulo 		return NULL;
52e28a4053SRui Paulo 
53e28a4053SRui Paulo 	ctx->alg = alg;
54e28a4053SRui Paulo 
55e28a4053SRui Paulo 	switch (alg) {
56e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_RC4:
57e28a4053SRui Paulo 		if (key_len > sizeof(ctx->u.rc4.key)) {
58e28a4053SRui Paulo 			os_free(ctx);
59e28a4053SRui Paulo 			return NULL;
60e28a4053SRui Paulo 		}
61e28a4053SRui Paulo 		ctx->u.rc4.keylen = key_len;
62e28a4053SRui Paulo 		os_memcpy(ctx->u.rc4.key, key, key_len);
63e28a4053SRui Paulo 		break;
64e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_AES:
65e28a4053SRui Paulo 		ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
66e28a4053SRui Paulo 		if (ctx->u.aes.ctx_enc == NULL) {
67e28a4053SRui Paulo 			os_free(ctx);
68e28a4053SRui Paulo 			return NULL;
69e28a4053SRui Paulo 		}
70e28a4053SRui Paulo 		ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
71e28a4053SRui Paulo 		if (ctx->u.aes.ctx_dec == NULL) {
72e28a4053SRui Paulo 			aes_encrypt_deinit(ctx->u.aes.ctx_enc);
73e28a4053SRui Paulo 			os_free(ctx);
74e28a4053SRui Paulo 			return NULL;
75e28a4053SRui Paulo 		}
76*f05cddf9SRui Paulo 		os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
77e28a4053SRui Paulo 		break;
78e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_3DES:
79e28a4053SRui Paulo 		if (key_len != 24) {
80e28a4053SRui Paulo 			os_free(ctx);
81e28a4053SRui Paulo 			return NULL;
82e28a4053SRui Paulo 		}
83e28a4053SRui Paulo 		des3_key_setup(key, &ctx->u.des3.key);
84e28a4053SRui Paulo 		os_memcpy(ctx->u.des3.cbc, iv, 8);
85e28a4053SRui Paulo 		break;
86e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_DES:
87e28a4053SRui Paulo 		if (key_len != 8) {
88e28a4053SRui Paulo 			os_free(ctx);
89e28a4053SRui Paulo 			return NULL;
90e28a4053SRui Paulo 		}
91e28a4053SRui Paulo 		des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
92e28a4053SRui Paulo 		os_memcpy(ctx->u.des.cbc, iv, 8);
93e28a4053SRui Paulo 		break;
94e28a4053SRui Paulo 	default:
95e28a4053SRui Paulo 		os_free(ctx);
96e28a4053SRui Paulo 		return NULL;
97e28a4053SRui Paulo 	}
98e28a4053SRui Paulo 
99e28a4053SRui Paulo 	return ctx;
100e28a4053SRui Paulo }
101e28a4053SRui Paulo 
102e28a4053SRui Paulo 
crypto_cipher_encrypt(struct crypto_cipher * ctx,const u8 * plain,u8 * crypt,size_t len)103e28a4053SRui Paulo int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
104e28a4053SRui Paulo 			  u8 *crypt, size_t len)
105e28a4053SRui Paulo {
106e28a4053SRui Paulo 	size_t i, j, blocks;
107e28a4053SRui Paulo 
108e28a4053SRui Paulo 	switch (ctx->alg) {
109e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_RC4:
110e28a4053SRui Paulo 		if (plain != crypt)
111e28a4053SRui Paulo 			os_memcpy(crypt, plain, len);
112e28a4053SRui Paulo 		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
113e28a4053SRui Paulo 			 ctx->u.rc4.used_bytes, crypt, len);
114e28a4053SRui Paulo 		ctx->u.rc4.used_bytes += len;
115e28a4053SRui Paulo 		break;
116e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_AES:
117*f05cddf9SRui Paulo 		if (len % AES_BLOCK_SIZE)
118e28a4053SRui Paulo 			return -1;
119*f05cddf9SRui Paulo 		blocks = len / AES_BLOCK_SIZE;
120e28a4053SRui Paulo 		for (i = 0; i < blocks; i++) {
121*f05cddf9SRui Paulo 			for (j = 0; j < AES_BLOCK_SIZE; j++)
122e28a4053SRui Paulo 				ctx->u.aes.cbc[j] ^= plain[j];
123e28a4053SRui Paulo 			aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
124e28a4053SRui Paulo 				    ctx->u.aes.cbc);
125*f05cddf9SRui Paulo 			os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
126*f05cddf9SRui Paulo 			plain += AES_BLOCK_SIZE;
127*f05cddf9SRui Paulo 			crypt += AES_BLOCK_SIZE;
128e28a4053SRui Paulo 		}
129e28a4053SRui Paulo 		break;
130e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_3DES:
131e28a4053SRui Paulo 		if (len % 8)
132e28a4053SRui Paulo 			return -1;
133e28a4053SRui Paulo 		blocks = len / 8;
134e28a4053SRui Paulo 		for (i = 0; i < blocks; i++) {
135e28a4053SRui Paulo 			for (j = 0; j < 8; j++)
136e28a4053SRui Paulo 				ctx->u.des3.cbc[j] ^= plain[j];
137e28a4053SRui Paulo 			des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
138e28a4053SRui Paulo 				     ctx->u.des3.cbc);
139e28a4053SRui Paulo 			os_memcpy(crypt, ctx->u.des3.cbc, 8);
140e28a4053SRui Paulo 			plain += 8;
141e28a4053SRui Paulo 			crypt += 8;
142e28a4053SRui Paulo 		}
143e28a4053SRui Paulo 		break;
144e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_DES:
145e28a4053SRui Paulo 		if (len % 8)
146e28a4053SRui Paulo 			return -1;
147e28a4053SRui Paulo 		blocks = len / 8;
148e28a4053SRui Paulo 		for (i = 0; i < blocks; i++) {
149e28a4053SRui Paulo 			for (j = 0; j < 8; j++)
150e28a4053SRui Paulo 				ctx->u.des3.cbc[j] ^= plain[j];
151e28a4053SRui Paulo 			des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
152e28a4053SRui Paulo 					  ctx->u.des.cbc);
153e28a4053SRui Paulo 			os_memcpy(crypt, ctx->u.des.cbc, 8);
154e28a4053SRui Paulo 			plain += 8;
155e28a4053SRui Paulo 			crypt += 8;
156e28a4053SRui Paulo 		}
157e28a4053SRui Paulo 		break;
158e28a4053SRui Paulo 	default:
159e28a4053SRui Paulo 		return -1;
160e28a4053SRui Paulo 	}
161e28a4053SRui Paulo 
162e28a4053SRui Paulo 	return 0;
163e28a4053SRui Paulo }
164e28a4053SRui Paulo 
165e28a4053SRui Paulo 
crypto_cipher_decrypt(struct crypto_cipher * ctx,const u8 * crypt,u8 * plain,size_t len)166e28a4053SRui Paulo int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
167e28a4053SRui Paulo 			  u8 *plain, size_t len)
168e28a4053SRui Paulo {
169e28a4053SRui Paulo 	size_t i, j, blocks;
170e28a4053SRui Paulo 	u8 tmp[32];
171e28a4053SRui Paulo 
172e28a4053SRui Paulo 	switch (ctx->alg) {
173e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_RC4:
174e28a4053SRui Paulo 		if (plain != crypt)
175e28a4053SRui Paulo 			os_memcpy(plain, crypt, len);
176e28a4053SRui Paulo 		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
177e28a4053SRui Paulo 			 ctx->u.rc4.used_bytes, plain, len);
178e28a4053SRui Paulo 		ctx->u.rc4.used_bytes += len;
179e28a4053SRui Paulo 		break;
180e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_AES:
181*f05cddf9SRui Paulo 		if (len % AES_BLOCK_SIZE)
182e28a4053SRui Paulo 			return -1;
183*f05cddf9SRui Paulo 		blocks = len / AES_BLOCK_SIZE;
184e28a4053SRui Paulo 		for (i = 0; i < blocks; i++) {
185*f05cddf9SRui Paulo 			os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
186e28a4053SRui Paulo 			aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
187*f05cddf9SRui Paulo 			for (j = 0; j < AES_BLOCK_SIZE; j++)
188e28a4053SRui Paulo 				plain[j] ^= ctx->u.aes.cbc[j];
189*f05cddf9SRui Paulo 			os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
190*f05cddf9SRui Paulo 			plain += AES_BLOCK_SIZE;
191*f05cddf9SRui Paulo 			crypt += AES_BLOCK_SIZE;
192e28a4053SRui Paulo 		}
193e28a4053SRui Paulo 		break;
194e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_3DES:
195e28a4053SRui Paulo 		if (len % 8)
196e28a4053SRui Paulo 			return -1;
197e28a4053SRui Paulo 		blocks = len / 8;
198e28a4053SRui Paulo 		for (i = 0; i < blocks; i++) {
199e28a4053SRui Paulo 			os_memcpy(tmp, crypt, 8);
200e28a4053SRui Paulo 			des3_decrypt(crypt, &ctx->u.des3.key, plain);
201e28a4053SRui Paulo 			for (j = 0; j < 8; j++)
202e28a4053SRui Paulo 				plain[j] ^= ctx->u.des3.cbc[j];
203e28a4053SRui Paulo 			os_memcpy(ctx->u.des3.cbc, tmp, 8);
204e28a4053SRui Paulo 			plain += 8;
205e28a4053SRui Paulo 			crypt += 8;
206e28a4053SRui Paulo 		}
207e28a4053SRui Paulo 		break;
208e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_DES:
209e28a4053SRui Paulo 		if (len % 8)
210e28a4053SRui Paulo 			return -1;
211e28a4053SRui Paulo 		blocks = len / 8;
212e28a4053SRui Paulo 		for (i = 0; i < blocks; i++) {
213e28a4053SRui Paulo 			os_memcpy(tmp, crypt, 8);
214e28a4053SRui Paulo 			des_block_decrypt(crypt, ctx->u.des.dk, plain);
215e28a4053SRui Paulo 			for (j = 0; j < 8; j++)
216e28a4053SRui Paulo 				plain[j] ^= ctx->u.des.cbc[j];
217e28a4053SRui Paulo 			os_memcpy(ctx->u.des.cbc, tmp, 8);
218e28a4053SRui Paulo 			plain += 8;
219e28a4053SRui Paulo 			crypt += 8;
220e28a4053SRui Paulo 		}
221e28a4053SRui Paulo 		break;
222e28a4053SRui Paulo 	default:
223e28a4053SRui Paulo 		return -1;
224e28a4053SRui Paulo 	}
225e28a4053SRui Paulo 
226e28a4053SRui Paulo 	return 0;
227e28a4053SRui Paulo }
228e28a4053SRui Paulo 
229e28a4053SRui Paulo 
crypto_cipher_deinit(struct crypto_cipher * ctx)230e28a4053SRui Paulo void crypto_cipher_deinit(struct crypto_cipher *ctx)
231e28a4053SRui Paulo {
232e28a4053SRui Paulo 	switch (ctx->alg) {
233e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_AES:
234e28a4053SRui Paulo 		aes_encrypt_deinit(ctx->u.aes.ctx_enc);
235e28a4053SRui Paulo 		aes_decrypt_deinit(ctx->u.aes.ctx_dec);
236e28a4053SRui Paulo 		break;
237e28a4053SRui Paulo 	case CRYPTO_CIPHER_ALG_3DES:
238e28a4053SRui Paulo 		break;
239e28a4053SRui Paulo 	default:
240e28a4053SRui Paulo 		break;
241e28a4053SRui Paulo 	}
242e28a4053SRui Paulo 	os_free(ctx);
243e28a4053SRui Paulo }
244