aesni: Implement 192-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 #define AES192_ROUNDS 12
23
24 typedef struct private_aesni_key_t private_aesni_key_t;
25
26 /**
27 * Private data of an aesni_key_t object.
28 */
29 struct private_aesni_key_t {
30
31 /**
32 * Public aesni_key_t interface.
33 */
34 aesni_key_t public;
35 };
36
37 /**
38 * Invert round encryption keys to get a decryption key schedule
39 */
40 static void reverse_key(aesni_key_t *this)
41 {
42 __m128i t[this->rounds + 1];
43 int i;
44
45 for (i = 0; i <= this->rounds; i++)
46 {
47 t[i] = this->schedule[i];
48 }
49 this->schedule[this->rounds] = t[0];
50 for (i = 1; i < this->rounds; i++)
51 {
52 this->schedule[this->rounds - i] = _mm_aesimc_si128(t[i]);
53 }
54 this->schedule[0] = t[this->rounds];
55
56 memwipe(t, sizeof(t));
57 }
58
59 /**
60 * Assist in creating a 128-bit round key
61 */
62 static __m128i assist128(__m128i a, __m128i b)
63 {
64 __m128i c;
65
66 b = _mm_shuffle_epi32(b ,0xff);
67 c = _mm_slli_si128(a, 0x04);
68 a = _mm_xor_si128(a, c);
69 c = _mm_slli_si128(c, 0x04);
70 a = _mm_xor_si128(a, c);
71 c = _mm_slli_si128(c, 0x04);
72 a = _mm_xor_si128(a, c);
73 a = _mm_xor_si128(a, b);
74
75 return a;
76 }
77
78 /**
79 * Expand a 128-bit key to encryption round keys
80 */
81 static void expand128(__m128i *key, __m128i *schedule)
82 {
83 __m128i t;
84
85 schedule[0] = t = _mm_loadu_si128(key);
86 schedule[1] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x01));
87 schedule[2] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x02));
88 schedule[3] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x04));
89 schedule[4] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x08));
90 schedule[5] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x10));
91 schedule[6] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x20));
92 schedule[7] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x40));
93 schedule[8] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x80));
94 schedule[9] = t = assist128(t, _mm_aeskeygenassist_si128(t, 0x1b));
95 schedule[10] = assist128(t, _mm_aeskeygenassist_si128(t, 0x36));
96 }
97
98 /**
99 * Assist in creating a 192-bit round key
100 */
101 static __m128i assist192(__m128i b, __m128i c, __m128i *a)
102 {
103 __m128i t;
104
105 b = _mm_shuffle_epi32(b, 0x55);
106 t = _mm_slli_si128(*a, 0x04);
107 *a = _mm_xor_si128(*a, t);
108 t = _mm_slli_si128(t, 0x04);
109 *a = _mm_xor_si128(*a, t);
110 t = _mm_slli_si128(t, 0x04);
111 *a = _mm_xor_si128(*a, t);
112 *a = _mm_xor_si128(*a, b);
113 b = _mm_shuffle_epi32(*a, 0xff);
114 t = _mm_slli_si128(c, 0x04);
115 t = _mm_xor_si128(c, t);
116 t = _mm_xor_si128(t, b);
117
118 return t;
119 }
120
121 /**
122 * return a[63:0] | b[63:0] << 64
123 */
124 static __m128i _mm_shuffle_i00(__m128i a, __m128i b)
125 {
126 return (__m128i)_mm_shuffle_pd((__m128d)a, (__m128d)b, 0);
127 }
128
129 /**
130 * return a[127:64] >> 64 | b[63:0] << 64
131 */
132 static __m128i _mm_shuffle_i01(__m128i a, __m128i b)
133 {
134 return (__m128i)_mm_shuffle_pd((__m128d)a, (__m128d)b, 1);
135 }
136
137 /**
138 * Expand a 192-bit encryption key to round keys
139 */
140 static void expand192(__m128i *key, __m128i *schedule)
141 {
142 __m128i t1, t2, t3;
143
144 schedule[0] = t1 = _mm_loadu_si128(key);
145 t2 = t3 = _mm_loadu_si128(key + 1);
146
147 t2 = assist192(_mm_aeskeygenassist_si128(t2, 0x1), t2, &t1);
148 schedule[1] = _mm_shuffle_i00(t3, t1);
149 schedule[2] = _mm_shuffle_i01(t1, t2);
150 t2 = t3 = assist192(_mm_aeskeygenassist_si128(t2, 0x2), t2, &t1);
151 schedule[3] = t1;
152
153 t2 = assist192(_mm_aeskeygenassist_si128(t2, 0x4), t2, &t1);
154 schedule[4] = _mm_shuffle_i00(t3, t1);
155 schedule[5] = _mm_shuffle_i01(t1, t2);
156 t2 = t3 = assist192(_mm_aeskeygenassist_si128(t2, 0x8), t2, &t1);
157 schedule[6] = t1;
158
159 t2 = assist192(_mm_aeskeygenassist_si128 (t2,0x10), t2, &t1);
160 schedule[7] = _mm_shuffle_i00(t3, t1);
161 schedule[8] = _mm_shuffle_i01(t1, t2);
162 t2 = t3 = assist192(_mm_aeskeygenassist_si128 (t2,0x20), t2, &t1);
163 schedule[9] = t1;
164
165 t2 = assist192(_mm_aeskeygenassist_si128(t2, 0x40), t2, &t1);
166 schedule[10] = _mm_shuffle_i00(t3, t1);
167 schedule[11] = _mm_shuffle_i01(t1, t2);
168 assist192(_mm_aeskeygenassist_si128(t2, 0x80), t2, &t1);
169 schedule[12] = t1;
170 }
171
172 METHOD(aesni_key_t, destroy, void,
173 private_aesni_key_t *this)
174 {
175 memwipe(this, sizeof(*this) + (this->public.rounds + 1) * AES_BLOCK_SIZE);
176 free(this);
177 }
178
179 /**
180 * See header
181 */
182 aesni_key_t *aesni_key_create(bool encrypt, chunk_t key)
183 {
184 private_aesni_key_t *this;
185 int rounds;
186
187 switch (key.len)
188 {
189 case 16:
190 rounds = AES128_ROUNDS;
191 break;
192 case 24:
193 rounds = AES192_ROUNDS;
194 break;
195 default:
196 return NULL;
197 }
198
199 INIT_EXTRA(this, (rounds + 1) * AES_BLOCK_SIZE,
200 .public = {
201 .destroy = _destroy,
202 .rounds = rounds,
203 },
204 );
205
206 switch (key.len)
207 {
208 case 16:
209 expand128((__m128i*)key.ptr, this->public.schedule);
210 break;
211 case 24:
212 expand192((__m128i*)key.ptr, this->public.schedule);
213 break;
214 default:
215 break;
216 }
217
218 if (!encrypt)
219 {
220 reverse_key(&this->public);
221 }
222
223 return &this->public;
224 }