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