Описание стандарта шифрования AES (Advanced Encryption Standard, улучшенный стандарт шифрования)

Создать новую статью

25.05.2009 13:00


Введение

Стандарт шифрования AES является официальным стандартом правительства США для симметричного шифрования. Стандарт определяется публикацией FIPS #197 (2001) и используется в разнообразных приложениях, где предъявляются повышенные требования к производительности и безопасности.

Компания Intel представила новый набор команд вида “одна инструкция на несколько данных” (SIMD, Single Instruction Multiple Data), который будет реализован в следующем поколении процессоров этой фирмы. Эти инструкции обеспечивают быстрое и безопасное шифрование и дешифрование с помощью алгоритма AES.

Этот набор команд, называемый SSE (Streaming SIMD Extensions, потоковое SIMD-расширение) включает в себя шесть инструкций. Четыре из них, AESENC, AESENCLAST, AESDEC, и AESDELAST обеспечивают высокопроизводительное шифрование и дешифрование. Еще две, AESIMC и AESKEYGENASSIST, позволяют производить расширение ключа AES. Вместе они обеспечивают полную аппаратную поддержку стандарта AES с необходимым уровнем безопасности, производительности и гибкости.

Данная статья приводит обзор алгоритма AES и методы использования его инструкций для достижения высокой производительности и безопасности шифрования. Приводятся также некоторые примеры специального использования этого алгоритма.

Архитектура AES и Intel®

Определение и краткое описание алгоритма AES

Стандарт шифрования AES является официальным стандартом правительства США для симметричного шифрования и описан в публикации FIPS №197 (FIPS197 hereafter).

AES представляет собой блочный шифр, кодирующий 128-битный текстовый блок в 128-битный шифрованный блок, или дешифрует 128-битный шифрованный блок в 128-битный текстовый блок.

AES представляет собой блочный шифр, кодирующий 128-битный текстовый блок в 128-битный шифрованный блок, или дешифрует 128-битный шифрованный блок в 128-битный текстовый блок.

AES-128, AES-192, AES-256 обрабатывают блоки данных за соответственно 10, 12 или 14 итераций. Каждая итерация представляет собой определенную последовательность трансформаций. Все итерации одинаковы за исключением последней, из которой исключено одно из преобразований. В дальнейшем будем именовать итерацию раундом.

Каждый раунд работает с двумя 128-битными блоками: “Текущий” и “ключ раунда”. Все раунды используют разные “ключи раунда”, которые получаются с пощью алгоритма расширения ключа. Этот алгоритм не зависит от шифруемых данных и может выполняться независимо от фазы шифрования/дешифрования.

Блок данных последовательно проходит через следующие стадии: над ним выполняется операция XOR первыми 128 битами ключа, на выходе получается “текущий” блок (эта стадия также называется нулевым раундом, с использованием нулевого ключа раунда – первых 128 битов ключа шифра). Затем текущий блок проходит через 10/12/14 раундов шифрования, после которых он превращается в шифрованный (или дешифрованный) блок.

Расположение байтов: Little Endian архитектура Intel и Big Endian спецификация FIPS197

В спецификации FIPS197 указано использование расположения байтов в словах от старшего к младшему (Big Endian), тогда как архитектура процессоров Intel подразумевает использование расположения байтов от младшего к старшему (Little Endian), так что при работе алгоритма шифрования необходимо применять соответсвующую процедуру изменения порядка байтов. Например, преобразование тестового вектора FIPS197 в стандартную нотацию Intel требует обращения порядка байтов. Если записать 128-битный вектор FIPS197 как [Byte0, byte1, …, Byte14, Byte15], в каждом байте последовательность битов идет как “самый левый – самый старший”, т.е. запись в битах [7-0, 15-8, 23-16, 31-24, …, 127-120].

Чтобы преобразовать такой вектор в стандарт Intel, его нужно отобразить как [Byte15, byte14, …, Byte1, Byte0], или в битах [127-120, …, 31-24, 23-16, 15-8, 7-0].

В дальнейшем мы будем применять шестнадцатеричную систему записи, где каждый байт записывается парой шестнадцатеричных цифр.

Пример

Рассмотрим вектор d4bf5d30e0b452aeb84111f11e2798e5, записанный в нотации FIPS197. В байтовом отображении мы получим 16 2-х разрядных шестнадцатеричных чисел “d4 bf 5d 30 e0 b4 52 ae b8 41 11 f1 1e 27 98 e5”. Здесь d4 – самый младший байт.

Запишем этот вектор в нотации Intel: e590271ef11141b8ae52b4e0305dbfd4, или побайтово “e5 90 27 1e f1 11 41 b8 ae 52 b4 e0 30 5d bf d4”. Двоичное 128-битное отображение таково:

1110010110011000001001110001111011110001000100010100000110111000

1010111001010010101101001110000000110000010111011011111111010100

(самый старший бит содержит 1, самый младший – 0)

Структуры данных AES в архитектуре Intel

Инструкции процессоров Intel позволяют оперировать одним или двумя 128-ми разрядными операндами. Типичный формат инструкции можно представить как “instruction xmm1 xmm2/m128”. Здесь xmm1, xmm2 – два произвольных регистра xmm, результат операции записывается в регистр xmm1; /m128 обозначает, что второй операнд является ячейкой памяти.

Обращаясь к содержимому регистра xmm, можно ссылаться на отдельные биты (индексы 127-0), байты (15-0), или 32-разрядные двойные слова (3-0). Байты могут также иметь и буквенную индексацию “P”-“A”, а двойные слова могут обозначаться как X3-X0. В таблице 1 показано, как в регистре соотносятся соответствующие биты, байты и слова.

Табл. 1. Биты, байты и двойные слова в регистре xmm

127-120

119-112

111-104

103-96

95-88

87-08

79-72

71-64

63-56

55-48

47-40

39-32

31-24

23-16

15-8

7-0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

3
(127-96)

2
(95-64)

1
(63-32)

0

(31-0)

X3

X2

X1

X0

P

O

N

M

L

K

J

I

H

G

F

E

D

C

B

A

4x4 матричное представление регистра xmm

A

E

I

M

B

F

J

N

C

G

K

O

D

H

L

P

Пример

В спецификации FIPS197 вектор d4bf5d30e0b452aeb84111f11e2798e5 (в формате Big Endian) имеет самым младшим байт d4, и самым старшим e5. Когда этот вектор приводят к формату Intel, то получается (указывая также и буквенную индексацию):

№ байта

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

P

O

N

M

L

K

J

I

H

G

F

E

D

C

B

A

e5

98

27

1e

f1

11

41

b8

ae

52

b4

e0

30

5d

bf

d4

Соответствующая матрица 4x4:

4x4 матричное представление регистра xmm

Вектор FIPS197, представленный в виде матрицы

A

E

I

M

d4

E0

b8

1e

B

F

J

N

Bf

B4

41

27

C

G

K

O

5d

52

11

98

D

H

L

P

30

ae

f1

e5

Алгоритм AES

Эта глава описывает функции и преобразования, определяемые стандартом AES. Следует отметить, что некоторые преобразования приведены в формате Little Endian, а не как в официальных документах FIPS197.

Ключ шифра

AES является симметричным алгоритмом шифрования с ключем. Ключ может иметь длину 128, 192 и 256 бит. Алгоритмы с ключем длиной 128, 192 и 256 бит обозначаются соответственно как AES-128, AES-192, AES-256.

“Текущее” состояние

Процесс шифрования (дешифрования) текста (шифра) в шифр (текст) производит промежуточные 128-битные результаты, которые мы будем обозначать как “текущие”.

Блоки данных

Алгоритм AES оперирует блоками по 128 бит как на входе, так и на выходе. В процессе обработки блоки в промежуточных состояниях мы будем обозначать как “текущие”.

Ключи раундов

Алгоритм AES (AES-128, AES192, AES-256) расширяет ключ шифра и получает 10, 12 или 14 ключей раундов. Каждый ключ раунда имеет длину 128 бит. Алгоритм получения ключа раунда называется “расширением ключа”.

AddRoundKey, добавление материала ключа

AddRoundKey (128-bit, 128-bit) является 128-битным преобразованием, которое заключается в побитовой операции XOR двух аргументов. В алгоритме AES аргументами выступают “текущий” блок и ключ раунда.

S-Box и InvS-Sbox

S-Box (Блок подстановки) это 8-битное преобразование, которое определяется как аффинная функция x -> A x-1 + b, где А – двоичная матрица 8х8, а b – 8-битный вектор, как показано на иллюстрации:

S-Box (блок подстановки)

Здесь ( )-1 обозначает инверсию над полем Галуа (конечным полем) GF(28), которое определяется полиномом x8+x4+x3+x+1 (для краткости 0x11b). Впоследствии мы будем называть это поле AES-GF256.

Матрица А и вектор b приведены к нотации Little Endian (и, следовательно, не идентичны соответствующим объектам в стандарте FIPS197)

InvS-Box является обратным преобразованием по отношению к S-Box и определяется как у->(A-1 y + A-1 b)-1:

InvS-Box

Таблицы подстановки для S-Box и InvS-Box

Преобразования S-Box и InvS-Box могут быть представлены в виде таблицы подстановки. Если на входе мы имеем байт B [7-0], а x и y – его старшая и младшая часть (x [3-0] = B [7-4], y [3-0] = B [3-0]), то на выходе байт получается кодированным в две шестнадцатиричные цифры. Например, применение таблицы подстановки S-Box для числа 85 (x=8; y=5 в шестнадцатиричном виде) дает на выходе шестнадцатиричное 97. А применение таблицы InvS-Box для 97 дает 85.

Табл. 2. Таблицы подстановки S-Box и InvS-Box

Таблица S-Box
ß------------------ y ---------------------->
0 1 2 3 4 5 6 7 8 9 a b c d e f
^ 0 63 7c 77 7b f2 6b 6f c5 30 01 67 2b fe d7 ab 76
| 1 ca 82 c9 7d fa 59 47 f0 ad d4 a2 af 9c a4 72 c0
| 2 b7 fd 93 26 36 3f f7 cc 34 a5 e5 f1 71 d8 31 15
| 3 04 c7 23 c3 18 96 05 9a 07 12 80 e2 eb 27 b2 75
| 4 09 83 2c 1a 1b 6e 5a a0 52 3b d6 b3 29 e3 2f 84
| 5 53 d1 00 ed 20 fc b1 5b 6a cb be 39 4a 4c 58 cf
6 d0 ef aa fb 43 4d 33 85 45 f9 02 7f 50 3c 9f a8
x 7 51 a3 40 8f 92 9d 38 f5 bc b6 da 21 10 ff f3 d2
8 cd 0c 13 ec 5f 97 44 17 c4 a7 7e 3d 64 5d 19 73
| 9 60 81 4f dc 22 2a 90 88 46 ee b8 14 de 5e 0b db
| a e0 32 3a 0a 49 06 24 5c c2 d3 ac 62 91 95 e4 79
| b e7 c8 37 6d 8d d5 4e a9 6c 56 f4 ea 65 7a ae 08
| c ba 78 25 2e 1c a6 b4 c6 e8 dd 74 1f 4b bd 8b 8a
| d 70 3e b5 66 48 03 f6 0e 61 35 57 b9 86 c1 1d 9e
| e e1 f8 98 11 69 d9 8e 94 9b 1e 87 e9 ce 55 28 df
V f 8c a1 89 0d bf e6 42 68 41 99 2d 0f b0 54 bb 16
Таблица InvS-Box
ß------------------ y ---------------------->
1 2 3 4 5 6 7 8 9 a b c d e f
^ 0 52 09 6a d5 30 36 a5 38 bf 40 a3 9e 81 f3 d7 fb
| 1 7c e3 39 82 9b 2f ff 87 34 8e 43 44 c4 de e9 cb
| 2 54 7b 94 32 a6 c2 23 3d ee 4c 95 0b 42 fa c3 4e
| 3 08 2e a1 66 28 d9 24 b2 76 5b a2 49 6d 8b d1 25
| 4 72 f8 f6 64 86 68 98 16 d4 a4 5c cc 5d 65 b6 92
| 5 6c 70 48 50 fd ed b9 da 5e 15 46 57 a7 8d 9d 84
6 90 d8 ab 00 8c bc d3 0a f7 e4 58 05 b8 b3 45 06
x 7 d0 2c 1e 8f ca 3f 0f 02 c1 af bd 03 01 13 8a 6b
8 3a 91 11 41 4f 67 dc ea 97 f2 cf ce f0 b4 e6 73
| 9 96 ac 74 22 e7 ad 35 85 e2 f9 37 e8 1c 75 df 6e
| a 47 f1 1a 71 1d 29 c5 89 6f b7 62 0e aa 18 be 1b
| b fc 56 3e 4b c6 d2 79 20 9a db c0 fe 78 cd 5a f4
| c 1f dd a8 33 88 07 c7 31 b1 12 10 59 27 80 ec 5f
| d 60 51 7f a9 19 b5 4a 0d 2d e5 7a 9f 93 c9 9c ef
| e a0 e0 3b 4d ae 2a f5 b0 c8 eb bb 3c 83 53 99 61
V f 17 2b 04 7e ba 77 d6 26 e1 69 14 63 55 21 0c 7d

Преобразование SubBytes

SubBytes является 16-байтовым преобразованием, которое заключается в применении преобразования S-Box к каждому из 16 байтов на входе, а конкретно

[P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A] à [S-Box (P), S-Box (O), S-Box (N), S-Box (M), S-Box (L), S-Box (K), S-Box (J), S-Box (I), S-Box (H), S-Box (G), S-Box (F), S-Box (E), S-Box (D), S-Box (C), S-Box (B), S-Box (A)].

Пример использования SubBytes

SubBytes (73744765635354655d5b56727b746f5d) = 8f92a04dfbed204d4c39b1402192a84c

Преобразование InvSubBytes

InvSubBytes является 16-байтовым преобразованием, которое заключается в применении преобразования InvS-Box к каждому из 16 байтов на входе, а конкретно

[P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A] à [InvS-Box (P), InvS-Box (O), InvS-Box (N), InvS-Box (M), InvS-Box (L), InvS-Box (K), InvS-Box (J), InvS-Box (I), InvS-Box (H), InvS-Box (G), InvS-Box (F), InvS-Box (E), InvS-Box (D), InvS-Box (C), InvS-Box (B), InvS-Box (A)].

Пример использования InvSubBytes

InvSubBytes (5d7456657b536f65735b47726374545d) = 8dcab9bc035006bc8f57161e00cafd8d)

Преобразование ShiftRows

ShiftRows является побайтовой перестановкой: (15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) à (11, 6, 1, 12, 7, 2, 13, 8, 3, 14, 9, 4, 15, 10, 5, 0). Если пользоваться буквенной индексацией, то получаем [P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A] à [L,G,B,M,H,C,N,I,D,O,J,E,P,K,F,A]. Название ShiftRows обозначает сдвиг строк в двумерном массиве на различные смещения и происходит от представления “текущего” блока в виде матрицы 4х4 байта. Первая строка массива остается без изменений, вторая циклично сдвигается влево на одну позицию (один байт), третья циклично сдвигается влево на две позиции, четвертая циклично сдвигается влево на три позиции.

Пример функционирования ShiftRows

ShiftRows (7b5b54657374566563746f725d53475d) = 73744765635354655d5b56727b746f5d

Преобразование InvShiftRows

InvShiftRows является побайтовой перестановкой, обратной по отношению к ShiftRows: (15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) à (3, 6, 9, 12, 15, 2, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0). Или, используя буквенную индексацию, [P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A] à [D,G,J,M,P,C,F,I,L,O,B,E,H,K,N,A]

Пример функционирования InvShiftRows

InvShiftRows (7b5b54657374566563746f725d53475d) = 5d7456657b536f65735b47726374545d

Преобразование MixColumns

MixColumns является 128-битным преобразованием, работающим со столбцами матрицы 4х4 байта, имеющейся на входе. Преобразование воспринимает каждый столбец матрицы как полином третьей степени с коэффициентами на поле AES-GF256. Каждый столбец матрицы “текущего” блока умножается на полином a(x) = {03}x3 + {01}x2 + {01}x + {02} по модулю x4 + 1. Здесь {--} обозначает элемент поля AES-GF256. Уравнения, определяющие данное преобразование, указаны в табл. 3. Преобразование имеет вид [P – A] à [P’ – A’]; символ • обозначает умножение в поле AES-GF256 (т.е. умножение без переноса по модулю 0x11b); символ + обозначает операцию XOR.

Табл. 3. Уравнения преобразования MixColumns

A' = ({02} • A) + ({03} • B) + C + D
B' = A + ({02} • B) + ({03} • C) + D
C' = A + B + ({02} • C) + ({03} • D)
D' = ({03} • A) + B + C + ({02} • D)
E' = ({02} • E) + ({03} • F) + G + H
F' = E + ({02} • F) + ({03} • G) + H
G' = E + F + ({02} • G) + ({03} • H)
H' = ({03} • E) + F + G + ({02} • H)
I' = ({02} • I) + ({03} • J) + K + L
J' = I + ({02} • J) + ({03} • K) + L
K' = I + J + ({02} • K) + ({03} • L)
L' = ({03} • I) + J + K + ({02} • L)
M' = ({02} • M) + ({03} • N) + O + P
N' = M + ({02} • N) + ({03} • O) + P
O' = M + N + ({02} • O) + ({03} • P)
P' = ({03} • M) + N + O + ({02} • P)

Пример действия MixColumns

MixColums (627a6f6644b109c82b18330a81c3b3e5) = 7b5b54657374566563746f725d53475d

Преобразование InvMixColumns

MixColumns является 128-битным преобразованием, работающим со столбцами матрицы 4х4 байта, поданной на вход. Преобразование воспринимает каждый столбец матрицы как полином третьей степени с коэффициентами на поле AES-GF256. Каждый столбец матрицы “текущего” блока умножается на полином a-1(x) = {0b}x3 + {0d}x2 + {09}x + {0e} по модулю x4 + 1. Уравнения, определяющие данное преобразование, представлены в табл. 4. Преобразование имеет вид [P – A] à [P’ – A’]; символ • обозначает умножение в поле AES-GF256 (т.е. умножение без переноса по модулю 0x11b); символ + обозначает операцию XOR.

Табл. 4. Уравнения преобразования InvMixColumns

A' = ({0e} • A) + ({0b} • B) + ({0d} • C) + ({09} • D)
B' = ({09} • A) + ({0e} • B) + ({0b} • C) + ({0d} • D)
C' = ({0d} • A) + ({09} • B) + ({0e} • C) + ({0b} • D)
D' = ({0b} • A) + ({0d} • B) + ({09} • C) + ({0e} • D)
E' = ({0e} • E) + ({0b} • F) + ({0d} • G) + ({09} • H)
F' = ({09} • E) + ({0e} • F) + ({0b} • G) + ({0d} • H)
G' = ({0d} • E) + ({09} • F) + ({0e} • G) + ({0b} • H)
H' = ({0b} • E) + ({0d} • F) + ({09} • G) + ({0e} • H)
I' = ({0e} • I) + ({0b} • J) + ({0d} • K) + ({09} • L)
J' = ({09} • I) + ({0e} • J) + ({0b} • K) + ({0d} • L)
K' = ({0d} • I) + ({09} • J) + ({0e} • K) + ({0b} • L)
L' = ({0b} • I) + ({0d} • J) + ({09} • K) + ({0e} • L)
M' = ({0e} • M) + ({0b} • N) + ({0d} • O) + ({09} • P)
N' = ({09} • M) + ({0e} • N) + ({0b} • O) + ({0d} • P)
O' = ({0d} • M) + ({09} • N) + ({0e} • O) + ({0b} • P)
P' = ({0b} • M) + ({0d} • N) + ({09} • O) + ({0e} • P)

Пример действия InvMixColumns

InvMixColumns (8dcab9dc035006bc8f57161e00cafd8d) = d635a667928b5eaeeec9cc3bc55f5777

Преобразование SubWord

SubWord является преобразованием, работающим с двойными словами (четыре байта) и осуществляющее применение операции S-Box к каждому из четырех байтов на входе, а конкретно:

SubWord (X) = [S-Box(X[31-24]), S-Box(X[23-16]), S-Box(X[15-8]), S-Box(X[7-0])]

Пример действия SubWord

SubWord (73744765) = 8f92a04d

Преобразование RotWord

RotWord это преобразование, оперирующее двойными словами следующим образом:

RotWord (X [31-0]) = [X[7-0], X [31-24], X [23-16], X [15-8]]

(эквивалентная запись на языке C: RotWord(X) = (X >> 8) | (X << 24))

Пример действия RotWord

RotWord (3c4fcf09) = 093c4fcf

Round Constant (RCON)

Процедура расширения ключа использует 10 констант, называющихся Константами Раунда (в дальнейшем именуемых RCON). Константы определяются как RCON [i] = {02}i-1 for i=1, 2, …, 10, операции производятся над полем AES-GF256.

Каждое значение RCON является элементом поля AES-GF256 и представляется в виде байта. Все десять констант в шестнадцатиричном виде представляются как.

RCON [1] = 01, RCON [2] = 02, RCON [3] = 04, RCON [4] = 08, RCON [5] = 10,

RCON [6] = 20, RCON [7] = 40, RCON [8] = 80, RCON [9] = 1B, RCON [10] = 36.

В дальнейшем будем считать, что константы RCON имеют тип двойных слов и что старшие 24 бита в них всегда равны 0, т.е. RCON [7] = 00000040 (шестнадцатиричные).

Расширение ключа

Стандарт AES использует ключи длиной 128, 192 или 256 бит. Ключи расширяются соответственно в 10, 12 или 14 ключей раундов, с помощюю алгоритма расширения ключа. Каждый ключ раунда имеет длину 128 бит. Расширение ключа зависит только от ключа шифра и не зависит от шифруемых данных, следовательно, расширение ключа может производиться независимо от фазы шифрованиф/дешифрования. Ядром алгоритма расширения ключа является набор преобразований SubWord(RotWord(tmp)) и SubWord(tmp), и использование констант RCON. Рис. 5 содержит описание алгоритма расширения ключа (в синтаксисе псевдо-кода), переменные имеют тип двойных слов (doublewords), стандарт хранения данных – big-endian.

Рис. 5. Алгоритм расширения ключа AES (как он описан в FIP197)

Параметры
Nb = 4
Nk = число двойных слов в ключе шифра (4, 6, 8 для AES-128, AES-192, AES-256)
Nr = количество раундов в шифре (Nr=10, 12, 14 для AES-128, AES-192, AES-256)
Процедура KeyExpansion
KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk)
begin
word tmp
i = 0
while (i < Nk)
w[i] = word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3])
i = i+1
end while
i = Nk
while (i < Nb * (Nr+1)]
tmp = w[i-1]
if (i mod Nk = 0)
tmp = SubWord(RotWord(tmp)) xor RCON[i/Nk]
else
if (Nk > 6 and i mod Nk = 4)
tmp = SubWord(tmp)
end if
w[i] = w[i-Nk] xor tmp
i = i + 1
end while

Поток шифрования/дешифрования AES

Порядок преобразований

Преобразование SubBytes воздействует отдельно на каждый байт “текущего блока”, а преобразование ShiftRows – на его отдельные столбцы, следовательно, порядок применения этих преобразований не важен. Так же не важна и очередность преобразований InvShiftRows и InvSubBytes.

В дальнейшем будем считать, что ShiftRows прменяется перед SubBytes, а InvShiftRows – перед InvSubBytes.

Эквивалентное инверсное шифрование

Есть два пути дешифрования в AES: один называется “инверсное шифрование”, а другой – “эквивалентное инверсное шифрование”. Они различаются внутренним порядком инверсных трансформаций и способом получения ключей раундов.

Архитектура Intel больше подходит для “эквивалентного инверсного шифрования”.

Преимущество “эквивалентного” пути в том, что порядок следования операций при шифровании и дешифровании одинаков (за исключением того, что при дешифровании он обратный).

В процессе “эквивалентного инверсного шифрования” ключи раундов создаются следующим образом: получаются 10, 12 или 14 ключей раундов для прямого шифрования, затем каждый ключ подвергается преобразованию InvMixColumns. Естественно, в процессе дешифрования ключи используются в обратном порядке.

Потоки шифрования и дешифрования

Потоки шифрования и дешифрования используют расширенные ключи (вспомним, что расширенные ключи не зависят от шифруемых данных). Процедура шифрования и дешифрования является серией преобразований AES, работающих с 128-битным “текущим” блоком и ключем раунда. Продолжительность потока зависит от длины ключа шифра, а именно

AES-128 шифрование/дешифрование имеет 40 шагов

AES-192 шифрование/дешифрование имеет 48 шагов

AES-256 шифрование/дешифрование имеет 56 шагов

На Рис. 6 и 7 для обозначения разных потоков использован цветовой код. В приведенном псевдо-коде будем считать, что 10, 12 или 14 ключей раундов уже получены (расширены) из ключа шифра и сохранены в нужном порядке в массиве данных (Round_Key_Encrypt и Round_Key_Decrypt), и что элемент массива Round_Key_Encrypt [0] хранит первые 128 бит ключа шифра (для нулевого раунда, который заключается в проведении просто операции XOR).

Илл 6. Поток шифрования AES

;; Data –128-битный шифруемый блок. Ключи раундов сохранены в Round_Key_Encrypt
Tmp = Add Round Key (Data, Round_Key_Encrypt [0])
For round = 1-9 or 1-11 or 1-13:
Tmp = ShiftRows (Tmp)
Tmp = SubBytes (Tmp)
Tmp = MixColumns (Tmp)
Tmp = AddRoundKey (Tmp, Round_Key_Encrypt [round])
end loop
Tmp = ShiftRows (Tmp)
Tmp = SubBytes (Tmp)
Tmp = Add RoundKey (Tmp, Round_Key_Encrypt [10 or 12 or 14])
Result = Tmp

Илл 7. Поток дешифрования AES (используя метод “эквивалентного инверсного шифра”)

;; Data –128-битный дешифруемый блок. Ключи раундов сохранены в Round_Key_ Decrypt
Tmp = Add Round Key (Data, Round_Key_Decrypt [0])
For round = 1-9 or 1-11 or 1-13:
Tmp = InvShiftRows (Tmp)
Tmp = InvSubBytes (Tmp)
Tmp = InvMixColumns (Tmp)
Tmp = AddRoundKey (Tmp, Round_Key_Decrypt [round])
end loop
Tmp = InvShift Rows (Tmp)
Tmp = InvSubBytes (Tmp)
Tmp = AddRoundKey (Tmp, Round_Key_Decrypt [10 or 12 or 14])
Result = Tmp

Сторонние каналы ПО

В этой главе приводится краткое описание сторонних каналов информации, которые могут быть использованы для атаки на шифр, и объясняется, почему структура доступа к памяти может быть использованы для атаки на коды программ AES, использующих таблицы подстановки.

Что такое атака по сторонним признакам?

Сторонние каналы программного обеспечения – это некий набор уязвимостей, возникающих при работе современных компьютеров. Уязвимости могут быть использованы для атаки на криптографические приложения, работающие в многозадачном окружении.

Эти атаки используют то обстоятельство, что практически все современные коммерческие компьютеры запускают несколько задач на одном наборе оборудования. Некоторые современные научные публикации наглядно показывают, что многозадачные операционные системы, работающие на одном процессоре, могут иметь утечки сторонней информации, если в системе параллельно с работающей криптосистемой запущен непривилегированный сторонний процесс-шпион, который может собирать информацию о структуре доступа к памяти или особенностях выполнения процессов.

Кэш процессора и основы атаки на кэш

Применение кэш-памяти – широко используемая технология оптимизации работы современных процессоров. Для кэша используется быстрая (и дорогая) память, которая обеспечивает скоростной доступ к данным, гораздо быстрее, чем обычная память. Процессор использует кэш-память для хранения данных из областей памяти, к которым было обращение. Таким образом, при каждом обращении к памяти процессор сначала проверяет наличие требуемых данных в кэше, и если они там оказываются (cache hit), доступ к ним оказыватся очень быстрым.. Если требумых данных там не оказывается (cache miss), то они прочитываются (довольно медленно) из основной памяти и сохраняются в кэше для возможного использования в будущем. Естественно, чтобы сохранить новые данные, процессор должен очистить место и выгрузить из кэша некие предыдущие данные. Как результат использования кэша, среднее время доступа к некоторым областям памяти существенно сокращается, и зловредный код может это определить и использовать, в случае если криптографическое приложение имеет уязвимую структуру доступа к памяти.

Таблицы подстановки и возможные уязвимости.

В настоящее время наиболее производительные реализации алгоритма AES используют большие таблицы подстановки (например, Gladmans или OpenSSL). Обычно программы используют пять таблиц подстановки. Доступ к этим таблицам зависит от ключа и шифруемых данных, открывается сторонний канал информации.

Для проведения атаки необходим сторонний шпионский процесс, запущенный в системе параллельно с программой шифрования. Этот процесс заполняет кэш своими данными и затем обращается к ним. Измеряя время доступа, шпион определяет, какие области памяти были исключены из кэша, и по этой информации можно определить, к каким областям обращался шифрующий процесс. Анализ этих областей может привести к раскрытию секретного ключа (на самом деле, первый и последний раунды дают самую большую утечку информации о ключе). Для получения детальной информации об атаках по сторонним каналам можно обратиться к следующим (среди многих) источникам: D. A. Osvik, A. Shamir, and E. Tromer, “Cache Attacks and Countermeasures: The Case of AES”, Lecture Notes in Computer Science series, Springer-Verlag, 3860: 1-20, (2006), а также D. J. Bernstein, "Cache-timing attacks on AES" (2005).

Ослабление возможностей атаки на AES уменьшает производительность алгоритма.

Есть способы написать реализующую AES программу таким способом, который исключит существенную зависимость структуры доступа к памяти от ключа и шифруемых данных. Один из таких способов – периодически менять таблицы подстановки местами. Однако такие защитные меры не даются даром, в случае алгоритма AES они существенно снижают его производительность. За подробностями можно обратиться к работе E. Brickell, E., G. Graunke, M. Neve, J. P. Seifert, “Software mitigations to hedge AES against cache based software side channel vulnerabilities”. Другой способ -- вообще не пользоваться таблицами подстановки, но опять же существенно страдает производительность. Подробности в работе M. Matsui and S. Fukuda. “How to Maximize Software Performance of Symmetric Primitives on Pentium III and 4 Processors”. LNCS, Springer Verlag, 3557: 398–412 (2005).

Новые AES инструкции процессоров Intel увеличивают защищенность алгоритмов AES от атак с помощью сторонних утечек информации.

Новый AES набор инструкций процессоров Intel позволяет производить быстрое шифрование/дешифрование существенно снижая при этом риск атаки с помощью сторонних каналов информации. Все операции имеют фиксированное и независимое от данных время исполнения. Более того, все вычисления выполняются исключительно аппаратно. Таким образом, операции шифрования и дешифрования, а также расширения ключа имеют фиксированное время исполнения и не требуют доступа к памяти. Как результат, исчезает опасность утечки информации с помощью наблюдения за доступом процессов к памяти.

AES архитектура Intel

Набор инструкций AES состоит из шести команд.

Четыре инструкции AESENC (AES Encrypt Round), AESENCLAST (AES Encrypt Last Round), AESDEC (AES Decrypt Round), AESDECLAST (AES Decrypt Last Round) реализуют шифрование и дешифрование данных. Инструкции имеют формат как регистр-регистр, так и регистр-память.

Две другие инструкции, AESIMC (AES Inverse Mix Columns) и AESKEYGENASSIST (AES Key Generation Assist), работают с расширением ключа.

Четыре инструкции раундов

Инструкции AESENC, AESENCLAST, AESDEC, AESDECLAST можно описать приведенным ниже псевдо-кодом. Эти инструкции выполняют набор групповых преобразований, который соответствует потокам шифрования и дешифрования AES.

Рис. 8. Инструкции AESENC и AESENCLAST

AESENC xmm1, xmm2/m128

Tmp := xmm1;

Round Key := xmm2/m128;

Tmp := ShiftRows (Tmp);

Tmp := SubBytes (Tmp);

Tmp := MixColumns (Tmp);

xmm1 := Tmp xor Round Key

AESENCLAST xmm1, xmm2/m128

Tmp := xmm1;

Round Key := xmm2/m128;

Tmp := Shift Rows (Tmp);

Tmp := SubBytes (Tmp);

xmm1 := Tmp xor Round Key

Рис. 9. Инструкции AESDEC и AESDECLAST

AESDEC xmm1, xmm2/m128

Tmp := xmm1;

Round Key := xmm2/m128;

Tmp := InvShift Rows (Tmp);

Tmp := InvSubBytes (Tmp);

Tmp := InvMix Columns (Tmp);

xmm1 := Tmp xor Round Key

AESDECLAST xmm1, xmm2/m128

State := xmm1;

Round Key := xmm2/m128

Tmp := InvShift Rows (State);

Tmp := InvSubBytes (Tmp);

xmm1 := := Tmp xor Round Key

Пример использования AESENC

Рис. 10. Пример AESENC

;; xmm1 и xmm2 содержат два входных 128-битных блока (xmm1 = текущий; xmm2 = ключ раунда)
;; результат сохраняется в xmm1
xmm1 = 7b5b54657374566563746f725d53475d xmm2 = 48692853686179295b477565726f6e5d
результат выполнения инструкции AESENC: a8311c2f9fdba3c58b104b58ded7e595

Пример AESENCLAST

Рис. 11. Пример AESENCLAST

;; xmm1 и xmm2 содержат два входных 128-битных блока (xmm1 = текущий; xmm2 = ключ раунда)
;; результат сохраняется в xmm1
xmm1 = 7b5b54657374566563746f725d53475d xmm2 = 48692853686179295b477565726f6e5d
результат AESENCLAST: c7fb881e938c5964177ec42553fdc611

Пример AESEDEC

Рис. 12. Пример AESDEC

;; xmm1 и xmm2 содержат два входных 128-битных блока (xmm1 = текущий; xmm2 = ключ раунда)
;; результат сохраняется в xmm1
xmm1 = 7b5b54657374566563746f725d53475d xmm2 = 48692853686179295b477565726f6e5d
результат AESDEC (в xmm1): 138ac342faea2787b58eb95eb730392a

Пример AESDECLAST

Рис. 13. Пример AESDECLAST

;; xmm1 и xmm2 содержат два входных 128-битных блока (xmm1 = текущий; xmm2 = ключ раунда)
;; результат сохраняется в xmm1
xmm1 = 7b5b54657374566563746f725d53475d xmm2 = 48692853686179295b477565726f6e5d
результат AESDECLAST: c5a391ef6b317f95d410637b72a593d0

Потоки шифрования в терминах инструкций раундов AES

Потоки шифрования и дешифрования стандарта AES (см. Рис. 14 и 15) реализуются с помощью четырех инструкций раундов AES. Будем использовать цветовой код для различения разных потоков.с разными длинами ключа (128, 192, 256 бит). В приведенном псевдо-коде будем считать, что 10, 12 или 14 ключей раундов уже получены (расширены) из ключа шифра и сохранены в должном порядке в массив данных (Round_Key_Encrypt или Round_Key_Decrypt). Также примем, что элемент Round_Key_Encrypt [0] содержит первые 128 бит основного ключа (которые используются в нулевом раунде для побитовой операцией исключающего ИЛИ)

Рис. 14. Реализация AES шифрования с помощью инструкций AESENC/AESENCLAST

Tmp = AddRoundKey (Data, Round_Key_Encrypt [0])
For round = 1-9 or 1-11 or 1-13:
Tmp = AESENC (Tmp, Round_Key_Encrypt [round])
end loop
Tmp = AESENCLAST (Tmp, Round_Key_Encrypt [10 or 12 or 14])
Result = Tmp

Рис. 15. Реализация AES дешифрования (эквивалентное инверсное шифрование) с помощью инструкций AESDEC/AESDECLAST

Tmp = AddRoundKey (Data, Round_Key_Decrypt [0])
For round = 1-9 or 1-11 or 1-13:
Tmp = AESDEC (Tmp, Round_Key_Decrypt [round])
end loop
Tmp = AESDECLAST (Tmp, Round_Key_Decrypt [10 or 12 or 14])
Result = Tmp

Пример реализации шифрования AES-128

Приведенный ниже код осуществляет последовательность алгоритма шифрования AES-128.

Рис. 16. Пример шифрования AES-128

;; Последовательность шифрования
;; данные в xmm1. регистры xmm2 – xmm12 содежат ключи раундов.
;; По завершении xmm1 содержит результат шифрования
pxor xmm1, xmm2 ; Round 0 (Round 0)
aesenc xmm1, xmm3 ; Round 1
aesenc xmm1, xmm4 ; Round 2
aesenc xmm1, xmm5 ; Round 3
aesenc xmm1, xmm6 ; Round 4
aesenc xmm1, xmm7 ; Round 5
aesenc xmm1, xmm8 ; Round 6
aesenc xmm1, xmm9 ; Round 7
aesenc xmm1, xmm10 ; Round 8
aesenc xmm1, xmm11 ; Round 9
aesenclast xmm1, xmm12 ; Round 10

Пример дешифрования AES-192

Рис. 17. Использование инструкции AESIMC в AES-192

;; Последовательность дешифрования
;; данные в xmm1. Регистры xmm14 – xmm2 содержат ключи раундов.
;; По завершении - xmm1 содерит дешифрованный результат
pxor xmm1, xmm14 ; Round 0 (Round 0)
aesdec xmm1, xmm13 ; Round 1 (ключи употребляются в обратном порядке)
aesdec xmm1, xmm12 ; Round 2
aesdec xmm1, xmm11 ; Round 3
aesdec xmm1, xmm10 ; Round 4
aesdec xmm1, xmm9 ; Round 5
aesdec xmm1, xmm8 ; Round 6
aesdec xmm1, xmm7 ; Round 7
aesdec xmm1, xmm6 ; Round 8
aesdec xmm1, xmm5 ; Round 9
aesdec xmm1, xmm4 ; Round 10
aesdec xmm1, xmm3 ; Round 11
aesdeclast xmm1, xmm2 ; Round 12

Расширение ключа AES

Генерация ключей происходит с помощью двух инструкций: AESKEYGENASSIST генерирует ключи раундов для шифрования, AESIMC конвертирует полученные ключи в форму, пригодную для дешифрования.

Инструкция AESKEYGENASSIST

Рис. 18. Инструкция AESKEYGENASSIST

AESKEYGENASSIST xmm1, xmm2/m128, imm8
Tmp := xmm2/LOAD(m128)
X3[31-0] := Tmp[127-96];
X2[31-0] := Tmp[95-64];
X1[31-0] := Tmp[63-32];
X0[31-0] := Tmp[31-0];
RCON[7-0] := imm8;
xmm1 := [Rot (SubWord (X3)) ⊕ RCON, SubWord (X3), Rot (SubWord (X1)) ⊕ RCON, SubWord (X1)]

Примечание: “Doubleword ⊕ RCON" в Рис. 18 означает операцию [Byte3, Byte2, Byte1, Byte0] XOR [0, 0, 0, RCON], где Byte3, Byte2, Byte1, Byte0 -- байты соответствующего двойного слова.

Пример AESKEYGENASSIST

Рис. 19. Пример AESKEYGENASSIST

;; xmm2 содержит 128-битный входной блок; imm8 содержит значение RCON
;; результат сохраняется в xmm1
xmm2 = 3c4fcf098815f7aba6d2ae2816157e2b imm8 = 1
результат AESKEYGENASSIST (в xmm1): 01eb848beb848a013424b5e524b5e434

Генерация таблицы ключей с помощью AESKEYGENASSIST

Следующий код демонстрирует пример подготовки таблицы ключей AES-128 и последующей дешифровки. В следующих главах рассмотрены примеры с ключами большей длины.

Рис. 20.Расширение ключей AES-128

;#==========================
;# ;# Инициализация данных ;#
;#==========================
$data->data(<<'DATA');
key do 03c4fcf098815f7aba6d2ae2816157e2bh ; 128-битный ключ (FIPS doc)
keyex_addr: keyex

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;
;;
;; Подготовка таблицы ключей
;;
movaps xmm1, OWORD PTR key ; загрузка ключа
movaps OWORD PTR keyex, xmm1 ; Сохранение ключа в памяти с остальными расширенными ключами
mov rcx, OFFSET keyex_addr+16 ; установка адреса сохранения расширенного ключа
aeskeygenassist xmm2, xmm1, 0x1 ; Генерация ключа 1 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x2 ; Генерация ключа 2 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x4 ; Генерация ключа 3 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x8 ; Генерация ключа 4 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x10 ; Генерация ключа 5 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x20 ; Генерация ключа 6 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x40 ; Генерация ключа 7 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x80 ; Генерация ключа 8 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x1b ; Генерация ключа 9 раунда
call key_expansion_128
aeskeygenassist xmm2, xmm1, 0x36 ; Генерация ключа 10 раунда
call key_expansion_128
key_expansion_128:
mov rdx, rcx
pshufd xmm2, xmm2, 0b11111111
pxor xmm2, xmm1
movd eax, xmm2
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100101b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100110b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100111b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movaps xmm1, OWORD PTR [rdx]
ret

Приготовление ключей раундов для дешифрования с использованием AESIMC

Команда AESIMC используется для создания ключей раундов для дешифровки с помощью метода “эквивалентного инверсного шифрования”. Приведенный псевдо-код иллюстрирует работу этой инструкции.

Рис. 21. Инструция AESIMC

AESIMC xmm1, xmm2/m128
RoundKey := xmm2/m128;
xmm1 := InvMixColumns (RoundKey)

Команды AESDEC и AESDECLAST выполняют дешифрование данных с помощью метода “эквивалентного инверсного шифрования”. Для получения в процессе корректных ключей раундов, должна быть правильным образом подготовлена.таблица ключей дешифровки. Если считать, что таблица ключей шифровки уже существует в памяти в виде массива, таблица ключей для дешифровки легко создается с помощью инструкции AESIMC. Для этого каждый из 10/12/14 ключей раундов шифровки прогоняется через команду AESIMC и на выходе получается соответствующий ключ раунда дешифровки. Алгоритм дешифрования использует ключи в обратном порядке, так что ключи дешифровки должны сохраняться в массиве в обратном порядке (по отношению к массиву ключей шифрования).

Например, возьмем метод AES-128 и будем считать, что регистр xmm2 содержит ключ раунда 3. Тогда после выполнения команды AESIMC xmm1, xmm2, регистр xmm1 будет содержать ключ раунда 8 дешифрования.

Пример AESIMC

Рис. 22. Пример AESIMC

;; xmm2 содержит один 128-блок входных данных (xmm2 = ключ раунда)
;; результат сохраняется в xmm1
xmm2 = 48692853686179295b477565726f6e5d
результат AESIMC (в xmm1): 627a6f6644b109c82b18330a81c3b3e5

Генерация ключей раундов дешифрования AES-192

Следующий код показывает вариант подготовки таблицы ключей AES-192 и последующего дешифрования.

Рис. 23. Использование AESIMC в AES-192

;;
kjd
; Ключи раундов шифрования в регистрах xmm2 -- xmm14
; Ключи раундов обрабатываются командой aesimc
; Дешифрование использует преобразованные ключи раундов в обратной последовательности
;;
;; DECRYPTION
;;
aesimc xmm3, xmm3 ; Генерация ключей дешифрования
aesimc xmm4, xmm4 ; (с помощью команды Inverse Mix Columns)
aesimc xmm5, xmm5 ;
aesimc xmm6, xmm6 ;
aesimc xmm7, xmm7 ;
aesimc xmm8, xmm8 ;
aesimc xmm9, xmm9 ;
aesimc xmm10, xmm10 ;
aesimc xmm11, xmm11 ;
aesimc xmm12, xmm12 ;
aesimc xmm13, xmm13 ;
pxor xmm1, xmm14 ; Round 0 (операция XOR)
aesdec xmm1, xmm13 ; Round 1 (ключи берутся в обратном порядке)
aesdec xmm1, xmm12 ; Round 2
aesdec xmm1, xmm11 ; Round 3
aesdec xmm1, xmm10 ; Round 4
aesdec xmm1, xmm9 ; Round 5
aesdec xmm1, xmm8 ; Round 6
aesdec xmm1, xmm7 ; Round 7
aesdec xmm1, xmm6 ; Round 8
aesdec xmm1, xmm5 ; Round 9
aesdec xmm1, xmm4 ; Round 10
aesdec xmm1, xmm3 ; Round 11
aesdeclast xmm1, xmm2 ; Round 12

Модель программирования приложений

Расширения AES следуют тем же программным моделям, что и Intel SSE, Intel SSE2, Intel SSE3, Intel SSSE3 и Intel SSE4 (см. IA-32 Intel Architecture Software Developer’s Manual, Пособие для разработчиков программ для 32-разрядной архитектуры Intel, том 1). Операционные системы, поддерживающие расширения SSE, будут поддерживать и работу приложений с командами AES. То же относится и к последующим версиям SSE.

Определение поддержки процессором инструкций AES

Перед тем как приложение попытается использовать ниструкции AES (AESDEC, AESDECLAST, AESENC, AESENCLAST, AESIMC, AESKEYGENASSIST), оно должно убедиться, что центральный процессор эти инструкции поддерживает. Расширение AES поддерживается, если CPUID.01H:ECX.AES[бит 25] = 1.

 

Примеры кода

В этой главе приводятся три примера кодов для форматов AES-128, AES-192 и AES-256. Каждый пример демонстрирует полный набор команд для расширения ключа, шифрования и дешифрования.

Рис. 24. Расширение ключа, шифрование и дешифрование AES-128

;#==========================
;# ;# Инициализация данных ;#
;#==========================
$data->data(<<'DATA');
dec_data do 0340737e0a29831318d305a88a8f64332h ; шифруемые данные (FIPS doc)
key do 03c4fcf098815f7aba6d2ae2816157e2bh ; 128-битный ключ (FIPS doc)
enc_data do 0320b6a19978511dcfb09dc021d842539h ; ожидаемый зашифрованный результат (FIPS doc)
retdata do 000000000000000000000000000000000h ; место для хранения шифруемых данных
keyex_addr: keyex

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;

do 000000000000000000000000000000000h;
DATA
;#==========================
;# ;# Основной код ;#
;#==========================
$code->code(<<'CODE');
;; Разрешаем программное использование MMX2
mov rax, CR4 ; Устанавливаем бит 9 (OSFXSR) инвертируем бит 10
or rax, 0200h ; (OSMMEXCPT).
mov CR4, rax
mov eax, 01h ; Проверяем наличие поддержки процессора
cpuid
mov eax, 02000000h ; Проверяем, установлен ли бит 25
and eax, ecx
jz FAIL
;;
;; Подготовка таблицы ключей
;;
movaps xmm1, OWORD PTR key ; Загружаем ключ
movaps OWORD PTR keyex, xmm1 ; Сохраняем ключ с расширенными ключами
mov rcx, OFFSET keyex_addr+16 ; задаем ячейку для расширенного ключа
aeskeygen xmm2, xmm1, 0x1 ; Генерируем ключ раунда 1
call key_expansion
aeskeygen xmm2, xmm1, 0x2 ; Генерируем ключ раунда 2
call key_expansion
aeskeygen xmm2, xmm1, 0x4 ; Генерируем ключ раунда 3
call key_expansion
aeskeygen xmm2, xmm1, 0x8 ; Генерируем ключ раунда 4
call key_expansion

aeskeygen xmm2, xmm1, 0x10 ; Генерируем ключ раунда 5
call key_expansion
aeskeygen xmm2, xmm1, 0x20 ; Генерируем ключ раунда 6
call key_expansion
aeskeygen xmm2, xmm1, 0x40 ; Генерируем ключ раунда 7
call key_expansion
aeskeygen xmm2, xmm1, 0x80 ; Генерируем ключ раунда 8
call key_expansion
aeskeygen xmm2, xmm1, 0x1b ; Генерируем ключ раунда 9
call key_expansion
aeskeygen xmm2, xmm1, 0x36 ; Генерируем ключ раунда 10
call key_expansion
;;
;; БЛОК ШИФРОВАНИЯ
;;
movaps xmm1, OWORD PTR dec_data ; Загружаем данные
movapd xmm2, OWORD PTR keyex ; Загружаем ключи
movapd xmm3, OWORD PTR [keyex+0x10] ;
movapd xmm4, OWORD PTR [keyex+0x20] ;
movapd xmm5, OWORD PTR [keyex+0x30] ;
movapd xmm6, OWORD PTR [keyex+0x40] ;
movapd xmm7, OWORD PTR [keyex+0x50] ;
movapd xmm8, OWORD PTR [keyex+0x60] ;
movapd xmm9, OWORD PTR [keyex+0x70] ;
movapd xmm10, OWORD PTR [keyex+0x80] ;
movapd xmm11, OWORD PTR [keyex+0x90] ;
movapd xmm12, OWORD PTR [keyex+0xA0] ;
pxor xmm1, xmm2 ; Round 0 (XORing)
aesenc xmm1, xmm3 ; Round 1
aesenc xmm1, xmm4 ; Round 2
aesenc xmm1, xmm5 ; Round 3
aesenc xmm1, xmm6 ; Round 4
aesenc xmm1, xmm7 ; Round 5
aesenc xmm1, xmm8 ; Round 6
aesenc xmm1, xmm9 ; Round 7
aesenc xmm1, xmm10 ; Round 8
aesenc xmm1, xmm11 ; Round 9
aesenclast xmm1, xmm12 ; Round 10
;;
;; ПРОВЕРЯЕМ КОРРЕКТНОСТЬ РЕЗУЛЬТАТА
;;
movups OWORD PTR retdata, xmm1 ; Сохраняем зашифрованный блок
mov rax, QWORD PTR retdata ;
cmp rax, QWORD PTR enc_data ; Сравниваем старшие байты с эталоном
jne FAIL
mov rax, QWORD PTR [retdata+8] ;
cmp rax, QWORD PTR [enc_data+8] ; Сравниваем младшие байты с эталоном
jne FAIL
;; БЛОК ДЕШИФРОВАНИЯ
aesimc xmm3, xmm3 ; Генерируем ключи для дешифрования
aesimc xmm4, xmm4 ;
aesimc xmm5, xmm5 ;
aesimc xmm6, xmm6 ;
aesimc xmm7, xmm7 ;
aesimc xmm8, xmm8 ;
aesimc xmm9, xmm9 ;
aesimc xmm10, xmm10 ;
aesimc xmm11, xmm11 ;
pxor xmm1, xmm12 ; XORing
aesdec xmm1, xmm11 ; Round 1
aesdec xmm1, xmm10 ; Round 2
aesdec xmm1, xmm9 ; Round 3
aesdec xmm1, xmm8 ; Round 4
aesdec xmm1, xmm7 ; Round 5
aesdec xmm1, xmm6 ; Round 6
aesdec xmm1, xmm5 ; Round 7
aesdec xmm1, xmm4 ; Round 8
aesdec xmm1, xmm3 ; Round 9
aesdeclast xmm1, xmm2 ; Round 10
;;
;; ПРОВЕРЯЕМ КОРРЕКТНОСТЬ
;;
movdqu OWORD PTR retdata, xmm1 ; Сохраняем дешифрованные данные
mov rax, QWORD PTR retdata ;
cmp rax, QWORD PTR dec_data ; Сравниваем старшие байты с начальными данными
jne FAIL
mov rax, QWORD PTR [retdata+8] ;
cmp rax, QWORD PTR [dec_data+8] ; Сравниваем младшие байты с начальными данными
jne FAIL
mov ebx, 0acedh
hlt;
key_expansion:
mov rdx, rcx
pshufd xmm2, xmm2, 0b11111111
pxor xmm2, xmm1
movd eax, xmm2
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100101b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100110b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100111b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movaps xmm1, OWORD PTR [rdx]
ret
FAIL:
mov ebx, 0deadh
hlt
CODE

Рис. 25. Расширение ключа, шифрование, дешифрование AES-192

;#========================== ;# ;# Инициализация данных ;#
;#==========================
$data->data(<<'DATA');
dec_data do 0ffeeddccbbaa99887766554433221100h ; шифруемые данные (FIPS doc)
key do 00f0e0d0c0b0a09080706050403020100h ; 192-битный ключ (FIPS doc)
key_ do 000000000000000001716151413121110h
enc_data do 091710deca070af6ee0df4c86a47ca9ddh ; ожидаемый результат шифрования (FIPS doc)
retdata do 000000000000000000000000000000000h ; место для хранения данных
keyex_addr:

keyex do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;
DATA
;#========================== ;# ;# Основной код ;#
;#==========================
;; Разрешаем программное использование MMX2
mov rax, CR4 ; Устанавливаем бит 9 (OSFXSR) и инвертируем бит 10
or rax, 0200h ; (OSMMEXCPT).
mov CR4, rax
mov eax, 01h ; Проверяем поддержку расширения процессором
cpuid
mov eax, 02000000h ; Проверяем установлен ли бит 25
and eax, ecx
jz FAIL
;;
;; ПОСТРОЕНИЕ ТАБЛИЦЫ КЛЮЧЕЙ
;;
movdqu xmm1, OWORD PTR key ; загружаем основной ключ
movq xmm3, QWORD PTR key_
movdqu OWORD PTR keyex, xmm1 ; Сохраняем ключ с расширенными ключами
movq QWORD PTR [keyex + 0x10], xmm3
mov rcx, OFFSET keyex_addr+24 ; устанавливаем адрес таблицы ключей
aeskeygen xmm2, xmm3, 0x1 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x2 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x4 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x8 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x10 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x20 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x40 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x80 ; расширяем ключ
call key_expansion
;;
;; БЛОК ШИФРОВАНИЯ
;;
movdqu xmm1, OWORD PTR dec_data ; загружаем начальные данные
movdqu xmm2, OWORD PTR keyex ; загружаем ключи
movdqu xmm3, OWORD PTR [keyex+0x10] ;
movdqu xmm4, OWORD PTR [keyex+0x20] ;
movdqu xmm5, OWORD PTR [keyex+0x30] ;
movdqu xmm6, OWORD PTR [keyex+0x40] ;
movdqu xmm7, OWORD PTR [keyex+0x50] ;
movdqu xmm8, OWORD PTR [keyex+0x60] ;
movdqu xmm9, OWORD PTR [keyex+0x70] ;
movdqu xmm10, OWORD PTR [keyex+0x80] ;
movdqu xmm11, OWORD PTR [keyex+0x90] ;
movdqu xmm12, OWORD PTR [keyex+0xA0] ;
movdqu xmm13, OWORD PTR [keyex+0xB0] ;
movdqu xmm14, OWORD PTR [keyex+0xC0] ;
pxor xmm1, xmm2 ; XORing
aesenc xmm1, xmm3 ; Round 1
aesenc xmm1, xmm4 ; Round 2
aesenc xmm1, xmm5 ; Round 3
aesenc xmm1, xmm6 ; Round 4
aesenc xmm1, xmm7 ; Round 5
aesenc xmm1, xmm8 ; Round 6
aesenc xmm1, xmm9 ; Round 7
aesenc xmm1, xmm10 ; Round 8
aesenc xmm1, xmm11 ; Round 9
aesenc xmm1, xmm12 ; Round 10
aesenc xmm1, xmm13 ; Round 11
aesenclast xmm1, xmm14 ; Round 12
;;
;; ПРОВЕРЯЕМ РЕЗУЛЬТАТ
;;
movdqu OWORD PTR retdata, xmm1 ; Сохраняем шифрованные данные
mov rax, QWORD PTR retdata ;
cmp rax, QWORD PTR enc_data ; Сравниваем с ожидаемым результатом
; to the expected result
jne FAIL
mov rax, QWORD PTR [retdata+8] ;
cmp rax, QWORD PTR [enc_data+8] ; Comparing the LSB of the encrypted data
; to the expected result
jne FAIL
;;
;; БЛОК ДЕШИФРОВКИ
;;
aesimc xmm3, xmm3 ; Генерация ключей дешифровки
aesimc xmm4, xmm4 ; (обработка с помощью Inverse Mix Columns)
aesimc xmm5, xmm5 ;
aesimc xmm6, xmm6 ;
aesimc xmm7, xmm7 ;
aesimc xmm8, xmm8 ;
aesimc xmm9, xmm9 ;
aesimc xmm10, xmm10 ;
aesimc xmm11, xmm11 ;
aesimc xmm12, xmm12 ;
aesimc xmm13, xmm13 ;
pxor xmm1, xmm14 ; Round 0 (XORing)
aesdec xmm1, xmm13 ; Round 1 (ключи используются в обратной последовательности)
aesdec xmm1, xmm12 ; Round 2
aesdec xmm1, xmm11 ; Round 3
aesdec xmm1, xmm10 ; Round 4
aesdec xmm1, xmm9 ; Round 5
aesdec xmm1, xmm8 ; Round 6
aesdec xmm1, xmm7 ; Round 7
aesdec xmm1, xmm6 ; Round 8
aesdec xmm1, xmm5 ; Round 9
aesdec xmm1, xmm4 ; Round 10
aesdec xmm1, xmm3 ; Round 11
aesdeclast xmm1, xmm2 ; Round 12
;;
;; ПРОВЕРЯЕМ КОРРЕКТНОСТЬ
;;
movdqu OWORD PTR retdata, xmm1 ; Сохраняем расшифрованный блок
mov rax, QWORD PTR retdata ;
cmp rax, QWORD PTR dec_data ; Сравниваем блок с начальными данными
; to the original data
jne FAIL
mov rax, QWORD PTR [retdata+8] ;
cmp rax, QWORD PTR [dec_data+8] ; Comparing the LSB of the (new) decrypted data
; to the original data
jne FAIL
mov ebx, 0acedh
hlt;
key_expansion:
mov rdx, rcx
pshufd xmm2, xmm2, 001010101b
pxor xmm2, xmm1
movd eax, xmm2
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100101b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100110b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100111b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movd ebx, xmm3
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm3, xmm3, 011100101b
movd ebx, xmm3
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movdqu xmm1, OWORD PTR [rdx]
add rdx, 0x10
movq xmm3, QWORD PTR [rdx]
ret
FAIL:
mov ebx, 0deadh
hlt
CODE

Рис. 26. AES-256 – расширение кюча, шифрование, дешифрование

;#========================== ;# ;# Инициализация ;#
;#==========================
$data->data(<<'DATA');
dec_data do 0ffeeddccbbaa99887766554433221100h ; начальные данные (FIPS doc)
key do 00f0e0d0c0b0a09080706050403020100h ; начальные данные (FIPS doc)
key_ do 01f1e1d1c1b1a19181716151413121110h
enc_data do 08960494b9049fceabf456751cab7a28eh ; ожидаемый результат (FIPS doc)
retdata do 000000000000000000000000000000000h ; место для результата
keyex_addr:

keyex do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;

do 000000000000000000000000000000000h ;
DATA
;#========================== ;# ;# Основной код ;#
;#==========================
$code->code(<<'CODE');
;; Разрешаем использование MMX2
mov rax, CR4 ; Устанавливаем бит 9 (OSFXSR) и инвертируем бит 10
or rax, 0200h ; (OSMMEXCPT).
mov CR4, rax
mov eax, 01h ; Проверям поддержку расширений процессором
cpuid
mov eax, 02000000h ; Установлен ли бит 25?
and eax, ecx
jz FAIL
;;
;; Подготовка таблицы ключей
;;
movdqu xmm1, OWORD PTR key ; Загружаем ключ
movdqu xmm3, OWORD PTR key_
movdqu OWORD PTR keyex, xmm1 ; Сохраняем ключ в таблице
movdqu OWORD PTR [keyex + 0x10], xmm3
mov rcx, OFFSET keyex_addr+0x20 ; Устанавливаем адрес таблицы с ключами
aeskeygen xmm2, xmm3, 0x1 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x2 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x4 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x8 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x10 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x20 ; расширяем ключ
call key_expansion
aeskeygen xmm2, xmm3, 0x40 ; расширяем ключ
call key_expansion
;;
;; БЛОК ШИФРОВАНИЯ
;;
movdqu xmm1, OWORD PTR dec_data ; загружаем начальные данные
movdqu xmm2, OWORD PTR [keyex+0x10] ;
movdqu xmm3, OWORD PTR [keyex+0x20] ;
movdqu xmm4, OWORD PTR [keyex+0x30] ;
movdqu xmm5, OWORD PTR [keyex+0x40] ;
movdqu xmm6, OWORD PTR [keyex+0x50] ;
movdqu xmm7, OWORD PTR [keyex+0x60] ;
movdqu xmm8, OWORD PTR [keyex+0x70] ;
movdqu xmm9, OWORD PTR [keyex+0x80] ;
movdqu xmm10, OWORD PTR [keyex+0x90] ;
movdqu xmm11, OWORD PTR [keyex+0xA0] ;
movdqu xmm12, OWORD PTR [keyex+0xB0] ;
movdqu xmm13, OWORD PTR [keyex+0xC0] ;
movdqu xmm14, OWORD PTR [keyex+0xD0] ;
movdqu xmm15, OWORD PTR [keyex+0xE0] ;
pxor xmm1, OWORD PTR keyex ; Round 0 (XORing)
aesenc xmm1, xmm2 ; Round 1
aesenc xmm1, xmm3 ; Round 2
aesenc xmm1, xmm4 ; Round 3
aesenc xmm1, xmm5 ; Round 4
aesenc xmm1, xmm6 ; Round 5
aesenc xmm1, xmm7 ; Round 6
aesenc xmm1, xmm8 ; Round 7
aesenc xmm1, xmm9 ; Round 8
aesenc xmm1, xmm10 ; Round 9
aesenc xmm1, xmm11 ; Round 10
aesenc xmm1, xmm12 ; Round 11
aesenc xmm1, xmm13 ; Round 12
aesenc xmm1, xmm14 ; Round 13
aesenclast xmm1, xmm15 ; Round 14
;;
;; ПРОВЕРЯЕМ РЕЗУЛЬТАТ
;;
movdqu OWORD PTR retdata, xmm1 ; Сохраняем результат
mov rax, QWORD PTR retdata ;
cmp rax, QWORD PTR enc_data ; Сравниваем с ожидаемым результатом
jne FAIL
mov rax, QWORD PTR [retdata+8] ;
cmp rax, QWORD PTR [enc_data+8] ; Comparing the LSB of the encrypted data
jne FAIL
;;
;; БЛОК ДЕШИФРОВКИ
;;
aesimc xmm2, xmm2 ; Генерация ключей дешифровки
aesimc xmm3, xmm3 ; (обработка с помощью Inverse Mix Columns)
aesimc xmm4, xmm4 ;
aesimc xmm5, xmm5 ;
aesimc xmm6, xmm6 ;
aesimc xmm7, xmm7 ;
aesimc xmm8, xmm8 ;
aesimc xmm9, xmm9 ;
aesimc xmm10, xmm10 ;
aesimc xmm11, xmm11 ;
aesimc xmm12, xmm12 ;
aesimc xmm13, xmm13 ;
aesimc xmm14, xmm14 ;
pxor xmm1, xmm15 ; XORing
aesdec xmm1, xmm14 ; Round 1(ключи используются в обратной последовательности)
aesdec xmm1, xmm13 ; Round 2
aesdec xmm1, xmm12 ; Round 3
aesdec xmm1, xmm11 ; Round 4
aesdec xmm1, xmm10 ; Round 5
aesdec xmm1, xmm9 ; Round 6
aesdec xmm1, xmm8 ; Round 7
aesdec xmm1, xmm7 ; Round 8
aesdec xmm1, xmm6 ; Round 9
aesdec xmm1, xmm5 ; Round 10
aesdec xmm1, xmm4 ; Round 11
aesdec xmm1, xmm3 ; Round 12
aesdec xmm1, xmm2 ; Round 13
aesdeclast xmm1, OWORD PTR keyex ; Round 14
;;
;; ПРОВЕРЯЕМ РЕЗУЛЬТАТ
;;
movdqu OWORD PTR retdata, xmm1 ; Сохраняем шифрованные данные
mov rax, QWORD PTR retdata ;
cmp rax, QWORD PTR dec_data ; Сравниваем блок с начальными данными
jne FAIL
mov rax, QWORD PTR [retdata+8] ;
cmp rax, QWORD PTR [dec_data+8] ; Comparing the LSB of the new decrypted data
jne FAIL
mov ebx, 0acedh
hlt;
key_expansion:
mov rdx, rcx
pshufd xmm2, xmm2, 011111111b
pxor xmm2, xmm1
movd eax, xmm2
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100101b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100110b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100111b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movdqu xmm4, OWORD PTR [rdx]
aeskeygen xmm4, xmm4, 0
pshufd xmm4, xmm4, 011100110b
movd eax, xmm4
movd ebx, xmm3
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm3, xmm3, 011100101b
movd ebx, xmm3
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm3, xmm3, 011100110b
movd ebx, xmm3
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm3, xmm3, 011100111b
movd ebx, xmm3
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movdqu xmm1, OWORD PTR [rdx]
add rdx, 0x10
movdqu xmm3, OWORD PTR [rdx]
ret
FAIL:
mov ebx, 0deadh
hlt
CODE

Использование AES-NI в режиме параллельной обработки.

В этой главе объясняется, как производительность алгоритма AES может быть существенно увеличена с помощью использования приемов параллельного программирования. Посмотрите на код в Илл. 27, AES-128 шифрование в режиме ECB. В нем обрабатываются 8 блоков данных в регистрах xmm2-xmm9, и ключ раунда содержится в xmm1. В каждом раунде выполняется 8 инструкций над 8 разными блоками с одним и тем же ключем раунда. Затем загружается следующий ключ раунда. 8 блоков с кодированной информацией сохраняется в память, в готовности загрузить следующие 8 блоков. Таким образом получается, что программа параллельно обрабатывает 8 блоков данных, но порядок обработки отличается от порядка в примере, рассмотренном в предыдущей главе. Вместо того чтобы полностью шифровать один блок и потом переходить к следующему, код выполняет один раунд на всех восьми блоках с использование одного ключа раунда, затем переходит к следующему раунду с другим ключем. Такая циклично-реверсивная (“loop-reversal”) технология подходит для любых режимов параллельного выполнения, таких как CTR и расшифровка CBC (но не CBC шифрование).

TКонвейерный процессор подразумевает, что за каждый такт может обрабатываться одна инструкция AES, при условии готовности данных. В режиме параллельной обработки, с использованием инструкций AES и технологии loop-reversing, данные определенно будут готовы для обработки в (почти) каждом цикле.

Следующий довольно грубый тест производительности показывает выигрыш в скорости (пренебрегая временем на обращение к памяти). Примем, что время выполнения инструкций AES составляет L тактов, и L ≤ 8 (фактическая латентность инструкций AES составляет 6 тактов, и в этом примере они оперируют с 8 регистрами xmm). Тогда шифрование 8 блоков данных будет выполнено за (приблизительно) 88+L тактов (операция pxor выполняется за 1 такт). Следовательно, достигнутая производительность достигает (88+6)/8=12 тактов на блок (16B), что приближается к теоретическому пределу производительности. Этот упрощенный расчет не учитывает некоторые факторы (такие как время на загрузку и сохранение), но, тем не менее, эффект близок к полученной нами величине.

Рис. 27. AES-128 Параллельный режим обработки

;#========================== ;# ;# Инициализация ;#
;#==========================
$data->data(<<'DATA'); datablock ; Начальные данные
do 0340737e0a29831318d305a88a8f64331h ;
do 0340737e0a29831318d305a88a8f64332h ;
do 0340737e0a29831318d305a88a8f64333h ;
do 0340737e0a29831318d305a88a8f64334h ;
do 0340737e0a29831318d305a88a8f64335h ;
do 0340737e0a29831318d305a88a8f64336h ;
do 0340737e0a29831318d305a88a8f64337h ;
do 0340737e0a29831318d305a88a8f64338h ;
key do 03c4fcf098815f7aba6d2ae2816157e2bh ; 128-битный ключ
retdata do 000000000000000000000000000000000h ; место для результата
keyex_addr: keyex do 000000000000000000000000000000000h ;
DATA
;#========================== ;# ;# Основной код ;#
;#==========================
$code->code(<<'CODE');
;; Разрешаем использование MMX2
mov rax, CR4 ; Устанавливаем бит 9 (OSFXSR) и инвертируем бит 10
or rax, 0200h ; (OSMMEXCPT).
mov CR4, rax
mov eax, 01h ; Проверям поддержку расширений процессором
cpuid
mov eax, 02000000h ; Проверяем бит 25
and eax, ecx
; jz FAIL
;; СОСТАВЛЯЕМ ТАБЛИЦУ КЛЮЧЕЙ
movdqu xmm1, OWORD PTR key ; Загружаем ключ
movdqu OWORD PTR keyex, xmm1 ; Сохраняем ключ в таблице
mov rcx, OFFSET keyex_addr+16 ; Устанавливаем адрес таблицы с ключами
aeskeygen xmm2, xmm1, 0x1 ; Генерируем ключ раунда 1
call key_expansion_128
aeskeygen xmm2, xmm1, 0x2 ; Генерируем ключ раунда 2
call key_expansion_128
aeskeygen xmm2, xmm1, 0x4 ; Генерируем ключ раунда 3
call key_expansion_128
aeskeygen xmm2, xmm1, 0x8 ; Генерируем ключ раунда 4
call key_expansion_128
aeskeygen xmm2, xmm1, 0x10 ; Генерируем ключ раунда 5
call key_expansion_128
aeskeygen xmm2, xmm1, 0x20 ; Генерируем ключ раунда 6
call key_expansion_128
aeskeygen xmm2, xmm1, 0x40 ; Генерируем ключ раунда 7
call key_expansion_128
aeskeygen xmm2, xmm1, 0x80 ; Генерируем ключ раунда 8
call key_expansion_128
aeskeygen xmm2, xmm1, 0x1b ; Генерируем ключ раунда 9
call key_expansion_128
aeskeygen xmm2, xmm1, 0x36 ; Генерируем ключ раунда 10
call key_expansion_128
;;
;; БЛОК ШИФРОВАНИЯ
mov rdx, OFFSET keyex_addr
movdqu xmm1, OWORD PTR [rdx] ; Загружаем ключ
movdqu xmm2, OWORD PTR [datablock] ; загружаем блоки данных
movdqu xmm3, OWORD PTR [datablock+0x10] ;
movdqu xmm4, OWORD PTR [datablock+0x20] ;
movdqu xmm5, OWORD PTR [datablock+0x30] ;
movdqu xmm6, OWORD PTR [datablock+0x40] ;
movdqu xmm7, OWORD PTR [datablock+0x50] ;
movdqu xmm8, OWORD PTR [datablock+0x60] ;
movdqu xmm9, OWORD PTR [datablock+0x70] ;
pxor xmm2, xmm1 ; XORing
pxor xmm3, xmm1 ; XORing
pxor xmm4, xmm1 ; XORing
pxor xmm5, xmm1 ; XORing
pxor xmm6, xmm1 ; XORing
pxor xmm7, xmm1 ; XORing
pxor xmm8, xmm1 ; XORing
pxor xmm9, xmm1 ; XORing
mov ecx, 9
main_loop:
add rdx, 0x10
movdqu xmm1, OWORD PTR [rdx] ; Загружаем ключ
aesenc xmm2, xmm1 ; Шифрование
aesenc xmm3, xmm1 ;
aesenc xmm4, xmm1 ;
aesenc xmm5, xmm1 ;
aesenc xmm6, xmm1 ;
aesenc xmm7, xmm1 ;
aesenc xmm8, xmm1 ;
aesenc xmm9, xmm1 ;
loop main_loop
add rdx, 0x10
movdqu xmm1, OWORD PTR [rdx] ; Загружаем ключ
aesenclast xmm2, xmm1 ; Последний раунд
aesenclast xmm3, xmm1 ;
aesenclast xmm4, xmm1 ;
aesenclast xmm5, xmm1 ;
aesenclast xmm6, xmm1 ;
aesenclast xmm7, xmm1 ;
aesenclast xmm8, xmm1 ;
aesenclast xmm9, xmm1 ;

movdqu OWORD PTR [datablock], xmm2 ; сохраняем зашифрованные данные
movdqu OWORD PTR [datablock+0x10], xmm3 ;
movdqu OWORD PTR [datablock+0x20], xmm4 ;
movdqu OWORD PTR [datablock+0x30], xmm5 ;
movdqu OWORD PTR [datablock+0x40], xmm6 ;
movdqu OWORD PTR [datablock+0x50], xmm7 ;
movdqu OWORD PTR [datablock+0x60], xmm8 ;
movdqu OWORD PTR [datablock+0x70], xmm9 ;

mov ebx, 0acedh
hlt;
key_expansion_128:
mov rdx, rcx
pshufd xmm2, xmm2, 0b11111111
pxor xmm2, xmm1
movd eax, xmm2
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100101b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100110b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
pshufd xmm1, xmm1, 011100111b
movd ebx, xmm1
xor eax, ebx
mov DWORD PTR [rcx], eax
add rcx, 4
movdqu xmm1, OWORD PTR [rdx]
ret
FAIL:
mov ebx, 0deadh
hlt
CODE

Заключение

В этом документе описаны новые инструкции шифрования AES фирмы Intel, которые будут поддерживаться всеми процессорами этой фирмы начиная с 2009 года. AES является ведущим стандартом симметричного шифрования, который используется в широком диапазоне приложений, и постоянно растущий спрос на безопасность и приватность данных обеспечил его повсеместное применение. Отсюда следует и важность технологии, обеспечивающей высокую производительность и безопасность алгоритмов шифровния в бытовых процессорах. Представленная архитектура AES располагает шестью командами для шифрования, дешифрования и расширения ключа, в данном документе приведены детальные подробности их использования в программах. Вместе это дает всестороннее аппаратное решение для технологии AES, предоставляя высокую производительность, гибкость и безопасность в отношении атак по сторонним каналам.

Об авторе

Шэй Герон (Shay Gueron) является специалистом по архитектуре систем безопасности Группы “Мобильность” корпорации Intel и в настоящее время работает в Центре разработок в Израиле. Шэй интересуется прикладной безопасностью, криптографией и алгоритмами. Он получил степень кандидата наук в сфере прикладной математики в израильском институте технологий “Technion”, также является доцентом кафедры математики факультета науки и преподавания наук Университета Хайфы, Израиль.


ПРЕДСТАВЛЕННАЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ ИНФОРМАЦИЯ ПРИВОДИТСЯ ТОЛЬКО В СВЯЗИ С ПРОДУКТАМИ INTEL®. В НАСТОЯЩЕМ ДОКУМЕНТЕ НЕ СОДЕРЖИТСЯ НИКАКОЙ ЯВНОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ, КАК В СИЛУ ПРАВОВОЙ ПРЕЗУМПЦИИ ТАК И ИНЫХ ОСНОВАНИЙ, ЛИЦЕНЗИИ НА ЛЮБЫЕ ПРАВА IntelЛЕКТУАЛЬНОЙ СОБСТВЕННОСТИ. ЕСЛИ ИНОЕ НЕ УКАЗАНО В УСЛОВИЯХ И ПОЛОЖЕНИЯХ INTEL, ПРИМЕНИМЫХ К ПРОДАЖЕ ТАКИХ ПРОДУКТОВ, INTEL НЕ ПРИНИМАЕТ НА СЕБЯ НИКАКИХ ОБЯЗАТЕЛЬСТВ И ОТКАЗЫВАЕТСЯ ОТ ЛЮБЫХ ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ В СВЯЗИ С ПРОДАЖЕЙ И/ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОДУКТОВ INTEL, ВКЛЮЧАЯ ОБЯЗАТЕЛЬСТВА ИЛИ ГАРАНТИИ, КАСАЮЩИЕСЯ ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В ОПРЕДЕЛЕННЫХ ЦЕЛЯХ, ТОВАРНОГО СОСТОЯНИЯ, РАВНО КАК И ОТСУТСТВИЯ НАРУШЕНИЙ КАКИХ-ЛИБО ПАТЕНТОВ, АВТОРСКИХ ПРАВ ИЛИ ИНЫХ ПРАВ IntelЛЕКТУАЛЬНОЙ СОБСТВЕННОСТИ. Продукты Intel не предназначены для использования в медицинских системах, системах спасения или жизнеобеспечения, критических системах управления или безопасности, а также в системах ядерных объектов.

Intel вправе без уведомления в любое время вносить изменения в спецификации и описания продуктов. Проектировщики не должны руководствоваться наличием или отсутствием описания каких-либо функций, равно как и материалами с пометкой “ограничено” или “не определено”. Указанные материалы предназначены для дальнейшей доработки, и Intel не несет никакой ответственности за конфликты или несовместимости, связанные с возможными изменениями в таких материалах. Содержащаяся в настоящем документе информация может быть изменена без уведомления и не должна использоваться для окончательного утверждения проектов.

Данная техническая публикация, равно как и описываемое в ней программное обеспечение, предоставляется по лицензии и может быть использована или воспроизведена исключительно в соответствии с условиями лицензии. Содержащаяся в настоящем документе информация предоставляется только в ознакомительных целях, может быть изменена без уведомления, и не может быть истолкована как принятие каких-либо обязательств со стороны Intel Corporation. Intel Corporation не несет никакой ответственности и не принимает никаких обязательств в отношении любых ошибок или неточностей, возможных в настоящем документе или каком-либо программное обеспечении, предоставляемом в связи с настоящим документом.

Номерные обозначения процессоров Intel не являются показателем производительности. Номерные обозначения процессоров служат для разграничения внутри серии процессоров, а не между различными сериями процессоров. Дополнительные сведения доступны на странице www.intel.com/products/processor_number.

Представленное в настоящем документе кодовое наименование Sandy Bridge используется Intel только для идентификации находящегося в разработке продукта, технологии или услуги, которые еще поступили в открытую продажу, т.е. не были объявлены, запущены в производство или поставлены в торговую сеть. Оно не является “коммерческим” наименованием продуктов или услуг и не предназначено для использования в качестве товарного знака.

Копии документов, на которые в настоящем документе имеется ссылка под порядковым номером, а также другие публикации Intel, можно получить, обратившись по телефону 1-800-548-4725, или посетив веб-сайт Intel.

Intel, Intel Core, Pentium, и логотип Intel являются товарными знаками Intel Corporation в США и других странах.

*Прочие наименования и товарные знаки могут являться собственностью других владельцев.

Охраняется авторским правом © 2008, Intel Corporation. Все права защищены.