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

arm64/crypto: use crypto instructions to generate AES key schedule

This patch implements the AES key schedule generation using ARMv8
Crypto Instructions. It replaces the table based C implementation
in aes_generic.ko, which means we can drop the dependency on that
module.

Tested-by: Steve Capper <steve.capper@linaro.org>
Acked-by: Steve Capper <steve.capper@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>

authored by

Ard Biesheuvel and committed by
Will Deacon
12ac3efe 286fb1cc

+133 -11
+2 -3
arch/arm64/crypto/Kconfig
··· 27 27 tristate "AES core cipher using ARMv8 Crypto Extensions" 28 28 depends on ARM64 && KERNEL_MODE_NEON 29 29 select CRYPTO_ALGAPI 30 - select CRYPTO_AES 31 30 32 31 config CRYPTO_AES_ARM64_CE_CCM 33 32 tristate "AES in CCM mode using ARMv8 Crypto Extensions" 34 33 depends on ARM64 && KERNEL_MODE_NEON 35 34 select CRYPTO_ALGAPI 36 - select CRYPTO_AES 35 + select CRYPTO_AES_ARM64_CE 37 36 select CRYPTO_AEAD 38 37 39 38 config CRYPTO_AES_ARM64_CE_BLK 40 39 tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions" 41 40 depends on ARM64 && KERNEL_MODE_NEON 42 41 select CRYPTO_BLKCIPHER 43 - select CRYPTO_AES 42 + select CRYPTO_AES_ARM64_CE 44 43 select CRYPTO_ABLK_HELPER 45 44 46 45 config CRYPTO_AES_ARM64_NEON_BLK
+3 -1
arch/arm64/crypto/aes-ce-ccm-glue.c
··· 16 16 #include <linux/crypto.h> 17 17 #include <linux/module.h> 18 18 19 + #include "aes-ce-setkey.h" 20 + 19 21 static int num_rounds(struct crypto_aes_ctx *ctx) 20 22 { 21 23 /* ··· 50 48 struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm); 51 49 int ret; 52 50 53 - ret = crypto_aes_expand_key(ctx, in_key, key_len); 51 + ret = ce_aes_expandkey(ctx, in_key, key_len); 54 52 if (!ret) 55 53 return 0; 56 54
+111 -1
arch/arm64/crypto/aes-ce-cipher.c
··· 14 14 #include <linux/crypto.h> 15 15 #include <linux/module.h> 16 16 17 + #include "aes-ce-setkey.h" 18 + 17 19 MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions"); 18 20 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 19 21 MODULE_LICENSE("GPL v2"); ··· 126 124 kernel_neon_end(); 127 125 } 128 126 127 + /* 128 + * aes_sub() - use the aese instruction to perform the AES sbox substitution 129 + * on each byte in 'input' 130 + */ 131 + static u32 aes_sub(u32 input) 132 + { 133 + u32 ret; 134 + 135 + __asm__("dup v1.4s, %w[in] ;" 136 + "movi v0.16b, #0 ;" 137 + "aese v0.16b, v1.16b ;" 138 + "umov %w[out], v0.4s[0] ;" 139 + 140 + : [out] "=r"(ret) 141 + : [in] "r"(input) 142 + : "v0","v1"); 143 + 144 + return ret; 145 + } 146 + 147 + int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, 148 + unsigned int key_len) 149 + { 150 + /* 151 + * The AES key schedule round constants 152 + */ 153 + static u8 const rcon[] = { 154 + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 155 + }; 156 + 157 + u32 kwords = key_len / sizeof(u32); 158 + struct aes_block *key_enc, *key_dec; 159 + int i, j; 160 + 161 + if (key_len != AES_KEYSIZE_128 && 162 + key_len != AES_KEYSIZE_192 && 163 + key_len != AES_KEYSIZE_256) 164 + return -EINVAL; 165 + 166 + memcpy(ctx->key_enc, in_key, key_len); 167 + ctx->key_length = key_len; 168 + 169 + kernel_neon_begin_partial(2); 170 + for (i = 0; i < sizeof(rcon); i++) { 171 + u32 *rki = ctx->key_enc + (i * kwords); 172 + u32 *rko = rki + kwords; 173 + 174 + rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0]; 175 + rko[1] = rko[0] ^ rki[1]; 176 + rko[2] = rko[1] ^ rki[2]; 177 + rko[3] = rko[2] ^ rki[3]; 178 + 179 + if (key_len == AES_KEYSIZE_192) { 180 + if (i >= 7) 181 + break; 182 + rko[4] = rko[3] ^ rki[4]; 183 + rko[5] = rko[4] ^ rki[5]; 184 + } else if (key_len == AES_KEYSIZE_256) { 185 + if (i >= 6) 186 + break; 187 + rko[4] = aes_sub(rko[3]) ^ rki[4]; 188 + rko[5] = rko[4] ^ rki[5]; 189 + rko[6] = rko[5] ^ rki[6]; 190 + rko[7] = rko[6] ^ rki[7]; 191 + } 192 + } 193 + 194 + /* 195 + * Generate the decryption keys for the Equivalent Inverse Cipher. 196 + * This involves reversing the order of the round keys, and applying 197 + * the Inverse Mix Columns transformation on all but the first and 198 + * the last one. 199 + */ 200 + key_enc = (struct aes_block *)ctx->key_enc; 201 + key_dec = (struct aes_block *)ctx->key_dec; 202 + j = num_rounds(ctx); 203 + 204 + key_dec[0] = key_enc[j]; 205 + for (i = 1, j--; j > 0; i++, j--) 206 + __asm__("ld1 {v0.16b}, %[in] ;" 207 + "aesimc v1.16b, v0.16b ;" 208 + "st1 {v1.16b}, %[out] ;" 209 + 210 + : [out] "=Q"(key_dec[i]) 211 + : [in] "Q"(key_enc[j]) 212 + : "v0","v1"); 213 + key_dec[i] = key_enc[0]; 214 + 215 + kernel_neon_end(); 216 + return 0; 217 + } 218 + EXPORT_SYMBOL(ce_aes_expandkey); 219 + 220 + int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, 221 + unsigned int key_len) 222 + { 223 + struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); 224 + int ret; 225 + 226 + ret = ce_aes_expandkey(ctx, in_key, key_len); 227 + if (!ret) 228 + return 0; 229 + 230 + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 231 + return -EINVAL; 232 + } 233 + EXPORT_SYMBOL(ce_aes_setkey); 234 + 129 235 static struct crypto_alg aes_alg = { 130 236 .cra_name = "aes", 131 237 .cra_driver_name = "aes-ce", ··· 245 135 .cra_cipher = { 246 136 .cia_min_keysize = AES_MIN_KEY_SIZE, 247 137 .cia_max_keysize = AES_MAX_KEY_SIZE, 248 - .cia_setkey = crypto_aes_set_key, 138 + .cia_setkey = ce_aes_setkey, 249 139 .cia_encrypt = aes_cipher_encrypt, 250 140 .cia_decrypt = aes_cipher_decrypt 251 141 }
+5
arch/arm64/crypto/aes-ce-setkey.h
··· 1 + 2 + int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, 3 + unsigned int key_len); 4 + int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, 5 + unsigned int key_len);
+12 -6
arch/arm64/crypto/aes-glue.c
··· 16 16 #include <linux/module.h> 17 17 #include <linux/cpufeature.h> 18 18 19 + #include "aes-ce-setkey.h" 20 + 19 21 #ifdef USE_V8_CRYPTO_EXTENSIONS 20 22 #define MODE "ce" 21 23 #define PRIO 300 24 + #define aes_setkey ce_aes_setkey 25 + #define aes_expandkey ce_aes_expandkey 22 26 #define aes_ecb_encrypt ce_aes_ecb_encrypt 23 27 #define aes_ecb_decrypt ce_aes_ecb_decrypt 24 28 #define aes_cbc_encrypt ce_aes_cbc_encrypt ··· 34 30 #else 35 31 #define MODE "neon" 36 32 #define PRIO 200 33 + #define aes_setkey crypto_aes_set_key 34 + #define aes_expandkey crypto_aes_expand_key 37 35 #define aes_ecb_encrypt neon_aes_ecb_encrypt 38 36 #define aes_ecb_decrypt neon_aes_ecb_decrypt 39 37 #define aes_cbc_encrypt neon_aes_cbc_encrypt ··· 85 79 struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); 86 80 int ret; 87 81 88 - ret = crypto_aes_expand_key(&ctx->key1, in_key, key_len / 2); 82 + ret = aes_expandkey(&ctx->key1, in_key, key_len / 2); 89 83 if (!ret) 90 - ret = crypto_aes_expand_key(&ctx->key2, &in_key[key_len / 2], 91 - key_len / 2); 84 + ret = aes_expandkey(&ctx->key2, &in_key[key_len / 2], 85 + key_len / 2); 92 86 if (!ret) 93 87 return 0; 94 88 ··· 294 288 .min_keysize = AES_MIN_KEY_SIZE, 295 289 .max_keysize = AES_MAX_KEY_SIZE, 296 290 .ivsize = AES_BLOCK_SIZE, 297 - .setkey = crypto_aes_set_key, 291 + .setkey = aes_setkey, 298 292 .encrypt = ecb_encrypt, 299 293 .decrypt = ecb_decrypt, 300 294 }, ··· 312 306 .min_keysize = AES_MIN_KEY_SIZE, 313 307 .max_keysize = AES_MAX_KEY_SIZE, 314 308 .ivsize = AES_BLOCK_SIZE, 315 - .setkey = crypto_aes_set_key, 309 + .setkey = aes_setkey, 316 310 .encrypt = cbc_encrypt, 317 311 .decrypt = cbc_decrypt, 318 312 }, ··· 330 324 .min_keysize = AES_MIN_KEY_SIZE, 331 325 .max_keysize = AES_MAX_KEY_SIZE, 332 326 .ivsize = AES_BLOCK_SIZE, 333 - .setkey = crypto_aes_set_key, 327 + .setkey = aes_setkey, 334 328 .encrypt = ctr_encrypt, 335 329 .decrypt = ctr_encrypt, 336 330 },