Merge branch 'vendor/GCC50'
[dragonfly.git] / contrib / hostapd / 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                         void *ctx_enc;
28                         void *ctx_dec;
29                 } aes;
30                 struct {
31                         struct des3_key_s key;
32                         u8 cbc[8];
33                 } des3;
34                 struct {
35                         u32 ek[32];
36                         u32 dk[32];
37                         u8 cbc[8];
38                 } des;
39         } u;
40 };
41
42
43 struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
44                                           const u8 *iv, const u8 *key,
45                                           size_t key_len)
46 {
47         struct crypto_cipher *ctx;
48
49         ctx = os_zalloc(sizeof(*ctx));
50         if (ctx == NULL)
51                 return NULL;
52
53         ctx->alg = alg;
54
55         switch (alg) {
56         case CRYPTO_CIPHER_ALG_RC4:
57                 if (key_len > sizeof(ctx->u.rc4.key)) {
58                         os_free(ctx);
59                         return NULL;
60                 }
61                 ctx->u.rc4.keylen = key_len;
62                 os_memcpy(ctx->u.rc4.key, key, key_len);
63                 break;
64         case CRYPTO_CIPHER_ALG_AES:
65                 ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
66                 if (ctx->u.aes.ctx_enc == NULL) {
67                         os_free(ctx);
68                         return NULL;
69                 }
70                 ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
71                 if (ctx->u.aes.ctx_dec == NULL) {
72                         aes_encrypt_deinit(ctx->u.aes.ctx_enc);
73                         os_free(ctx);
74                         return NULL;
75                 }
76                 os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
77                 break;
78         case CRYPTO_CIPHER_ALG_3DES:
79                 if (key_len != 24) {
80                         os_free(ctx);
81                         return NULL;
82                 }
83                 des3_key_setup(key, &ctx->u.des3.key);
84                 os_memcpy(ctx->u.des3.cbc, iv, 8);
85                 break;
86         case CRYPTO_CIPHER_ALG_DES:
87                 if (key_len != 8) {
88                         os_free(ctx);
89                         return NULL;
90                 }
91                 des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
92                 os_memcpy(ctx->u.des.cbc, iv, 8);
93                 break;
94         default:
95                 os_free(ctx);
96                 return NULL;
97         }
98
99         return ctx;
100 }
101
102
103 int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
104                           u8 *crypt, size_t len)
105 {
106         size_t i, j, blocks;
107
108         switch (ctx->alg) {
109         case CRYPTO_CIPHER_ALG_RC4:
110                 if (plain != crypt)
111                         os_memcpy(crypt, plain, len);
112                 rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
113                          ctx->u.rc4.used_bytes, crypt, len);
114                 ctx->u.rc4.used_bytes += len;
115                 break;
116         case CRYPTO_CIPHER_ALG_AES:
117                 if (len % AES_BLOCK_SIZE)
118                         return -1;
119                 blocks = len / AES_BLOCK_SIZE;
120                 for (i = 0; i < blocks; i++) {
121                         for (j = 0; j < AES_BLOCK_SIZE; j++)
122                                 ctx->u.aes.cbc[j] ^= plain[j];
123                         aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
124                                     ctx->u.aes.cbc);
125                         os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
126                         plain += AES_BLOCK_SIZE;
127                         crypt += AES_BLOCK_SIZE;
128                 }
129                 break;
130         case CRYPTO_CIPHER_ALG_3DES:
131                 if (len % 8)
132                         return -1;
133                 blocks = len / 8;
134                 for (i = 0; i < blocks; i++) {
135                         for (j = 0; j < 8; j++)
136                                 ctx->u.des3.cbc[j] ^= plain[j];
137                         des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
138                                      ctx->u.des3.cbc);
139                         os_memcpy(crypt, ctx->u.des3.cbc, 8);
140                         plain += 8;
141                         crypt += 8;
142                 }
143                 break;
144         case CRYPTO_CIPHER_ALG_DES:
145                 if (len % 8)
146                         return -1;
147                 blocks = len / 8;
148                 for (i = 0; i < blocks; i++) {
149                         for (j = 0; j < 8; j++)
150                                 ctx->u.des3.cbc[j] ^= plain[j];
151                         des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
152                                           ctx->u.des.cbc);
153                         os_memcpy(crypt, ctx->u.des.cbc, 8);
154                         plain += 8;
155                         crypt += 8;
156                 }
157                 break;
158         default:
159                 return -1;
160         }
161
162         return 0;
163 }
164
165
166 int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
167                           u8 *plain, size_t len)
168 {
169         size_t i, j, blocks;
170         u8 tmp[32];
171
172         switch (ctx->alg) {
173         case CRYPTO_CIPHER_ALG_RC4:
174                 if (plain != crypt)
175                         os_memcpy(plain, crypt, len);
176                 rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
177                          ctx->u.rc4.used_bytes, plain, len);
178                 ctx->u.rc4.used_bytes += len;
179                 break;
180         case CRYPTO_CIPHER_ALG_AES:
181                 if (len % AES_BLOCK_SIZE)
182                         return -1;
183                 blocks = len / AES_BLOCK_SIZE;
184                 for (i = 0; i < blocks; i++) {
185                         os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
186                         aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
187                         for (j = 0; j < AES_BLOCK_SIZE; j++)
188                                 plain[j] ^= ctx->u.aes.cbc[j];
189                         os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
190                         plain += AES_BLOCK_SIZE;
191                         crypt += AES_BLOCK_SIZE;
192                 }
193                 break;
194         case CRYPTO_CIPHER_ALG_3DES:
195                 if (len % 8)
196                         return -1;
197                 blocks = len / 8;
198                 for (i = 0; i < blocks; i++) {
199                         os_memcpy(tmp, crypt, 8);
200                         des3_decrypt(crypt, &ctx->u.des3.key, plain);
201                         for (j = 0; j < 8; j++)
202                                 plain[j] ^= ctx->u.des3.cbc[j];
203                         os_memcpy(ctx->u.des3.cbc, tmp, 8);
204                         plain += 8;
205                         crypt += 8;
206                 }
207                 break;
208         case CRYPTO_CIPHER_ALG_DES:
209                 if (len % 8)
210                         return -1;
211                 blocks = len / 8;
212                 for (i = 0; i < blocks; i++) {
213                         os_memcpy(tmp, crypt, 8);
214                         des_block_decrypt(crypt, ctx->u.des.dk, plain);
215                         for (j = 0; j < 8; j++)
216                                 plain[j] ^= ctx->u.des.cbc[j];
217                         os_memcpy(ctx->u.des.cbc, tmp, 8);
218                         plain += 8;
219                         crypt += 8;
220                 }
221                 break;
222         default:
223                 return -1;
224         }
225
226         return 0;
227 }
228
229
230 void crypto_cipher_deinit(struct crypto_cipher *ctx)
231 {
232         switch (ctx->alg) {
233         case CRYPTO_CIPHER_ALG_AES:
234                 aes_encrypt_deinit(ctx->u.aes.ctx_enc);
235                 aes_decrypt_deinit(ctx->u.aes.ctx_dec);
236                 break;
237         case CRYPTO_CIPHER_ALG_3DES:
238                 break;
239         default:
240                 break;
241         }
242         os_free(ctx);
243 }