2 * copyright (c) 2007 Michael Niedermayer <michaelni@gmx.at>
4 * some optimization ideas from aes128.c by Reimar Doeffinger
6 * This file is part of Libav.
8 * Libav is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * Libav is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with Libav; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "intreadwrite.h"
34 typedef struct AVAES
{
35 // Note: round_key[16] is accessed in the init code, but this only
36 // overwrites state, which does not matter (see also commit ba554c0).
37 av_aes_block round_key
[15];
38 av_aes_block state
[2];
42 const int av_aes_size
= sizeof(AVAES
);
44 static const uint8_t rcon
[10] = {
45 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
48 static uint8_t sbox
[256];
49 static uint8_t inv_sbox
[256];
51 static uint32_t enc_multbl
[1][256];
52 static uint32_t dec_multbl
[1][256];
54 static uint32_t enc_multbl
[4][256];
55 static uint32_t dec_multbl
[4][256];
59 # define ROT(x, s) ((x >> s) | (x << (32-s)))
61 # define ROT(x, s) ((x << s) | (x >> (32-s)))
64 static inline void addkey(av_aes_block
*dst
, const av_aes_block
*src
,
65 const av_aes_block
*round_key
)
67 dst
->u64
[0] = src
->u64
[0] ^ round_key
->u64
[0];
68 dst
->u64
[1] = src
->u64
[1] ^ round_key
->u64
[1];
71 static inline void addkey_s(av_aes_block
*dst
, const uint8_t *src
,
72 const av_aes_block
*round_key
)
74 dst
->u64
[0] = AV_RN64(src
) ^ round_key
->u64
[0];
75 dst
->u64
[1] = AV_RN64(src
+ 8) ^ round_key
->u64
[1];
78 static inline void addkey_d(uint8_t *dst
, const av_aes_block
*src
,
79 const av_aes_block
*round_key
)
81 AV_WN64(dst
, src
->u64
[0] ^ round_key
->u64
[0]);
82 AV_WN64(dst
+ 8, src
->u64
[1] ^ round_key
->u64
[1]);
85 static void subshift(av_aes_block s0
[2], int s
, const uint8_t *box
)
87 av_aes_block
*s1
= (av_aes_block
*) (s0
[0].u8
- s
);
88 av_aes_block
*s3
= (av_aes_block
*) (s0
[0].u8
+ s
);
90 s0
[0].u8
[ 0] = box
[s0
[1].u8
[ 0]];
91 s0
[0].u8
[ 4] = box
[s0
[1].u8
[ 4]];
92 s0
[0].u8
[ 8] = box
[s0
[1].u8
[ 8]];
93 s0
[0].u8
[12] = box
[s0
[1].u8
[12]];
94 s1
[0].u8
[ 3] = box
[s1
[1].u8
[ 7]];
95 s1
[0].u8
[ 7] = box
[s1
[1].u8
[11]];
96 s1
[0].u8
[11] = box
[s1
[1].u8
[15]];
97 s1
[0].u8
[15] = box
[s1
[1].u8
[ 3]];
98 s0
[0].u8
[ 2] = box
[s0
[1].u8
[10]];
99 s0
[0].u8
[10] = box
[s0
[1].u8
[ 2]];
100 s0
[0].u8
[ 6] = box
[s0
[1].u8
[14]];
101 s0
[0].u8
[14] = box
[s0
[1].u8
[ 6]];
102 s3
[0].u8
[ 1] = box
[s3
[1].u8
[13]];
103 s3
[0].u8
[13] = box
[s3
[1].u8
[ 9]];
104 s3
[0].u8
[ 9] = box
[s3
[1].u8
[ 5]];
105 s3
[0].u8
[ 5] = box
[s3
[1].u8
[ 1]];
108 static inline int mix_core(uint32_t multbl
[][256], int a
, int b
, int c
, int d
){
110 return multbl
[0][a
] ^ ROT(multbl
[0][b
], 8) ^ ROT(multbl
[0][c
], 16) ^ ROT(multbl
[0][d
], 24);
112 return multbl
[0][a
] ^ multbl
[1][b
] ^ multbl
[2][c
] ^ multbl
[3][d
];
116 static inline void mix(av_aes_block state
[2], uint32_t multbl
[][256], int s1
, int s3
){
117 uint8_t (*src
)[4] = state
[1].u8x4
;
118 state
[0].u32
[0] = mix_core(multbl
, src
[0][0], src
[s1
][1], src
[2][2], src
[s3
][3]);
119 state
[0].u32
[1] = mix_core(multbl
, src
[1][0], src
[s3
-1][1], src
[3][2], src
[s1
-1][3]);
120 state
[0].u32
[2] = mix_core(multbl
, src
[2][0], src
[s3
][1], src
[0][2], src
[s1
][3]);
121 state
[0].u32
[3] = mix_core(multbl
, src
[3][0], src
[s1
-1][1], src
[1][2], src
[s3
-1][3]);
124 static inline void crypt(AVAES
*a
, int s
, const uint8_t *sbox
,
125 uint32_t multbl
[][256])
129 for (r
= a
->rounds
- 1; r
> 0; r
--) {
130 mix(a
->state
, multbl
, 3 - s
, 1 + s
);
131 addkey(&a
->state
[1], &a
->state
[0], &a
->round_key
[r
]);
134 subshift(&a
->state
[0], s
, sbox
);
137 void av_aes_crypt(AVAES
*a
, uint8_t *dst
, const uint8_t *src
,
138 int count
, uint8_t *iv
, int decrypt
)
141 addkey_s(&a
->state
[1], src
, &a
->round_key
[a
->rounds
]);
143 crypt(a
, 0, inv_sbox
, dec_multbl
);
145 addkey_s(&a
->state
[0], iv
, &a
->state
[0]);
148 addkey_d(dst
, &a
->state
[0], &a
->round_key
[0]);
151 addkey_s(&a
->state
[1], iv
, &a
->state
[1]);
152 crypt(a
, 2, sbox
, enc_multbl
);
153 addkey_d(dst
, &a
->state
[0], &a
->round_key
[0]);
162 static void init_multbl2(uint32_t tbl
[][256], const int c
[4],
163 const uint8_t *log8
, const uint8_t *alog8
,
168 for (i
= 0; i
< 256; i
++) {
173 k
= alog8
[x
+ log8
[c
[0]]];
174 l
= alog8
[x
+ log8
[c
[1]]];
175 m
= alog8
[x
+ log8
[c
[2]]];
176 n
= alog8
[x
+ log8
[c
[3]]];
177 tbl
[0][i
] = AV_NE(MKBETAG(k
,l
,m
,n
), MKTAG(k
,l
,m
,n
));
179 tbl
[1][i
] = ROT(tbl
[0][i
], 8);
180 tbl
[2][i
] = ROT(tbl
[0][i
], 16);
181 tbl
[3][i
] = ROT(tbl
[0][i
], 24);
187 // this is based on the reference AES code by Paulo Barreto and Vincent Rijmen
188 int av_aes_init(AVAES
*a
, const uint8_t *key
, int key_bits
, int decrypt
)
190 int i
, j
, t
, rconpointer
= 0;
192 int KC
= key_bits
>> 5;
197 if (!enc_multbl
[FF_ARRAY_ELEMS(enc_multbl
)-1][FF_ARRAY_ELEMS(enc_multbl
[0])-1]) {
199 for (i
= 0; i
< 255; i
++) {
200 alog8
[i
] = alog8
[i
+ 255] = j
;
206 for (i
= 0; i
< 256; i
++) {
207 j
= i ? alog8
[255 - log8
[i
]] : 0;
208 j
^= (j
<< 1) ^ (j
<< 2) ^ (j
<< 3) ^ (j
<< 4);
209 j
= (j
^ (j
>> 8) ^ 99) & 255;
213 init_multbl2(dec_multbl
, (const int[4]) { 0xe, 0x9, 0xd, 0xb },
214 log8
, alog8
, inv_sbox
);
215 init_multbl2(enc_multbl
, (const int[4]) { 0x2, 0x1, 0x1, 0x3 },
219 if (key_bits
!= 128 && key_bits
!= 192 && key_bits
!= 256)
224 memcpy(tk
, key
, KC
* 4);
225 memcpy(a
->round_key
[0].u8
, key
, KC
* 4);
227 for (t
= KC
* 4; t
< (rounds
+ 1) * 16; t
+= KC
* 4) {
228 for (i
= 0; i
< 4; i
++)
229 tk
[0][i
] ^= sbox
[tk
[KC
- 1][(i
+ 1) & 3]];
230 tk
[0][0] ^= rcon
[rconpointer
++];
232 for (j
= 1; j
< KC
; j
++) {
233 if (KC
!= 8 || j
!= KC
>> 1)
234 for (i
= 0; i
< 4; i
++)
235 tk
[j
][i
] ^= tk
[j
- 1][i
];
237 for (i
= 0; i
< 4; i
++)
238 tk
[j
][i
] ^= sbox
[tk
[j
- 1][i
]];
241 memcpy(a
->round_key
[0].u8
+ t
, tk
, KC
* 4);
245 for (i
= 1; i
< rounds
; i
++) {
247 tmp
[2] = a
->round_key
[i
];
248 subshift(&tmp
[1], 0, sbox
);
249 mix(tmp
, dec_multbl
, 1, 3);
250 a
->round_key
[i
] = tmp
[0];
253 for (i
= 0; i
< (rounds
+ 1) >> 1; i
++) {
254 FFSWAP(av_aes_block
, a
->round_key
[i
], a
->round_key
[rounds
-i
]);
266 int main(int argc
, char **argv
)
270 uint8_t rkey
[2][16] = {
272 { 0x10, 0xa5, 0x88, 0x69, 0xd7, 0x4b, 0xe5, 0xa3,
273 0x74, 0xcf, 0x86, 0x7c, 0xfb, 0x47, 0x38, 0x59 }
275 uint8_t pt
[16], rpt
[2][16]= {
276 { 0x6a, 0x84, 0x86, 0x7c, 0xd7, 0x7e, 0x12, 0xad,
277 0x07, 0xea, 0x1b, 0xe8, 0x95, 0xc5, 0x3f, 0xa3 },
280 uint8_t rct
[2][16]= {
281 { 0x73, 0x22, 0x81, 0xc0, 0xa0, 0xaa, 0xb8, 0xf7,
282 0xa5, 0x4a, 0x0c, 0x67, 0xa0, 0xc4, 0x5e, 0xcf },
283 { 0x6d, 0x25, 0x1e, 0x69, 0x44, 0xb0, 0x51, 0xe0,
284 0x4e, 0xaa, 0x6f, 0xb4, 0xdb, 0xf7, 0x84, 0x65 }
289 av_log_set_level(AV_LOG_DEBUG
);
291 for (i
= 0; i
< 2; i
++) {
292 av_aes_init(&b
, rkey
[i
], 128, 1);
293 av_aes_crypt(&b
, temp
, rct
[i
], 1, NULL
, 1);
294 for (j
= 0; j
< 16; j
++) {
295 if (rpt
[i
][j
] != temp
[j
]) {
296 av_log(NULL
, AV_LOG_ERROR
, "%d %02X %02X\n",
297 j
, rpt
[i
][j
], temp
[j
]);
303 if (argc
> 1 && !strcmp(argv
[1], "-t")) {
307 av_aes_init(&ae
, "PI=3.141592654..", 128, 0);
308 av_aes_init(&ad
, "PI=3.141592654..", 128, 1);
309 av_lfg_init(&prng
, 1);
311 for (i
= 0; i
< 10000; i
++) {
312 for (j
= 0; j
< 16; j
++) {
313 pt
[j
] = av_lfg_get(&prng
);
317 av_aes_crypt(&ae
, temp
, pt
, 1, NULL
, 0);
319 av_log(NULL
, AV_LOG_ERROR
, "%02X %02X %02X %02X\n",
320 temp
[0], temp
[5], temp
[10], temp
[15]);
321 av_aes_crypt(&ad
, temp
, temp
, 1, NULL
, 1);
324 for (j
= 0; j
< 16; j
++) {
325 if (pt
[j
] != temp
[j
]) {
326 av_log(NULL
, AV_LOG_ERROR
, "%d %d %02X %02X\n",
327 i
, j
, pt
[j
], temp
[j
]);