blob: 58aa9f7f91f791e58ccc7e2e1ed54de5134ccce2 [file] [log] [blame]
Eric Biggersda7a0ab2018-02-14 10:42:19 -08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Speck: a lightweight block cipher
4 *
5 * Copyright (c) 2018 Google, Inc
6 *
7 * Speck has 10 variants, including 5 block sizes. For now we only implement
8 * the variants Speck128/128, Speck128/192, Speck128/256, Speck64/96, and
9 * Speck64/128. Speck${B}/${K} denotes the variant with a block size of B bits
10 * and a key size of K bits. The Speck128 variants are believed to be the most
11 * secure variants, and they use the same block size and key sizes as AES. The
12 * Speck64 variants are less secure, but on 32-bit processors are usually
13 * faster. The remaining variants (Speck32, Speck48, and Speck96) are even less
14 * secure and/or not as well suited for implementation on either 32-bit or
15 * 64-bit processors, so are omitted.
16 *
17 * Reference: "The Simon and Speck Families of Lightweight Block Ciphers"
18 * https://eprint.iacr.org/2013/404.pdf
19 *
20 * In a correspondence, the Speck designers have also clarified that the words
21 * should be interpreted in little-endian format, and the words should be
22 * ordered such that the first word of each block is 'y' rather than 'x', and
23 * the first key word (rather than the last) becomes the first round key.
24 */
25
26#include <asm/unaligned.h>
Eric Biggersc8c36412018-02-14 10:42:20 -080027#include <crypto/speck.h>
Eric Biggersda7a0ab2018-02-14 10:42:19 -080028#include <linux/bitops.h>
29#include <linux/crypto.h>
30#include <linux/init.h>
31#include <linux/module.h>
32
33/* Speck128 */
34
Eric Biggersda7a0ab2018-02-14 10:42:19 -080035static __always_inline void speck128_round(u64 *x, u64 *y, u64 k)
36{
37 *x = ror64(*x, 8);
38 *x += *y;
39 *x ^= k;
40 *y = rol64(*y, 3);
41 *y ^= *x;
42}
43
44static __always_inline void speck128_unround(u64 *x, u64 *y, u64 k)
45{
46 *y ^= *x;
47 *y = ror64(*y, 3);
48 *x ^= k;
49 *x -= *y;
50 *x = rol64(*x, 8);
51}
52
Eric Biggersc8c36412018-02-14 10:42:20 -080053void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx,
54 u8 *out, const u8 *in)
Eric Biggersda7a0ab2018-02-14 10:42:19 -080055{
Eric Biggersda7a0ab2018-02-14 10:42:19 -080056 u64 y = get_unaligned_le64(in);
57 u64 x = get_unaligned_le64(in + 8);
58 int i;
59
60 for (i = 0; i < ctx->nrounds; i++)
61 speck128_round(&x, &y, ctx->round_keys[i]);
62
63 put_unaligned_le64(y, out);
64 put_unaligned_le64(x, out + 8);
65}
Eric Biggersc8c36412018-02-14 10:42:20 -080066EXPORT_SYMBOL_GPL(crypto_speck128_encrypt);
Eric Biggersda7a0ab2018-02-14 10:42:19 -080067
Eric Biggersc8c36412018-02-14 10:42:20 -080068static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
Eric Biggersda7a0ab2018-02-14 10:42:19 -080069{
Eric Biggersc8c36412018-02-14 10:42:20 -080070 crypto_speck128_encrypt(crypto_tfm_ctx(tfm), out, in);
71}
72
73void crypto_speck128_decrypt(const struct speck128_tfm_ctx *ctx,
74 u8 *out, const u8 *in)
75{
Eric Biggersda7a0ab2018-02-14 10:42:19 -080076 u64 y = get_unaligned_le64(in);
77 u64 x = get_unaligned_le64(in + 8);
78 int i;
79
80 for (i = ctx->nrounds - 1; i >= 0; i--)
81 speck128_unround(&x, &y, ctx->round_keys[i]);
82
83 put_unaligned_le64(y, out);
84 put_unaligned_le64(x, out + 8);
85}
Eric Biggersc8c36412018-02-14 10:42:20 -080086EXPORT_SYMBOL_GPL(crypto_speck128_decrypt);
Eric Biggersda7a0ab2018-02-14 10:42:19 -080087
Eric Biggersc8c36412018-02-14 10:42:20 -080088static void speck128_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
89{
90 crypto_speck128_decrypt(crypto_tfm_ctx(tfm), out, in);
91}
92
93int crypto_speck128_setkey(struct speck128_tfm_ctx *ctx, const u8 *key,
Eric Biggersda7a0ab2018-02-14 10:42:19 -080094 unsigned int keylen)
95{
Eric Biggersda7a0ab2018-02-14 10:42:19 -080096 u64 l[3];
97 u64 k;
98 int i;
99
100 switch (keylen) {
101 case SPECK128_128_KEY_SIZE:
102 k = get_unaligned_le64(key);
103 l[0] = get_unaligned_le64(key + 8);
104 ctx->nrounds = SPECK128_128_NROUNDS;
105 for (i = 0; i < ctx->nrounds; i++) {
106 ctx->round_keys[i] = k;
107 speck128_round(&l[0], &k, i);
108 }
109 break;
110 case SPECK128_192_KEY_SIZE:
111 k = get_unaligned_le64(key);
112 l[0] = get_unaligned_le64(key + 8);
113 l[1] = get_unaligned_le64(key + 16);
114 ctx->nrounds = SPECK128_192_NROUNDS;
115 for (i = 0; i < ctx->nrounds; i++) {
116 ctx->round_keys[i] = k;
117 speck128_round(&l[i % 2], &k, i);
118 }
119 break;
120 case SPECK128_256_KEY_SIZE:
121 k = get_unaligned_le64(key);
122 l[0] = get_unaligned_le64(key + 8);
123 l[1] = get_unaligned_le64(key + 16);
124 l[2] = get_unaligned_le64(key + 24);
125 ctx->nrounds = SPECK128_256_NROUNDS;
126 for (i = 0; i < ctx->nrounds; i++) {
127 ctx->round_keys[i] = k;
128 speck128_round(&l[i % 3], &k, i);
129 }
130 break;
131 default:
132 return -EINVAL;
133 }
134
135 return 0;
136}
Eric Biggersc8c36412018-02-14 10:42:20 -0800137EXPORT_SYMBOL_GPL(crypto_speck128_setkey);
138
139static int speck128_setkey(struct crypto_tfm *tfm, const u8 *key,
140 unsigned int keylen)
141{
142 return crypto_speck128_setkey(crypto_tfm_ctx(tfm), key, keylen);
143}
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800144
145/* Speck64 */
146
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800147static __always_inline void speck64_round(u32 *x, u32 *y, u32 k)
148{
149 *x = ror32(*x, 8);
150 *x += *y;
151 *x ^= k;
152 *y = rol32(*y, 3);
153 *y ^= *x;
154}
155
156static __always_inline void speck64_unround(u32 *x, u32 *y, u32 k)
157{
158 *y ^= *x;
159 *y = ror32(*y, 3);
160 *x ^= k;
161 *x -= *y;
162 *x = rol32(*x, 8);
163}
164
Eric Biggersc8c36412018-02-14 10:42:20 -0800165void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx,
166 u8 *out, const u8 *in)
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800167{
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800168 u32 y = get_unaligned_le32(in);
169 u32 x = get_unaligned_le32(in + 4);
170 int i;
171
172 for (i = 0; i < ctx->nrounds; i++)
173 speck64_round(&x, &y, ctx->round_keys[i]);
174
175 put_unaligned_le32(y, out);
176 put_unaligned_le32(x, out + 4);
177}
Eric Biggersc8c36412018-02-14 10:42:20 -0800178EXPORT_SYMBOL_GPL(crypto_speck64_encrypt);
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800179
Eric Biggersc8c36412018-02-14 10:42:20 -0800180static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800181{
Eric Biggersc8c36412018-02-14 10:42:20 -0800182 crypto_speck64_encrypt(crypto_tfm_ctx(tfm), out, in);
183}
184
185void crypto_speck64_decrypt(const struct speck64_tfm_ctx *ctx,
186 u8 *out, const u8 *in)
187{
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800188 u32 y = get_unaligned_le32(in);
189 u32 x = get_unaligned_le32(in + 4);
190 int i;
191
192 for (i = ctx->nrounds - 1; i >= 0; i--)
193 speck64_unround(&x, &y, ctx->round_keys[i]);
194
195 put_unaligned_le32(y, out);
196 put_unaligned_le32(x, out + 4);
197}
Eric Biggersc8c36412018-02-14 10:42:20 -0800198EXPORT_SYMBOL_GPL(crypto_speck64_decrypt);
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800199
Eric Biggersc8c36412018-02-14 10:42:20 -0800200static void speck64_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
201{
202 crypto_speck64_decrypt(crypto_tfm_ctx(tfm), out, in);
203}
204
205int crypto_speck64_setkey(struct speck64_tfm_ctx *ctx, const u8 *key,
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800206 unsigned int keylen)
207{
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800208 u32 l[3];
209 u32 k;
210 int i;
211
212 switch (keylen) {
213 case SPECK64_96_KEY_SIZE:
214 k = get_unaligned_le32(key);
215 l[0] = get_unaligned_le32(key + 4);
216 l[1] = get_unaligned_le32(key + 8);
217 ctx->nrounds = SPECK64_96_NROUNDS;
218 for (i = 0; i < ctx->nrounds; i++) {
219 ctx->round_keys[i] = k;
220 speck64_round(&l[i % 2], &k, i);
221 }
222 break;
223 case SPECK64_128_KEY_SIZE:
224 k = get_unaligned_le32(key);
225 l[0] = get_unaligned_le32(key + 4);
226 l[1] = get_unaligned_le32(key + 8);
227 l[2] = get_unaligned_le32(key + 12);
228 ctx->nrounds = SPECK64_128_NROUNDS;
229 for (i = 0; i < ctx->nrounds; i++) {
230 ctx->round_keys[i] = k;
231 speck64_round(&l[i % 3], &k, i);
232 }
233 break;
234 default:
235 return -EINVAL;
236 }
237
238 return 0;
239}
Eric Biggersc8c36412018-02-14 10:42:20 -0800240EXPORT_SYMBOL_GPL(crypto_speck64_setkey);
241
242static int speck64_setkey(struct crypto_tfm *tfm, const u8 *key,
243 unsigned int keylen)
244{
245 return crypto_speck64_setkey(crypto_tfm_ctx(tfm), key, keylen);
246}
Eric Biggersda7a0ab2018-02-14 10:42:19 -0800247
248/* Algorithm definitions */
249
250static struct crypto_alg speck_algs[] = {
251 {
252 .cra_name = "speck128",
253 .cra_driver_name = "speck128-generic",
254 .cra_priority = 100,
255 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
256 .cra_blocksize = SPECK128_BLOCK_SIZE,
257 .cra_ctxsize = sizeof(struct speck128_tfm_ctx),
258 .cra_module = THIS_MODULE,
259 .cra_u = {
260 .cipher = {
261 .cia_min_keysize = SPECK128_128_KEY_SIZE,
262 .cia_max_keysize = SPECK128_256_KEY_SIZE,
263 .cia_setkey = speck128_setkey,
264 .cia_encrypt = speck128_encrypt,
265 .cia_decrypt = speck128_decrypt
266 }
267 }
268 }, {
269 .cra_name = "speck64",
270 .cra_driver_name = "speck64-generic",
271 .cra_priority = 100,
272 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
273 .cra_blocksize = SPECK64_BLOCK_SIZE,
274 .cra_ctxsize = sizeof(struct speck64_tfm_ctx),
275 .cra_module = THIS_MODULE,
276 .cra_u = {
277 .cipher = {
278 .cia_min_keysize = SPECK64_96_KEY_SIZE,
279 .cia_max_keysize = SPECK64_128_KEY_SIZE,
280 .cia_setkey = speck64_setkey,
281 .cia_encrypt = speck64_encrypt,
282 .cia_decrypt = speck64_decrypt
283 }
284 }
285 }
286};
287
288static int __init speck_module_init(void)
289{
290 return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
291}
292
293static void __exit speck_module_exit(void)
294{
295 crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
296}
297
298module_init(speck_module_init);
299module_exit(speck_module_exit);
300
301MODULE_DESCRIPTION("Speck block cipher (generic)");
302MODULE_LICENSE("GPL");
303MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
304MODULE_ALIAS_CRYPTO("speck128");
305MODULE_ALIAS_CRYPTO("speck128-generic");
306MODULE_ALIAS_CRYPTO("speck64");
307MODULE_ALIAS_CRYPTO("speck64-generic");