Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.17-rc2 307 lines 7.9 kB view raw
1// 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> 27#include <crypto/speck.h> 28#include <linux/bitops.h> 29#include <linux/crypto.h> 30#include <linux/init.h> 31#include <linux/module.h> 32 33/* Speck128 */ 34 35static __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 53void crypto_speck128_encrypt(const struct speck128_tfm_ctx *ctx, 54 u8 *out, const u8 *in) 55{ 56 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} 66EXPORT_SYMBOL_GPL(crypto_speck128_encrypt); 67 68static void speck128_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 69{ 70 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{ 76 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} 86EXPORT_SYMBOL_GPL(crypto_speck128_decrypt); 87 88static 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, 94 unsigned int keylen) 95{ 96 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} 137EXPORT_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} 144 145/* Speck64 */ 146 147static __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 165void crypto_speck64_encrypt(const struct speck64_tfm_ctx *ctx, 166 u8 *out, const u8 *in) 167{ 168 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} 178EXPORT_SYMBOL_GPL(crypto_speck64_encrypt); 179 180static void speck64_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) 181{ 182 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{ 188 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} 198EXPORT_SYMBOL_GPL(crypto_speck64_decrypt); 199 200static 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, 206 unsigned int keylen) 207{ 208 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} 240EXPORT_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} 247 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");