aesni: Implement 128-bit key schedule
[strongswan.git] / src / libstrongswan / plugins / aesni / aesni_key.c
1 /*
2 * Copyright (C) 2015 Martin Willi
3 * Copyright (C) 2015 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "aesni_key.h"
17
18 /**
19 * Rounds used for each AES key size
20 */
21 #define AES128_ROUNDS 10
22
23 typedef struct private_aesni_key_t private_aesni_key_t;
24
25 /**
26 * Private data of an aesni_key_t object.
27 */
28 struct private_aesni_key_t {
29
30 /**
31 * Public aesni_key_t interface.
32 */
33 aesni_key_t public;
34 };
35
36 /**
37 * Invert round encryption keys to get a decryption key schedule
38 */
39 static void reverse_key(aesni_key_t *this)
40 {
41 __m128i t[this->rounds + 1];
42 int i;
43
44 for (i = 0; i <= this->rounds; i++)
45 {
46 t[i] = this->schedule[i];
47 }
48 this->schedule[this->rounds] = t[0];
49 for (i = 1; i < this->rounds; i++)
50 {
51 this->schedule[this->rounds - i] = _mm_aesimc_si128(t[i]);
52 }
53 this->schedule[0] = t[this->rounds];
54
55 memwipe(t, sizeof(t));
56 }
57
58 /**
59 * Assist in creating a 128-bit round key
60 */
61 static __m128i assist128(__m128i a, __m128i b)
62 {
63 __m128i c;
64
65 b = _mm_shuffle_epi32(b ,0xff);
66 c = _mm_slli_si128(a, 0x04);
67 a = _mm_xor_si128(a, c);
68 c = _mm_slli_si128(c, 0x04);
69 a = _mm_xor_si128(a, c);
70 c = _mm_slli_si128(c, 0x04);
71 a = _mm_xor_si128(a, c);
72 a = _mm_xor_si128(a, b);
73
74 return a;
75 }
76
77 /**
78 * Expand a 128-bit key to encryption round keys
79 */
80 static void expand128(__m128i *key, __m128i *schedule)
81 {
82 __m128i t;
83
84 schedule[0] = t = _mm_loadu_si128(key);
85 schedule[1] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x01));
86 schedule[2] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x02));
87 schedule[3] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x04));
88 schedule[4] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x08));
89 schedule[5] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x10));
90 schedule[6] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x20));
91 schedule[7] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x40));
92 schedule[8] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x80));
93 schedule[9] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x1b));
94 schedule[10] = assist128(t, _mm_aeskeygenassist_si128(t, 0x36));
95 }
96
97 METHOD(aesni_key_t, destroy, void,
98 private_aesni_key_t *this)
99 {
100 memwipe(this, sizeof(*this) + (this->public.rounds + 1) * AES_BLOCK_SIZE);
101 free(this);
102 }
103
104 /**
105 * See header
106 */
107 aesni_key_t *aesni_key_create(bool encrypt, chunk_t key)
108 {
109 private_aesni_key_t *this;
110 int rounds;
111
112 switch (key.len)
113 {
114 case 16:
115 rounds = AES128_ROUNDS;
116 break;
117 default:
118 return NULL;
119 }
120
121 INIT_EXTRA(this, (rounds + 1) * AES_BLOCK_SIZE,
122 .public = {
123 .destroy = _destroy,
124 .rounds = rounds,
125 },
126 );
127
128 switch (key.len)
129 {
130 case 16:
131 expand128((__m128i*)key.ptr, this->public.schedule);
132 break;
133 default:
134 break;
135 }
136
137 if (!encrypt)
138 {
139 reverse_key(&this->public);
140 }
141
142 return &this->public;
143 }