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