1 /*
2 * Copyright (c) 2014-2018, Andrew Romanenko <melanhit@gmail.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <string.h>
32
33 #include "akmos.h"
34 #include "error.h"
35 #include "cipher.h"
36 #include "pxor.h"
37
38 #include "mask.h"
39
cipher_init_mode(akmos_cipher_t ctx,akmos_mode_id mode)40 static int cipher_init_mode(akmos_cipher_t ctx, akmos_mode_id mode)
41 {
42 switch(mode & AKMOS_MODE_CIPHER_MASK) {
43 case AKMOS_MODE_ECB:
44 ctx->xmode = &akmos_xmode_ecb;
45 break;
46
47 case AKMOS_MODE_CBC:
48 ctx->xmode = &akmos_xmode_cbc;
49 break;
50
51 case AKMOS_MODE_OFB:
52 ctx->xmode = &akmos_xmode_ofb;
53 break;
54
55 case AKMOS_MODE_CTR:
56 ctx->xmode = &akmos_xmode_ctr;
57 break;
58
59 case AKMOS_MODE_CFB:
60 ctx->xmode = &akmos_xmode_cfb;
61 break;
62
63 case AKMOS_MODE_CFB1:
64 ctx->xmode = &akmos_xmode_cfb1;
65 break;
66
67 default:
68 return AKMOS_ERR_MODEID;
69 }
70
71 switch(mode & AKMOS_MODE_FLAG_MASK) {
72 case AKMOS_MODE_ENCRYPT:
73 ctx->crypt = ctx->xmode->encrypt;
74 break;
75
76 case AKMOS_MODE_DECRYPT:
77 ctx->crypt = ctx->xmode->decrypt;
78 break;
79
80 default:
81 return AKMOS_ERR_MODEID;
82 }
83
84 return AKMOS_ERR_SUCCESS;
85 }
86
cipher_init_stream(akmos_cipher_t ctx)87 static void cipher_init_stream(akmos_cipher_t ctx)
88 {
89 ctx->xmode = &akmos_xmode_ctr;
90 ctx->crypt = &akmos_ctr_stream;
91 }
92
cipher_setkey(akmos_cipher_t ctx,const uint8_t * key,size_t len)93 static void cipher_setkey(akmos_cipher_t ctx, const uint8_t *key, size_t len)
94 {
95 ctx->xalgo->setkey(&ctx->actx[0], key, len);
96 }
97
cipher_encrypt(akmos_cipher_t ctx,const uint8_t * in_blk,uint8_t * out_blk)98 static void cipher_encrypt(akmos_cipher_t ctx, const uint8_t *in_blk, uint8_t *out_blk)
99 {
100 ctx->xalgo->encrypt(&ctx->actx[0], in_blk, out_blk);
101 }
102
cipher_decrypt(akmos_cipher_t ctx,const uint8_t * in_blk,uint8_t * out_blk)103 static void cipher_decrypt(akmos_cipher_t ctx, const uint8_t *in_blk, uint8_t *out_blk)
104 {
105 ctx->xalgo->decrypt(&ctx->actx[0], in_blk, out_blk);
106 }
107
cipher_tde_setkey(akmos_cipher_t ctx,const uint8_t * key,size_t len)108 static void cipher_tde_setkey(akmos_cipher_t ctx, const uint8_t *key, size_t len)
109 {
110 ctx->xalgo->setkey(&ctx->actx[0], key, len);
111 ctx->xalgo->setkey(&ctx->actx[1], key + len, len);
112 ctx->xalgo->setkey(&ctx->actx[2], key + len * 2, len);
113 }
114
cipher_ede_encrypt(akmos_cipher_t ctx,const uint8_t * in_blk,uint8_t * out_blk)115 static void cipher_ede_encrypt(akmos_cipher_t ctx, const uint8_t *in_blk, uint8_t *out_blk)
116 {
117 ctx->xalgo->encrypt(&ctx->actx[0], in_blk, out_blk);
118 ctx->xalgo->decrypt(&ctx->actx[1], out_blk, out_blk);
119 ctx->xalgo->encrypt(&ctx->actx[2], out_blk, out_blk);
120 }
121
cipher_ede_decrypt(akmos_cipher_t ctx,const uint8_t * in_blk,uint8_t * out_blk)122 static void cipher_ede_decrypt(akmos_cipher_t ctx, const uint8_t *in_blk, uint8_t *out_blk)
123 {
124 ctx->xalgo->decrypt(&ctx->actx[2], in_blk, out_blk);
125 ctx->xalgo->encrypt(&ctx->actx[1], out_blk, out_blk);
126 ctx->xalgo->decrypt(&ctx->actx[0], out_blk, out_blk);
127 }
128
cipher_eee_encrypt(akmos_cipher_t ctx,const uint8_t * in_blk,uint8_t * out_blk)129 static void cipher_eee_encrypt(akmos_cipher_t ctx, const uint8_t *in_blk, uint8_t *out_blk)
130 {
131 ctx->xalgo->encrypt(&ctx->actx[0], in_blk, out_blk);
132 ctx->xalgo->encrypt(&ctx->actx[1], out_blk, out_blk);
133 ctx->xalgo->encrypt(&ctx->actx[2], out_blk, out_blk);
134 }
135
cipher_eee_decrypt(akmos_cipher_t ctx,const uint8_t * in_blk,uint8_t * out_blk)136 static void cipher_eee_decrypt(akmos_cipher_t ctx, const uint8_t *in_blk, uint8_t *out_blk)
137 {
138 ctx->xalgo->decrypt(&ctx->actx[2], in_blk, out_blk);
139 ctx->xalgo->decrypt(&ctx->actx[1], out_blk, out_blk);
140 ctx->xalgo->decrypt(&ctx->actx[0], out_blk, out_blk);
141 }
142
cipher_init_tde(akmos_cipher_t ctx,akmos_algo_id algo)143 static int cipher_init_tde(akmos_cipher_t ctx, akmos_algo_id algo)
144 {
145 if((algo & AKMOS_ALGO_STMCIPH_MASK))
146 return AKMOS_ERR_STMTDEA;
147
148 switch(algo & AKMOS_ALGO_FLAG_MASK) {
149 case AKMOS_ALGO_FLAG_EDE:
150 ctx->setkey = &cipher_tde_setkey;
151 ctx->encrypt = &cipher_ede_encrypt;
152 ctx->decrypt = &cipher_ede_decrypt;
153 break;
154
155 case AKMOS_ALGO_FLAG_EEE:
156 ctx->setkey = &cipher_tde_setkey;
157 ctx->encrypt = &cipher_eee_encrypt;
158 ctx->decrypt = &cipher_eee_decrypt;
159 break;
160
161 default:
162 ctx->setkey = &cipher_setkey;
163 ctx->encrypt = &cipher_encrypt;
164 ctx->decrypt = &cipher_decrypt;
165 break;
166 }
167
168 return AKMOS_ERR_SUCCESS;
169 }
170
cipher_init_pxor(akmos_cipher_t ctx)171 static int cipher_init_pxor(akmos_cipher_t ctx)
172 {
173 switch(ctx->xalgo->desc.blklen) {
174 case 8:
175 ctx->pxor = &akmos_pxor8;
176 break;
177
178 case 16:
179 ctx->pxor = &akmos_pxor16;
180 break;
181
182 case 32:
183 ctx->pxor = &akmos_pxor32;
184 break;
185
186 case 64:
187 ctx->pxor = &akmos_pxor64;
188 break;
189
190 case 128:
191 ctx->pxor = &akmos_pxor128;
192 break;
193
194 default:
195 return AKMOS_ERR_BLKLEN;
196 }
197
198 return AKMOS_ERR_SUCCESS;
199 }
200
akmos_cipher_init(akmos_cipher_t * ctx,akmos_algo_id algo,akmos_mode_id mode)201 int akmos_cipher_init(akmos_cipher_t *ctx, akmos_algo_id algo, akmos_mode_id mode)
202 {
203 akmos_cipher_t ptr;
204 int err;
205
206 err = AKMOS_ERR_SUCCESS;
207
208 ptr = *ctx = malloc(sizeof(struct akmos_cipher_s));
209 if(!ptr)
210 return AKMOS_ERR_ENOMEM;
211
212 memset(ptr, 0, sizeof(struct akmos_cipher_s));
213
214 ptr->xalgo = akmos_cipher_xalgo(algo);
215 if(!ptr->xalgo) {
216 err = AKMOS_ERR_ALGOID;
217 goto out;
218 }
219
220 /* stream cipher support only CTR mode */
221 if((algo & AKMOS_ALGO_STMCIPH_MASK)) {
222 if((mode & AKMOS_MODE_CIPHER_MASK) != AKMOS_MODE_CTR) {
223 err = AKMOS_ERR_STMMODE;
224 goto out;
225 }
226
227 cipher_init_stream(ptr);
228 /* set mode for block cipher */
229 } else {
230 err = cipher_init_mode(ptr, mode);
231 if(err)
232 goto out;
233 }
234
235 /* set iv routines */
236 if(ptr->xmode->setiv)
237 ptr->setiv = ptr->xmode->setiv;
238
239 /* set cnt routines */
240 if(ptr->xmode->setcnt)
241 ptr->setcnt = ptr->xmode->setcnt;
242
243 /* TDEA */
244 err = cipher_init_tde(ptr, algo & AKMOS_ALGO_FLAG_MASK);
245 if(err)
246 goto out;
247
248 /* set parallel xor routines */
249 err = cipher_init_pxor(ptr);
250 if(err)
251 goto out;
252
253 return AKMOS_ERR_SUCCESS;
254
255 /* process errors */
256 out:
257 if(ptr)
258 free(ptr);
259
260 return err;
261 }
262
akmos_cipher_setkey(akmos_cipher_t ctx,const uint8_t * key,size_t len)263 int akmos_cipher_setkey(akmos_cipher_t ctx, const uint8_t *key, size_t len)
264 {
265 if(len < ctx->xalgo->desc.keymin || len > ctx->xalgo->desc.keymax)
266 return AKMOS_ERR_KEYLEN;
267
268 if((len % ctx->xalgo->desc.keystep) != 0)
269 return AKMOS_ERR_KEYLEN;
270
271 ctx->setkey(ctx, key, len);
272
273 return AKMOS_ERR_SUCCESS;
274 }
275
akmos_cipher_setiv(akmos_cipher_t ctx,const uint8_t * iv)276 void akmos_cipher_setiv(akmos_cipher_t ctx, const uint8_t *iv)
277 {
278 if(ctx->setiv)
279 ctx->setiv(ctx, iv);
280 }
281
akmos_cipher_setcnt(akmos_cipher_t ctx,const uint8_t * cnt)282 void akmos_cipher_setcnt(akmos_cipher_t ctx, const uint8_t *cnt)
283 {
284 if(ctx->setcnt)
285 ctx->setcnt(ctx, cnt);
286 }
287
akmos_cipher_crypt(akmos_cipher_t ctx,const uint8_t * in_blk,size_t in_len,uint8_t * out_blk)288 void akmos_cipher_crypt(akmos_cipher_t ctx, const uint8_t *in_blk, size_t in_len, uint8_t *out_blk)
289 {
290 ctx->crypt(ctx, in_blk, in_len, out_blk);
291 }
292
akmos_cipher_free(akmos_cipher_t ctx)293 void akmos_cipher_free(akmos_cipher_t ctx)
294 {
295 if(!ctx)
296 return;
297
298 akmos_memzero(ctx, sizeof(struct akmos_cipher_s));
299 free(ctx);
300 }
301
akmos_cipher(akmos_algo_id algo,akmos_mode_id mode,const uint8_t * key,size_t keylen,const uint8_t * iv,const uint8_t * in_blk,size_t in_len,uint8_t * out_blk)302 int akmos_cipher(akmos_algo_id algo, akmos_mode_id mode, const uint8_t *key, size_t keylen,
303 const uint8_t *iv, const uint8_t *in_blk, size_t in_len, uint8_t *out_blk)
304 {
305 akmos_cipher_t ctx;
306 int err;
307
308 err = akmos_cipher_init(&ctx, algo, mode);
309 if(err)
310 return err;
311
312 err = akmos_cipher_setkey(ctx, key, keylen);
313 if(err)
314 goto out;
315
316 akmos_cipher_setiv(ctx, iv);
317
318 if(mode == AKMOS_MODE_CTR)
319 akmos_cipher_setcnt(ctx, 0);
320
321 akmos_cipher_crypt(ctx, in_blk, in_len, out_blk);
322
323 out:
324 if(ctx)
325 akmos_cipher_free(ctx);
326
327 return err;
328 }
329