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 FFmpeg.
8 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "intreadwrite.h"
35 typedef struct AVAES
{
36 // Note: round_key[16] is accessed in the init code, but this only
37 // overwrites state, which does not matter (see also commit ba554c0).
38 av_aes_block round_key
[15];
39 av_aes_block state
[2];
43 const int av_aes_size
= sizeof(AVAES
);
45 struct AVAES
*av_aes_alloc(void)
47 return av_mallocz(sizeof(struct AVAES
));
50 static const uint8_t rcon
[10] = {
51 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
54 static uint8_t sbox
[256];
55 static uint8_t inv_sbox
[256];
57 static uint32_t enc_multbl
[1][256];
58 static uint32_t dec_multbl
[1][256];
60 static uint32_t enc_multbl
[4][256];
61 static uint32_t dec_multbl
[4][256];
65 # define ROT(x, s) ((x >> s) | (x << (32-s)))
67 # define ROT(x, s) ((x << s) | (x >> (32-s)))
70 static inline void addkey(av_aes_block
*dst
, const av_aes_block
*src
,
71 const av_aes_block
*round_key
)
73 dst
->u64
[0] = src
->u64
[0] ^ round_key
->u64
[0];
74 dst
->u64
[1] = src
->u64
[1] ^ round_key
->u64
[1];
77 static inline void addkey_s(av_aes_block
*dst
, const uint8_t *src
,
78 const av_aes_block
*round_key
)
80 dst
->u64
[0] = AV_RN64(src
) ^ round_key
->u64
[0];
81 dst
->u64
[1] = AV_RN64(src
+ 8) ^ round_key
->u64
[1];
84 static inline void addkey_d(uint8_t *dst
, const av_aes_block
*src
,
85 const av_aes_block
*round_key
)
87 AV_WN64(dst
, src
->u64
[0] ^ round_key
->u64
[0]);
88 AV_WN64(dst
+ 8, src
->u64
[1] ^ round_key
->u64
[1]);
91 static void subshift(av_aes_block s0
[2], int s
, const uint8_t *box
)
93 av_aes_block
*s1
= (av_aes_block
*) (s0
[0].u8
- s
);
94 av_aes_block
*s3
= (av_aes_block
*) (s0
[0].u8
+ s
);
96 s0
[0].u8
[ 0] = box
[s0
[1].u8
[ 0]];
97 s0
[0].u8
[ 4] = box
[s0
[1].u8
[ 4]];
98 s0
[0].u8
[ 8] = box
[s0
[1].u8
[ 8]];
99 s0
[0].u8
[12] = box
[s0
[1].u8
[12]];
100 s1
[0].u8
[ 3] = box
[s1
[1].u8
[ 7]];
101 s1
[0].u8
[ 7] = box
[s1
[1].u8
[11]];
102 s1
[0].u8
[11] = box
[s1
[1].u8
[15]];
103 s1
[0].u8
[15] = box
[s1
[1].u8
[ 3]];
104 s0
[0].u8
[ 2] = box
[s0
[1].u8
[10]];
105 s0
[0].u8
[10] = box
[s0
[1].u8
[ 2]];
106 s0
[0].u8
[ 6] = box
[s0
[1].u8
[14]];
107 s0
[0].u8
[14] = box
[s0
[1].u8
[ 6]];
108 s3
[0].u8
[ 1] = box
[s3
[1].u8
[13]];
109 s3
[0].u8
[13] = box
[s3
[1].u8
[ 9]];
110 s3
[0].u8
[ 9] = box
[s3
[1].u8
[ 5]];
111 s3
[0].u8
[ 5] = box
[s3
[1].u8
[ 1]];
114 static inline int mix_core(uint32_t multbl
[][256], int a
, int b
, int c
, int d
){
116 return multbl
[0][a
] ^ ROT(multbl
[0][b
], 8) ^ ROT(multbl
[0][c
], 16) ^ ROT(multbl
[0][d
], 24);
118 return multbl
[0][a
] ^ multbl
[1][b
] ^ multbl
[2][c
] ^ multbl
[3][d
];
122 static inline void mix(av_aes_block state
[2], uint32_t multbl
[][256], int s1
, int s3
){
123 uint8_t (*src
)[4] = state
[1].u8x4
;
124 state
[0].u32
[0] = mix_core(multbl
, src
[0][0], src
[s1
][1], src
[2][2], src
[s3
][3]);
125 state
[0].u32
[1] = mix_core(multbl
, src
[1][0], src
[s3
-1][1], src
[3][2], src
[s1
-1][3]);
126 state
[0].u32
[2] = mix_core(multbl
, src
[2][0], src
[s3
][1], src
[0][2], src
[s1
][3]);
127 state
[0].u32
[3] = mix_core(multbl
, src
[3][0], src
[s1
-1][1], src
[1][2], src
[s3
-1][3]);
130 static inline void crypt(AVAES
*a
, int s
, const uint8_t *sbox
,
131 uint32_t multbl
[][256])
135 for (r
= a
->rounds
- 1; r
> 0; r
--) {
136 mix(a
->state
, multbl
, 3 - s
, 1 + s
);
137 addkey(&a
->state
[1], &a
->state
[0], &a
->round_key
[r
]);
140 subshift(&a
->state
[0], s
, sbox
);
143 void av_aes_crypt(AVAES
*a
, uint8_t *dst
, const uint8_t *src
,
144 int count
, uint8_t *iv
, int decrypt
)
147 addkey_s(&a
->state
[1], src
, &a
->round_key
[a
->rounds
]);
149 crypt(a
, 0, inv_sbox
, dec_multbl
);
151 addkey_s(&a
->state
[0], iv
, &a
->state
[0]);
154 addkey_d(dst
, &a
->state
[0], &a
->round_key
[0]);
157 addkey_s(&a
->state
[1], iv
, &a
->state
[1]);
158 crypt(a
, 2, sbox
, enc_multbl
);
159 addkey_d(dst
, &a
->state
[0], &a
->round_key
[0]);
168 static void init_multbl2(uint32_t tbl
[][256], const int c
[4],
169 const uint8_t *log8
, const uint8_t *alog8
,
174 for (i
= 0; i
< 256; i
++) {
179 k
= alog8
[x
+ log8
[c
[0]]];
180 l
= alog8
[x
+ log8
[c
[1]]];
181 m
= alog8
[x
+ log8
[c
[2]]];
182 n
= alog8
[x
+ log8
[c
[3]]];
183 tbl
[0][i
] = AV_NE(MKBETAG(k
,l
,m
,n
), MKTAG(k
,l
,m
,n
));
185 tbl
[1][i
] = ROT(tbl
[0][i
], 8);
186 tbl
[2][i
] = ROT(tbl
[0][i
], 16);
187 tbl
[3][i
] = ROT(tbl
[0][i
], 24);
193 // this is based on the reference AES code by Paulo Barreto and Vincent Rijmen
194 int av_aes_init(AVAES
*a
, const uint8_t *key
, int key_bits
, int decrypt
)
196 int i
, j
, t
, rconpointer
= 0;
198 int KC
= key_bits
>> 5;
203 if (!enc_multbl
[FF_ARRAY_ELEMS(enc_multbl
)-1][FF_ARRAY_ELEMS(enc_multbl
[0])-1]) {
205 for (i
= 0; i
< 255; i
++) {
206 alog8
[i
] = alog8
[i
+ 255] = j
;
212 for (i
= 0; i
< 256; i
++) {
213 j
= i
? alog8
[255 - log8
[i
]] : 0;
214 j
^= (j
<< 1) ^ (j
<< 2) ^ (j
<< 3) ^ (j
<< 4);
215 j
= (j
^ (j
>> 8) ^ 99) & 255;
219 init_multbl2(dec_multbl
, (const int[4]) { 0xe, 0x9, 0xd, 0xb },
220 log8
, alog8
, inv_sbox
);
221 init_multbl2(enc_multbl
, (const int[4]) { 0x2, 0x1, 0x1, 0x3 },
225 if (key_bits
!= 128 && key_bits
!= 192 && key_bits
!= 256)
230 memcpy(tk
, key
, KC
* 4);
231 memcpy(a
->round_key
[0].u8
, key
, KC
* 4);
233 for (t
= KC
* 4; t
< (rounds
+ 1) * 16; t
+= KC
* 4) {
234 for (i
= 0; i
< 4; i
++)
235 tk
[0][i
] ^= sbox
[tk
[KC
- 1][(i
+ 1) & 3]];
236 tk
[0][0] ^= rcon
[rconpointer
++];
238 for (j
= 1; j
< KC
; j
++) {
239 if (KC
!= 8 || j
!= KC
>> 1)
240 for (i
= 0; i
< 4; i
++)
241 tk
[j
][i
] ^= tk
[j
- 1][i
];
243 for (i
= 0; i
< 4; i
++)
244 tk
[j
][i
] ^= sbox
[tk
[j
- 1][i
]];
247 memcpy(a
->round_key
[0].u8
+ t
, tk
, KC
* 4);
251 for (i
= 1; i
< rounds
; i
++) {
253 tmp
[2] = a
->round_key
[i
];
254 subshift(&tmp
[1], 0, sbox
);
255 mix(tmp
, dec_multbl
, 1, 3);
256 a
->round_key
[i
] = tmp
[0];
259 for (i
= 0; i
< (rounds
+ 1) >> 1; i
++) {
260 FFSWAP(av_aes_block
, a
->round_key
[i
], a
->round_key
[rounds
-i
]);
273 int main(int argc
, char **argv
)
277 uint8_t rkey
[2][16] = {
279 { 0x10, 0xa5, 0x88, 0x69, 0xd7, 0x4b, 0xe5, 0xa3,
280 0x74, 0xcf, 0x86, 0x7c, 0xfb, 0x47, 0x38, 0x59 }
282 uint8_t pt
[16], rpt
[2][16]= {
283 { 0x6a, 0x84, 0x86, 0x7c, 0xd7, 0x7e, 0x12, 0xad,
284 0x07, 0xea, 0x1b, 0xe8, 0x95, 0xc5, 0x3f, 0xa3 },
287 uint8_t rct
[2][16]= {
288 { 0x73, 0x22, 0x81, 0xc0, 0xa0, 0xaa, 0xb8, 0xf7,
289 0xa5, 0x4a, 0x0c, 0x67, 0xa0, 0xc4, 0x5e, 0xcf },
290 { 0x6d, 0x25, 0x1e, 0x69, 0x44, 0xb0, 0x51, 0xe0,
291 0x4e, 0xaa, 0x6f, 0xb4, 0xdb, 0xf7, 0x84, 0x65 }
296 av_log_set_level(AV_LOG_DEBUG
);
298 for (i
= 0; i
< 2; i
++) {
299 av_aes_init(&b
, rkey
[i
], 128, 1);
300 av_aes_crypt(&b
, temp
, rct
[i
], 1, NULL
, 1);
301 for (j
= 0; j
< 16; j
++) {
302 if (rpt
[i
][j
] != temp
[j
]) {
303 av_log(NULL
, AV_LOG_ERROR
, "%d %02X %02X\n",
304 j
, rpt
[i
][j
], temp
[j
]);
310 if (argc
> 1 && !strcmp(argv
[1], "-t")) {
314 av_aes_init(&ae
, "PI=3.141592654..", 128, 0);
315 av_aes_init(&ad
, "PI=3.141592654..", 128, 1);
316 av_lfg_init(&prng
, 1);
318 for (i
= 0; i
< 10000; i
++) {
319 for (j
= 0; j
< 16; j
++) {
320 pt
[j
] = av_lfg_get(&prng
);
324 av_aes_crypt(&ae
, temp
, pt
, 1, NULL
, 0);
326 av_log(NULL
, AV_LOG_ERROR
, "%02X %02X %02X %02X\n",
327 temp
[0], temp
[5], temp
[10], temp
[15]);
328 av_aes_crypt(&ad
, temp
, temp
, 1, NULL
, 1);
331 for (j
= 0; j
< 16; j
++) {
332 if (pt
[j
] != temp
[j
]) {
333 av_log(NULL
, AV_LOG_ERROR
, "%d %d %02X %02X\n",
334 i
, j
, pt
[j
], temp
[j
]);