1214501Srpaulo/*
2214501Srpaulo * Crypto wrapper for internal crypto implementation - Cipher wrappers
3214501Srpaulo * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo
11214501Srpaulo#include "common.h"
12214501Srpaulo#include "crypto.h"
13214501Srpaulo#include "aes.h"
14214501Srpaulo#include "des_i.h"
15214501Srpaulo
16214501Srpaulo
17214501Srpaulostruct crypto_cipher {
18214501Srpaulo	enum crypto_cipher_alg alg;
19214501Srpaulo	union {
20214501Srpaulo		struct {
21214501Srpaulo			size_t used_bytes;
22214501Srpaulo			u8 key[16];
23214501Srpaulo			size_t keylen;
24214501Srpaulo		} rc4;
25214501Srpaulo		struct {
26214501Srpaulo			u8 cbc[32];
27214501Srpaulo			void *ctx_enc;
28214501Srpaulo			void *ctx_dec;
29214501Srpaulo		} aes;
30214501Srpaulo		struct {
31214501Srpaulo			struct des3_key_s key;
32214501Srpaulo			u8 cbc[8];
33214501Srpaulo		} des3;
34214501Srpaulo		struct {
35214501Srpaulo			u32 ek[32];
36214501Srpaulo			u32 dk[32];
37214501Srpaulo			u8 cbc[8];
38214501Srpaulo		} des;
39214501Srpaulo	} u;
40214501Srpaulo};
41214501Srpaulo
42214501Srpaulo
43214501Srpaulostruct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
44214501Srpaulo					  const u8 *iv, const u8 *key,
45214501Srpaulo					  size_t key_len)
46214501Srpaulo{
47214501Srpaulo	struct crypto_cipher *ctx;
48214501Srpaulo
49214501Srpaulo	ctx = os_zalloc(sizeof(*ctx));
50214501Srpaulo	if (ctx == NULL)
51214501Srpaulo		return NULL;
52214501Srpaulo
53214501Srpaulo	ctx->alg = alg;
54214501Srpaulo
55214501Srpaulo	switch (alg) {
56214501Srpaulo	case CRYPTO_CIPHER_ALG_RC4:
57214501Srpaulo		if (key_len > sizeof(ctx->u.rc4.key)) {
58214501Srpaulo			os_free(ctx);
59214501Srpaulo			return NULL;
60214501Srpaulo		}
61214501Srpaulo		ctx->u.rc4.keylen = key_len;
62214501Srpaulo		os_memcpy(ctx->u.rc4.key, key, key_len);
63214501Srpaulo		break;
64214501Srpaulo	case CRYPTO_CIPHER_ALG_AES:
65214501Srpaulo		ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
66214501Srpaulo		if (ctx->u.aes.ctx_enc == NULL) {
67214501Srpaulo			os_free(ctx);
68214501Srpaulo			return NULL;
69214501Srpaulo		}
70214501Srpaulo		ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
71214501Srpaulo		if (ctx->u.aes.ctx_dec == NULL) {
72214501Srpaulo			aes_encrypt_deinit(ctx->u.aes.ctx_enc);
73214501Srpaulo			os_free(ctx);
74214501Srpaulo			return NULL;
75214501Srpaulo		}
76252726Srpaulo		os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
77214501Srpaulo		break;
78214501Srpaulo	case CRYPTO_CIPHER_ALG_3DES:
79214501Srpaulo		if (key_len != 24) {
80214501Srpaulo			os_free(ctx);
81214501Srpaulo			return NULL;
82214501Srpaulo		}
83214501Srpaulo		des3_key_setup(key, &ctx->u.des3.key);
84214501Srpaulo		os_memcpy(ctx->u.des3.cbc, iv, 8);
85214501Srpaulo		break;
86214501Srpaulo	case CRYPTO_CIPHER_ALG_DES:
87214501Srpaulo		if (key_len != 8) {
88214501Srpaulo			os_free(ctx);
89214501Srpaulo			return NULL;
90214501Srpaulo		}
91214501Srpaulo		des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
92214501Srpaulo		os_memcpy(ctx->u.des.cbc, iv, 8);
93214501Srpaulo		break;
94214501Srpaulo	default:
95214501Srpaulo		os_free(ctx);
96214501Srpaulo		return NULL;
97214501Srpaulo	}
98214501Srpaulo
99214501Srpaulo	return ctx;
100214501Srpaulo}
101214501Srpaulo
102214501Srpaulo
103214501Srpauloint crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
104214501Srpaulo			  u8 *crypt, size_t len)
105214501Srpaulo{
106214501Srpaulo	size_t i, j, blocks;
107214501Srpaulo
108214501Srpaulo	switch (ctx->alg) {
109214501Srpaulo	case CRYPTO_CIPHER_ALG_RC4:
110214501Srpaulo		if (plain != crypt)
111214501Srpaulo			os_memcpy(crypt, plain, len);
112214501Srpaulo		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
113214501Srpaulo			 ctx->u.rc4.used_bytes, crypt, len);
114214501Srpaulo		ctx->u.rc4.used_bytes += len;
115214501Srpaulo		break;
116214501Srpaulo	case CRYPTO_CIPHER_ALG_AES:
117252726Srpaulo		if (len % AES_BLOCK_SIZE)
118214501Srpaulo			return -1;
119252726Srpaulo		blocks = len / AES_BLOCK_SIZE;
120214501Srpaulo		for (i = 0; i < blocks; i++) {
121252726Srpaulo			for (j = 0; j < AES_BLOCK_SIZE; j++)
122214501Srpaulo				ctx->u.aes.cbc[j] ^= plain[j];
123214501Srpaulo			aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
124214501Srpaulo				    ctx->u.aes.cbc);
125252726Srpaulo			os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
126252726Srpaulo			plain += AES_BLOCK_SIZE;
127252726Srpaulo			crypt += AES_BLOCK_SIZE;
128214501Srpaulo		}
129214501Srpaulo		break;
130214501Srpaulo	case CRYPTO_CIPHER_ALG_3DES:
131214501Srpaulo		if (len % 8)
132214501Srpaulo			return -1;
133214501Srpaulo		blocks = len / 8;
134214501Srpaulo		for (i = 0; i < blocks; i++) {
135214501Srpaulo			for (j = 0; j < 8; j++)
136214501Srpaulo				ctx->u.des3.cbc[j] ^= plain[j];
137214501Srpaulo			des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
138214501Srpaulo				     ctx->u.des3.cbc);
139214501Srpaulo			os_memcpy(crypt, ctx->u.des3.cbc, 8);
140214501Srpaulo			plain += 8;
141214501Srpaulo			crypt += 8;
142214501Srpaulo		}
143214501Srpaulo		break;
144214501Srpaulo	case CRYPTO_CIPHER_ALG_DES:
145214501Srpaulo		if (len % 8)
146214501Srpaulo			return -1;
147214501Srpaulo		blocks = len / 8;
148214501Srpaulo		for (i = 0; i < blocks; i++) {
149214501Srpaulo			for (j = 0; j < 8; j++)
150214501Srpaulo				ctx->u.des3.cbc[j] ^= plain[j];
151214501Srpaulo			des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
152214501Srpaulo					  ctx->u.des.cbc);
153214501Srpaulo			os_memcpy(crypt, ctx->u.des.cbc, 8);
154214501Srpaulo			plain += 8;
155214501Srpaulo			crypt += 8;
156214501Srpaulo		}
157214501Srpaulo		break;
158214501Srpaulo	default:
159214501Srpaulo		return -1;
160214501Srpaulo	}
161214501Srpaulo
162214501Srpaulo	return 0;
163214501Srpaulo}
164214501Srpaulo
165214501Srpaulo
166214501Srpauloint crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
167214501Srpaulo			  u8 *plain, size_t len)
168214501Srpaulo{
169214501Srpaulo	size_t i, j, blocks;
170214501Srpaulo	u8 tmp[32];
171214501Srpaulo
172214501Srpaulo	switch (ctx->alg) {
173214501Srpaulo	case CRYPTO_CIPHER_ALG_RC4:
174214501Srpaulo		if (plain != crypt)
175214501Srpaulo			os_memcpy(plain, crypt, len);
176214501Srpaulo		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
177214501Srpaulo			 ctx->u.rc4.used_bytes, plain, len);
178214501Srpaulo		ctx->u.rc4.used_bytes += len;
179214501Srpaulo		break;
180214501Srpaulo	case CRYPTO_CIPHER_ALG_AES:
181252726Srpaulo		if (len % AES_BLOCK_SIZE)
182214501Srpaulo			return -1;
183252726Srpaulo		blocks = len / AES_BLOCK_SIZE;
184214501Srpaulo		for (i = 0; i < blocks; i++) {
185252726Srpaulo			os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
186214501Srpaulo			aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
187252726Srpaulo			for (j = 0; j < AES_BLOCK_SIZE; j++)
188214501Srpaulo				plain[j] ^= ctx->u.aes.cbc[j];
189252726Srpaulo			os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
190252726Srpaulo			plain += AES_BLOCK_SIZE;
191252726Srpaulo			crypt += AES_BLOCK_SIZE;
192214501Srpaulo		}
193214501Srpaulo		break;
194214501Srpaulo	case CRYPTO_CIPHER_ALG_3DES:
195214501Srpaulo		if (len % 8)
196214501Srpaulo			return -1;
197214501Srpaulo		blocks = len / 8;
198214501Srpaulo		for (i = 0; i < blocks; i++) {
199214501Srpaulo			os_memcpy(tmp, crypt, 8);
200214501Srpaulo			des3_decrypt(crypt, &ctx->u.des3.key, plain);
201214501Srpaulo			for (j = 0; j < 8; j++)
202214501Srpaulo				plain[j] ^= ctx->u.des3.cbc[j];
203214501Srpaulo			os_memcpy(ctx->u.des3.cbc, tmp, 8);
204214501Srpaulo			plain += 8;
205214501Srpaulo			crypt += 8;
206214501Srpaulo		}
207214501Srpaulo		break;
208214501Srpaulo	case CRYPTO_CIPHER_ALG_DES:
209214501Srpaulo		if (len % 8)
210214501Srpaulo			return -1;
211214501Srpaulo		blocks = len / 8;
212214501Srpaulo		for (i = 0; i < blocks; i++) {
213214501Srpaulo			os_memcpy(tmp, crypt, 8);
214214501Srpaulo			des_block_decrypt(crypt, ctx->u.des.dk, plain);
215214501Srpaulo			for (j = 0; j < 8; j++)
216214501Srpaulo				plain[j] ^= ctx->u.des.cbc[j];
217214501Srpaulo			os_memcpy(ctx->u.des.cbc, tmp, 8);
218214501Srpaulo			plain += 8;
219214501Srpaulo			crypt += 8;
220214501Srpaulo		}
221214501Srpaulo		break;
222214501Srpaulo	default:
223214501Srpaulo		return -1;
224214501Srpaulo	}
225214501Srpaulo
226214501Srpaulo	return 0;
227214501Srpaulo}
228214501Srpaulo
229214501Srpaulo
230214501Srpaulovoid crypto_cipher_deinit(struct crypto_cipher *ctx)
231214501Srpaulo{
232214501Srpaulo	switch (ctx->alg) {
233214501Srpaulo	case CRYPTO_CIPHER_ALG_AES:
234214501Srpaulo		aes_encrypt_deinit(ctx->u.aes.ctx_enc);
235214501Srpaulo		aes_decrypt_deinit(ctx->u.aes.ctx_dec);
236214501Srpaulo		break;
237214501Srpaulo	case CRYPTO_CIPHER_ALG_3DES:
238214501Srpaulo		break;
239214501Srpaulo	default:
240214501Srpaulo		break;
241214501Srpaulo	}
242214501Srpaulo	os_free(ctx);
243214501Srpaulo}
244