Merged revisions 127663 via svnmerge from
[asterisk/asterisk.git] / main / aescrypt.c
1 /*
2  ---------------------------------------------------------------------------
3  Copyright (c) 2003, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
4  All rights reserved.
5
6  LICENSE TERMS
7
8  The free distribution and use of this software in both source and binary
9  form is allowed (with or without changes) provided that:
10
11    1. distributions of this source code include the above copyright
12       notice, this list of conditions and the following disclaimer;
13
14    2. distributions in binary form include the above copyright
15       notice, this list of conditions and the following disclaimer
16       in the documentation and/or other associated materials;
17
18    3. the copyright holder's name is not used to endorse products
19       built using this software without specific written permission.
20
21  ALTERNATIVELY, provided that this notice is retained in full, this product
22  may be distributed under the terms of the GNU General Public License (GPL),
23  in which case the provisions of the GPL apply INSTEAD OF those given above.
24
25  DISCLAIMER
26
27  This software is provided 'as is' with no explicit or implied warranties
28  in respect of its properties, including, but not limited to, correctness
29  and/or fitness for purpose.
30  ---------------------------------------------------------------------------
31  Issue Date: 26/08/2003
32
33 */
34
35 /*! \file
36  *
37  * \brief  This file contains the code for implementing encryption and decryption
38  * for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It
39  * can optionally be replaced by code written in assembler using NASM. For
40  * further details see the file aesopt.h
41  *
42  * \author Dr Brian Gladman <brg@gladman.me.uk>
43  */
44
45 #if defined(__cplusplus)
46 extern "C"
47 {
48 #endif
49
50 #ifndef HAVE_CRYPTO
51
52 #include "aesopt.h"
53
54 #define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
55 #define so(y,x,c)   word_out(y, c, s(x,c))
56
57 #if defined(ARRAYS)
58 #define locals(y,x)     x[4],y[4]
59 #else
60 #define locals(y,x)     x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
61 #endif
62
63 #define l_copy(y, x)    s(y,0) = s(x,0); s(y,1) = s(x,1); \
64                         s(y,2) = s(x,2); s(y,3) = s(x,3);
65 #define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
66 #define state_out(y,x)  so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
67 #define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
68
69 #if defined(ENCRYPTION) && !defined(AES_ASM)
70
71 /* Visual C++ .Net v7.1 provides the fastest encryption code when using
72    Pentium optimiation with small code but this is poor for decryption
73    so we need to control this with the following VC++ pragmas
74 */
75
76 #if defined(_MSC_VER)
77 #pragma optimize( "s", on )
78 #endif
79
80 /* Given the column (c) of the output state variable, the following
81    macros give the input state variables which are needed in its
82    computation for each row (r) of the state. All the alternative
83    macros give the same end values but expand into different ways
84    of calculating these values.  In particular the complex macro
85    used for dynamically variable block sizes is designed to expand
86    to a compile time constant whenever possible but will expand to
87    conditional clauses on some branches (I am grateful to Frank
88    Yellin for this construction)
89 */
90
91 #define fwd_var(x,r,c)\
92  ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
93  : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
94  : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
95  :          ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
96
97 #if defined(FT4_SET)
98 #undef  dec_fmvars
99 #define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
100 #elif defined(FT1_SET)
101 #undef  dec_fmvars
102 #define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
103 #else
104 #define fwd_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
105 #endif
106
107 #if defined(FL4_SET)
108 #define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
109 #elif defined(FL1_SET)
110 #define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
111 #else
112 #define fwd_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
113 #endif
114
115 aes_rval aes_encrypt(const void *in_blk, void *out_blk, const aes_encrypt_ctx cx[1])
116 {   aes_32t         locals(b0, b1);
117     const aes_32t   *kp = cx->ks;
118 #ifdef dec_fmvars
119     dec_fmvars; /* declare variables for fwd_mcol() if needed */
120 #endif
121
122     aes_32t nr = (kp[45] ^ kp[52] ^ kp[53] ? kp[52] : 14);
123
124 #ifdef AES_ERR_CHK
125     if(   (nr != 10 || !(kp[0] | kp[3] | kp[4])) 
126        && (nr != 12 || !(kp[0] | kp[5] | kp[6]))
127        && (nr != 14 || !(kp[0] | kp[7] | kp[8])) )
128         return aes_error;
129 #endif
130
131     state_in(b0, in_blk, kp);
132
133 #if (ENC_UNROLL == FULL)
134
135     switch(nr)
136     {
137     case 14:
138         round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
139         round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
140         kp += 2 * N_COLS;
141     case 12:
142         round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
143         round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
144         kp += 2 * N_COLS;
145     case 10:
146         round(fwd_rnd,  b1, b0, kp + 1 * N_COLS);
147         round(fwd_rnd,  b0, b1, kp + 2 * N_COLS);
148         round(fwd_rnd,  b1, b0, kp + 3 * N_COLS);
149         round(fwd_rnd,  b0, b1, kp + 4 * N_COLS);
150         round(fwd_rnd,  b1, b0, kp + 5 * N_COLS);
151         round(fwd_rnd,  b0, b1, kp + 6 * N_COLS);
152         round(fwd_rnd,  b1, b0, kp + 7 * N_COLS);
153         round(fwd_rnd,  b0, b1, kp + 8 * N_COLS);
154         round(fwd_rnd,  b1, b0, kp + 9 * N_COLS);
155         round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
156     }
157
158 #else
159
160 #if (ENC_UNROLL == PARTIAL)
161     {   aes_32t    rnd;
162         for(rnd = 0; rnd < (nr >> 1) - 1; ++rnd)
163         {
164             kp += N_COLS;
165             round(fwd_rnd, b1, b0, kp);
166             kp += N_COLS;
167             round(fwd_rnd, b0, b1, kp);
168         }
169         kp += N_COLS;
170         round(fwd_rnd,  b1, b0, kp);
171 #else
172     {   aes_32t    rnd;
173         for(rnd = 0; rnd < nr - 1; ++rnd)
174         {
175             kp += N_COLS;
176             round(fwd_rnd, b1, b0, kp);
177             l_copy(b0, b1);
178         }
179 #endif
180         kp += N_COLS;
181         round(fwd_lrnd, b0, b1, kp);
182     }
183 #endif
184
185     state_out(out_blk, b0);
186 #ifdef AES_ERR_CHK
187     return aes_good;
188 #endif
189 }
190
191 #endif
192
193 #if defined(DECRYPTION) && !defined(AES_ASM)
194
195 /* Visual C++ .Net v7.1 provides the fastest encryption code when using
196    Pentium optimiation with small code but this is poor for decryption
197    so we need to control this with the following VC++ pragmas
198 */
199
200 #if defined(_MSC_VER)
201 #pragma optimize( "t", on )
202 #endif
203
204 /* Given the column (c) of the output state variable, the following
205    macros give the input state variables which are needed in its
206    computation for each row (r) of the state. All the alternative
207    macros give the same end values but expand into different ways
208    of calculating these values.  In particular the complex macro
209    used for dynamically variable block sizes is designed to expand
210    to a compile time constant whenever possible but will expand to
211    conditional clauses on some branches (I am grateful to Frank
212    Yellin for this construction)
213 */
214
215 #define inv_var(x,r,c)\
216  ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
217  : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
218  : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
219  :          ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
220
221 #if defined(IT4_SET)
222 #undef  dec_imvars
223 #define inv_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
224 #elif defined(IT1_SET)
225 #undef  dec_imvars
226 #define inv_rnd(y,x,k,c)    (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
227 #else
228 #define inv_rnd(y,x,k,c)    (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
229 #endif
230
231 #if defined(IL4_SET)
232 #define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
233 #elif defined(IL1_SET)
234 #define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
235 #else
236 #define inv_lrnd(y,x,k,c)   (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
237 #endif
238
239 aes_rval aes_decrypt(const void *in_blk, void *out_blk, const aes_decrypt_ctx cx[1])
240 {   aes_32t        locals(b0, b1);
241 #ifdef dec_imvars
242     dec_imvars; /* declare variables for inv_mcol() if needed */
243 #endif
244
245     aes_32t nr = (cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] ? cx->ks[52] : 14);
246     const aes_32t *kp = cx->ks + nr * N_COLS;
247
248 #ifdef AES_ERR_CHK
249     if(   (nr != 10 || !(cx->ks[0] | cx->ks[3] | cx->ks[4])) 
250        && (nr != 12 || !(cx->ks[0] | cx->ks[5] | cx->ks[6]))
251        && (nr != 14 || !(cx->ks[0] | cx->ks[7] | cx->ks[8])) )
252         return aes_error;
253 #endif
254
255     state_in(b0, in_blk, kp);
256
257 #if (DEC_UNROLL == FULL)
258
259     switch(nr)
260     {
261     case 14:
262         round(inv_rnd,  b1, b0, kp -  1 * N_COLS);
263         round(inv_rnd,  b0, b1, kp -  2 * N_COLS);
264         kp -= 2 * N_COLS;
265     case 12:
266         round(inv_rnd,  b1, b0, kp -  1 * N_COLS);
267         round(inv_rnd,  b0, b1, kp -  2 * N_COLS);
268         kp -= 2 * N_COLS;
269     case 10:
270         round(inv_rnd,  b1, b0, kp -  1 * N_COLS);
271         round(inv_rnd,  b0, b1, kp -  2 * N_COLS);
272         round(inv_rnd,  b1, b0, kp -  3 * N_COLS);
273         round(inv_rnd,  b0, b1, kp -  4 * N_COLS);
274         round(inv_rnd,  b1, b0, kp -  5 * N_COLS);
275         round(inv_rnd,  b0, b1, kp -  6 * N_COLS);
276         round(inv_rnd,  b1, b0, kp -  7 * N_COLS);
277         round(inv_rnd,  b0, b1, kp -  8 * N_COLS);
278         round(inv_rnd,  b1, b0, kp -  9 * N_COLS);
279         round(inv_lrnd, b0, b1, kp - 10 * N_COLS);
280     }
281
282 #else
283
284 #if (DEC_UNROLL == PARTIAL)
285     {   aes_32t    rnd;
286         for(rnd = 0; rnd < (nr >> 1) - 1; ++rnd)
287         {
288             kp -= N_COLS;
289             round(inv_rnd, b1, b0, kp);
290             kp -= N_COLS;
291             round(inv_rnd, b0, b1, kp);
292         }
293         kp -= N_COLS;
294         round(inv_rnd, b1, b0, kp);
295 #else
296     {   aes_32t    rnd;
297         for(rnd = 0; rnd < nr - 1; ++rnd)
298         {
299             kp -= N_COLS;
300             round(inv_rnd, b1, b0, kp);
301             l_copy(b0, b1);
302         }
303 #endif
304         kp -= N_COLS;
305         round(inv_lrnd, b0, b1, kp);
306     }
307 #endif
308
309     state_out(out_blk, b0);
310 #ifdef AES_ERR_CHK
311     return aes_good;
312 #endif
313 }
314
315 #endif
316
317 #endif /* !HAVE_CRYPTO */
318
319 #if defined(__cplusplus)
320 }
321 #endif