aes_ssse3_subr.c revision 1.1 1 /* $NetBSD: aes_ssse3_subr.c,v 1.1 2020/06/29 23:51:35 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(1, "$NetBSD: aes_ssse3_subr.c,v 1.1 2020/06/29 23:51:35 riastradh Exp $");
31
32 #include <sys/systm.h>
33
34 #include <lib/libkern/libkern.h>
35
36 #include "aes_ssse3_impl.h"
37
38 static inline __m128i
39 loadblock(const void *in)
40 {
41 return _mm_loadu_epi8(in);
42 }
43
44 static inline void
45 storeblock(void *out, __m128i block)
46 {
47 _mm_storeu_epi8(out, block);
48 }
49
50 void
51 aes_ssse3_enc(const struct aesenc *enc, const uint8_t in[static 16],
52 uint8_t out[static 16], uint32_t nrounds)
53 {
54 __m128i block;
55
56 block = loadblock(in);
57 block = aes_ssse3_enc1(enc, block, nrounds);
58 storeblock(out, block);
59 }
60
61 void
62 aes_ssse3_dec(const struct aesdec *dec, const uint8_t in[static 16],
63 uint8_t out[static 16], uint32_t nrounds)
64 {
65 __m128i block;
66
67 block = loadblock(in);
68 block = aes_ssse3_dec1(dec, block, nrounds);
69 storeblock(out, block);
70 }
71
72 void
73 aes_ssse3_cbc_enc(const struct aesenc *enc, const uint8_t in[static 16],
74 uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
75 uint32_t nrounds)
76 {
77 __m128i cv;
78
79 KASSERT(nbytes);
80
81 cv = loadblock(iv);
82 for (; nbytes; nbytes -= 16, in += 16, out += 16) {
83 cv ^= loadblock(in);
84 cv = aes_ssse3_enc1(enc, cv, nrounds);
85 storeblock(out, cv);
86 }
87 storeblock(iv, cv);
88 }
89
90 void
91 aes_ssse3_cbc_dec(const struct aesdec *dec, const uint8_t in[static 16],
92 uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
93 uint32_t nrounds)
94 {
95 __m128i iv0, cv, b;
96
97 KASSERT(nbytes);
98 KASSERT(nbytes % 16 == 0);
99
100 iv0 = loadblock(iv);
101 cv = loadblock(in + nbytes - 16);
102 storeblock(iv, cv);
103
104 for (;;) {
105 b = aes_ssse3_dec1(dec, cv, nrounds);
106 if ((nbytes -= 16) == 0)
107 break;
108 cv = loadblock(in + nbytes - 16);
109 storeblock(out + nbytes, b ^ cv);
110 }
111 storeblock(out, b ^ iv0);
112 }
113
114 static inline __m128i
115 aes_ssse3_xts_update(__m128i t)
116 {
117 const __m128i one = _mm_set_epi64x(1, 1);
118 __m128i s, m, c;
119
120 s = _mm_srli_epi64(t, 63); /* 1 if high bit set else 0 */
121 m = _mm_sub_epi64(s, one); /* 0 if high bit set else -1 */
122 m = _mm_shuffle_epi32(m, 0x4e); /* swap halves */
123 c = _mm_set_epi64x(1, 0x87); /* carry */
124
125 return _mm_slli_epi64(t, 1) ^ (c & ~m);
126 }
127
128 static int
129 aes_ssse3_xts_update_selftest(void)
130 {
131 static const struct {
132 uint32_t in[4], out[4];
133 } cases[] = {
134 [0] = { {1}, {2} },
135 [1] = { {0x80000000U,0,0,0}, {0,1,0,0} },
136 [2] = { {0,0x80000000U,0,0}, {0,0,1,0} },
137 [3] = { {0,0,0x80000000U,0}, {0,0,0,1} },
138 [4] = { {0,0,0,0x80000000U}, {0x87,0,0,0} },
139 [5] = { {0,0x80000000U,0,0x80000000U}, {0x87,0,1,0} },
140 };
141 unsigned i;
142 uint32_t t[4];
143 int result = 0;
144
145 for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
146 t[0] = cases[i].in[0];
147 t[1] = cases[i].in[1];
148 t[2] = cases[i].in[2];
149 t[3] = cases[i].in[3];
150 storeblock(t, aes_ssse3_xts_update(loadblock(t)));
151 if (t[0] != cases[i].out[0] ||
152 t[1] != cases[i].out[1] ||
153 t[2] != cases[i].out[2] ||
154 t[3] != cases[i].out[3]) {
155 printf("%s %u:"
156 " %"PRIx32" %"PRIx32" %"PRIx32" %"PRIx32"\n",
157 __func__, i, t[0], t[1], t[2], t[3]);
158 result = -1;
159 }
160 }
161
162 return result;
163 }
164
165 void
166 aes_ssse3_xts_enc(const struct aesenc *enc, const uint8_t in[static 16],
167 uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
168 uint32_t nrounds)
169 {
170 __m128i t, b;
171
172 KASSERT(nbytes);
173 KASSERT(nbytes % 16 == 0);
174
175 t = loadblock(tweak);
176 for (; nbytes; nbytes -= 16, in += 16, out += 16) {
177 b = t ^ loadblock(in);
178 b = aes_ssse3_enc1(enc, b, nrounds);
179 storeblock(out, t ^ b);
180 t = aes_ssse3_xts_update(t);
181 }
182 storeblock(tweak, t);
183 }
184
185 void
186 aes_ssse3_xts_dec(const struct aesdec *dec, const uint8_t in[static 16],
187 uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
188 uint32_t nrounds)
189 {
190 __m128i t, b;
191
192 KASSERT(nbytes);
193 KASSERT(nbytes % 16 == 0);
194
195 t = loadblock(tweak);
196 for (; nbytes; nbytes -= 16, in += 16, out += 16) {
197 b = t ^ loadblock(in);
198 b = aes_ssse3_dec1(dec, b, nrounds);
199 storeblock(out, t ^ b);
200 t = aes_ssse3_xts_update(t);
201 }
202 storeblock(tweak, t);
203 }
204
205 int
206 aes_ssse3_selftest(void)
207 {
208
209 if (aes_ssse3_xts_update_selftest())
210 return -1;
211
212 return 0;
213 }
214