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