1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 26574e6c6SJussi Kivilinna /* 36574e6c6SJussi Kivilinna * Glue Code for assembler optimized version of 3DES 46574e6c6SJussi Kivilinna * 56574e6c6SJussi Kivilinna * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 66574e6c6SJussi Kivilinna * 76574e6c6SJussi Kivilinna * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 86574e6c6SJussi Kivilinna * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 96574e6c6SJussi Kivilinna * CTR part based on code (crypto/ctr.c) by: 106574e6c6SJussi Kivilinna * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> 116574e6c6SJussi Kivilinna */ 126574e6c6SJussi Kivilinna 1309c0f03bSEric Biggers #include <crypto/algapi.h> 14*cc1d24b9SArd Biesheuvel #include <crypto/des.h> 1509c0f03bSEric Biggers #include <crypto/internal/skcipher.h> 166574e6c6SJussi Kivilinna #include <linux/crypto.h> 176574e6c6SJussi Kivilinna #include <linux/init.h> 186574e6c6SJussi Kivilinna #include <linux/module.h> 196574e6c6SJussi Kivilinna #include <linux/types.h> 206574e6c6SJussi Kivilinna 216574e6c6SJussi Kivilinna struct des3_ede_x86_ctx { 22*cc1d24b9SArd Biesheuvel struct des3_ede_ctx enc; 23*cc1d24b9SArd Biesheuvel struct des3_ede_ctx dec; 246574e6c6SJussi Kivilinna }; 256574e6c6SJussi Kivilinna 266574e6c6SJussi Kivilinna /* regular block cipher functions */ 276574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk(const u32 *expkey, u8 *dst, 286574e6c6SJussi Kivilinna const u8 *src); 296574e6c6SJussi Kivilinna 306574e6c6SJussi Kivilinna /* 3-way parallel cipher functions */ 316574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst, 326574e6c6SJussi Kivilinna const u8 *src); 336574e6c6SJussi Kivilinna 346574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, 356574e6c6SJussi Kivilinna const u8 *src) 366574e6c6SJussi Kivilinna { 37*cc1d24b9SArd Biesheuvel u32 *enc_ctx = ctx->enc.expkey; 386574e6c6SJussi Kivilinna 396574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk(enc_ctx, dst, src); 406574e6c6SJussi Kivilinna } 416574e6c6SJussi Kivilinna 426574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, 436574e6c6SJussi Kivilinna const u8 *src) 446574e6c6SJussi Kivilinna { 45*cc1d24b9SArd Biesheuvel u32 *dec_ctx = ctx->dec.expkey; 466574e6c6SJussi Kivilinna 476574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk(dec_ctx, dst, src); 486574e6c6SJussi Kivilinna } 496574e6c6SJussi Kivilinna 506574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, 516574e6c6SJussi Kivilinna const u8 *src) 526574e6c6SJussi Kivilinna { 53*cc1d24b9SArd Biesheuvel u32 *enc_ctx = ctx->enc.expkey; 546574e6c6SJussi Kivilinna 556574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src); 566574e6c6SJussi Kivilinna } 576574e6c6SJussi Kivilinna 586574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, 596574e6c6SJussi Kivilinna const u8 *src) 606574e6c6SJussi Kivilinna { 61*cc1d24b9SArd Biesheuvel u32 *dec_ctx = ctx->dec.expkey; 626574e6c6SJussi Kivilinna 636574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src); 646574e6c6SJussi Kivilinna } 656574e6c6SJussi Kivilinna 666574e6c6SJussi Kivilinna static void des3_ede_x86_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 676574e6c6SJussi Kivilinna { 686574e6c6SJussi Kivilinna des3_ede_enc_blk(crypto_tfm_ctx(tfm), dst, src); 696574e6c6SJussi Kivilinna } 706574e6c6SJussi Kivilinna 716574e6c6SJussi Kivilinna static void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 726574e6c6SJussi Kivilinna { 736574e6c6SJussi Kivilinna des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src); 746574e6c6SJussi Kivilinna } 756574e6c6SJussi Kivilinna 7609c0f03bSEric Biggers static int ecb_crypt(struct skcipher_request *req, const u32 *expkey) 776574e6c6SJussi Kivilinna { 7809c0f03bSEric Biggers const unsigned int bsize = DES3_EDE_BLOCK_SIZE; 7909c0f03bSEric Biggers struct skcipher_walk walk; 806574e6c6SJussi Kivilinna unsigned int nbytes; 816574e6c6SJussi Kivilinna int err; 826574e6c6SJussi Kivilinna 8309c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 846574e6c6SJussi Kivilinna 8509c0f03bSEric Biggers while ((nbytes = walk.nbytes)) { 8609c0f03bSEric Biggers u8 *wsrc = walk.src.virt.addr; 8709c0f03bSEric Biggers u8 *wdst = walk.dst.virt.addr; 886574e6c6SJussi Kivilinna 896574e6c6SJussi Kivilinna /* Process four block batch */ 906574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 916574e6c6SJussi Kivilinna do { 926574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk_3way(expkey, wdst, 936574e6c6SJussi Kivilinna wsrc); 946574e6c6SJussi Kivilinna 956574e6c6SJussi Kivilinna wsrc += bsize * 3; 966574e6c6SJussi Kivilinna wdst += bsize * 3; 976574e6c6SJussi Kivilinna nbytes -= bsize * 3; 986574e6c6SJussi Kivilinna } while (nbytes >= bsize * 3); 996574e6c6SJussi Kivilinna 1006574e6c6SJussi Kivilinna if (nbytes < bsize) 1016574e6c6SJussi Kivilinna goto done; 1026574e6c6SJussi Kivilinna } 1036574e6c6SJussi Kivilinna 1046574e6c6SJussi Kivilinna /* Handle leftovers */ 1056574e6c6SJussi Kivilinna do { 1066574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk(expkey, wdst, wsrc); 1076574e6c6SJussi Kivilinna 1086574e6c6SJussi Kivilinna wsrc += bsize; 1096574e6c6SJussi Kivilinna wdst += bsize; 1106574e6c6SJussi Kivilinna nbytes -= bsize; 1116574e6c6SJussi Kivilinna } while (nbytes >= bsize); 1126574e6c6SJussi Kivilinna 1136574e6c6SJussi Kivilinna done: 11409c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 1156574e6c6SJussi Kivilinna } 1166574e6c6SJussi Kivilinna 1176574e6c6SJussi Kivilinna return err; 1186574e6c6SJussi Kivilinna } 1196574e6c6SJussi Kivilinna 12009c0f03bSEric Biggers static int ecb_encrypt(struct skcipher_request *req) 1216574e6c6SJussi Kivilinna { 12209c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 12309c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 1246574e6c6SJussi Kivilinna 125*cc1d24b9SArd Biesheuvel return ecb_crypt(req, ctx->enc.expkey); 1266574e6c6SJussi Kivilinna } 1276574e6c6SJussi Kivilinna 12809c0f03bSEric Biggers static int ecb_decrypt(struct skcipher_request *req) 1296574e6c6SJussi Kivilinna { 13009c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 13109c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 1326574e6c6SJussi Kivilinna 133*cc1d24b9SArd Biesheuvel return ecb_crypt(req, ctx->dec.expkey); 1346574e6c6SJussi Kivilinna } 1356574e6c6SJussi Kivilinna 13609c0f03bSEric Biggers static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx, 13709c0f03bSEric Biggers struct skcipher_walk *walk) 1386574e6c6SJussi Kivilinna { 1396574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 1406574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 1416574e6c6SJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 1426574e6c6SJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 1436574e6c6SJussi Kivilinna u64 *iv = (u64 *)walk->iv; 1446574e6c6SJussi Kivilinna 1456574e6c6SJussi Kivilinna do { 1466574e6c6SJussi Kivilinna *dst = *src ^ *iv; 1476574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 1486574e6c6SJussi Kivilinna iv = dst; 1496574e6c6SJussi Kivilinna 1506574e6c6SJussi Kivilinna src += 1; 1516574e6c6SJussi Kivilinna dst += 1; 1526574e6c6SJussi Kivilinna nbytes -= bsize; 1536574e6c6SJussi Kivilinna } while (nbytes >= bsize); 1546574e6c6SJussi Kivilinna 1556574e6c6SJussi Kivilinna *(u64 *)walk->iv = *iv; 1566574e6c6SJussi Kivilinna return nbytes; 1576574e6c6SJussi Kivilinna } 1586574e6c6SJussi Kivilinna 15909c0f03bSEric Biggers static int cbc_encrypt(struct skcipher_request *req) 1606574e6c6SJussi Kivilinna { 16109c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 16209c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 16309c0f03bSEric Biggers struct skcipher_walk walk; 16409c0f03bSEric Biggers unsigned int nbytes; 1656574e6c6SJussi Kivilinna int err; 1666574e6c6SJussi Kivilinna 16709c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 1686574e6c6SJussi Kivilinna 1696574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 17009c0f03bSEric Biggers nbytes = __cbc_encrypt(ctx, &walk); 17109c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 1726574e6c6SJussi Kivilinna } 1736574e6c6SJussi Kivilinna 1746574e6c6SJussi Kivilinna return err; 1756574e6c6SJussi Kivilinna } 1766574e6c6SJussi Kivilinna 17709c0f03bSEric Biggers static unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx, 17809c0f03bSEric Biggers struct skcipher_walk *walk) 1796574e6c6SJussi Kivilinna { 1806574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 1816574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 1826574e6c6SJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 1836574e6c6SJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 1846574e6c6SJussi Kivilinna u64 ivs[3 - 1]; 1856574e6c6SJussi Kivilinna u64 last_iv; 1866574e6c6SJussi Kivilinna 1876574e6c6SJussi Kivilinna /* Start of the last block. */ 1886574e6c6SJussi Kivilinna src += nbytes / bsize - 1; 1896574e6c6SJussi Kivilinna dst += nbytes / bsize - 1; 1906574e6c6SJussi Kivilinna 1916574e6c6SJussi Kivilinna last_iv = *src; 1926574e6c6SJussi Kivilinna 1936574e6c6SJussi Kivilinna /* Process four block batch */ 1946574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 1956574e6c6SJussi Kivilinna do { 1966574e6c6SJussi Kivilinna nbytes -= bsize * 3 - bsize; 1976574e6c6SJussi Kivilinna src -= 3 - 1; 1986574e6c6SJussi Kivilinna dst -= 3 - 1; 1996574e6c6SJussi Kivilinna 2006574e6c6SJussi Kivilinna ivs[0] = src[0]; 2016574e6c6SJussi Kivilinna ivs[1] = src[1]; 2026574e6c6SJussi Kivilinna 2036574e6c6SJussi Kivilinna des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src); 2046574e6c6SJussi Kivilinna 2056574e6c6SJussi Kivilinna dst[1] ^= ivs[0]; 2066574e6c6SJussi Kivilinna dst[2] ^= ivs[1]; 2076574e6c6SJussi Kivilinna 2086574e6c6SJussi Kivilinna nbytes -= bsize; 2096574e6c6SJussi Kivilinna if (nbytes < bsize) 2106574e6c6SJussi Kivilinna goto done; 2116574e6c6SJussi Kivilinna 2126574e6c6SJussi Kivilinna *dst ^= *(src - 1); 2136574e6c6SJussi Kivilinna src -= 1; 2146574e6c6SJussi Kivilinna dst -= 1; 2156574e6c6SJussi Kivilinna } while (nbytes >= bsize * 3); 2166574e6c6SJussi Kivilinna } 2176574e6c6SJussi Kivilinna 2186574e6c6SJussi Kivilinna /* Handle leftovers */ 2196574e6c6SJussi Kivilinna for (;;) { 2206574e6c6SJussi Kivilinna des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src); 2216574e6c6SJussi Kivilinna 2226574e6c6SJussi Kivilinna nbytes -= bsize; 2236574e6c6SJussi Kivilinna if (nbytes < bsize) 2246574e6c6SJussi Kivilinna break; 2256574e6c6SJussi Kivilinna 2266574e6c6SJussi Kivilinna *dst ^= *(src - 1); 2276574e6c6SJussi Kivilinna src -= 1; 2286574e6c6SJussi Kivilinna dst -= 1; 2296574e6c6SJussi Kivilinna } 2306574e6c6SJussi Kivilinna 2316574e6c6SJussi Kivilinna done: 2326574e6c6SJussi Kivilinna *dst ^= *(u64 *)walk->iv; 2336574e6c6SJussi Kivilinna *(u64 *)walk->iv = last_iv; 2346574e6c6SJussi Kivilinna 2356574e6c6SJussi Kivilinna return nbytes; 2366574e6c6SJussi Kivilinna } 2376574e6c6SJussi Kivilinna 23809c0f03bSEric Biggers static int cbc_decrypt(struct skcipher_request *req) 2396574e6c6SJussi Kivilinna { 24009c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 24109c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 24209c0f03bSEric Biggers struct skcipher_walk walk; 24309c0f03bSEric Biggers unsigned int nbytes; 2446574e6c6SJussi Kivilinna int err; 2456574e6c6SJussi Kivilinna 24609c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 2476574e6c6SJussi Kivilinna 2486574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 24909c0f03bSEric Biggers nbytes = __cbc_decrypt(ctx, &walk); 25009c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 2516574e6c6SJussi Kivilinna } 2526574e6c6SJussi Kivilinna 2536574e6c6SJussi Kivilinna return err; 2546574e6c6SJussi Kivilinna } 2556574e6c6SJussi Kivilinna 2566574e6c6SJussi Kivilinna static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx, 25709c0f03bSEric Biggers struct skcipher_walk *walk) 2586574e6c6SJussi Kivilinna { 2596574e6c6SJussi Kivilinna u8 *ctrblk = walk->iv; 2606574e6c6SJussi Kivilinna u8 keystream[DES3_EDE_BLOCK_SIZE]; 2616574e6c6SJussi Kivilinna u8 *src = walk->src.virt.addr; 2626574e6c6SJussi Kivilinna u8 *dst = walk->dst.virt.addr; 2636574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 2646574e6c6SJussi Kivilinna 2656574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, keystream, ctrblk); 26645fe93dfSArd Biesheuvel crypto_xor_cpy(dst, keystream, src, nbytes); 2676574e6c6SJussi Kivilinna 2686574e6c6SJussi Kivilinna crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE); 2696574e6c6SJussi Kivilinna } 2706574e6c6SJussi Kivilinna 27109c0f03bSEric Biggers static unsigned int __ctr_crypt(struct des3_ede_x86_ctx *ctx, 27209c0f03bSEric Biggers struct skcipher_walk *walk) 2736574e6c6SJussi Kivilinna { 2746574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 2756574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 2765e50d43dSJussi Kivilinna __be64 *src = (__be64 *)walk->src.virt.addr; 2775e50d43dSJussi Kivilinna __be64 *dst = (__be64 *)walk->dst.virt.addr; 2786574e6c6SJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 2796574e6c6SJussi Kivilinna __be64 ctrblocks[3]; 2806574e6c6SJussi Kivilinna 2816574e6c6SJussi Kivilinna /* Process four block batch */ 2826574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 2836574e6c6SJussi Kivilinna do { 2846574e6c6SJussi Kivilinna /* create ctrblks for parallel encrypt */ 2856574e6c6SJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 2866574e6c6SJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 2876574e6c6SJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 2886574e6c6SJussi Kivilinna 2896574e6c6SJussi Kivilinna des3_ede_enc_blk_3way(ctx, (u8 *)ctrblocks, 2906574e6c6SJussi Kivilinna (u8 *)ctrblocks); 2916574e6c6SJussi Kivilinna 2926574e6c6SJussi Kivilinna dst[0] = src[0] ^ ctrblocks[0]; 2936574e6c6SJussi Kivilinna dst[1] = src[1] ^ ctrblocks[1]; 2946574e6c6SJussi Kivilinna dst[2] = src[2] ^ ctrblocks[2]; 2956574e6c6SJussi Kivilinna 2966574e6c6SJussi Kivilinna src += 3; 2976574e6c6SJussi Kivilinna dst += 3; 2986574e6c6SJussi Kivilinna } while ((nbytes -= bsize * 3) >= bsize * 3); 2996574e6c6SJussi Kivilinna 3006574e6c6SJussi Kivilinna if (nbytes < bsize) 3016574e6c6SJussi Kivilinna goto done; 3026574e6c6SJussi Kivilinna } 3036574e6c6SJussi Kivilinna 3046574e6c6SJussi Kivilinna /* Handle leftovers */ 3056574e6c6SJussi Kivilinna do { 3066574e6c6SJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 3076574e6c6SJussi Kivilinna 3086574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); 3096574e6c6SJussi Kivilinna 3106574e6c6SJussi Kivilinna dst[0] = src[0] ^ ctrblocks[0]; 3116574e6c6SJussi Kivilinna 3126574e6c6SJussi Kivilinna src += 1; 3136574e6c6SJussi Kivilinna dst += 1; 3146574e6c6SJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 3156574e6c6SJussi Kivilinna 3166574e6c6SJussi Kivilinna done: 3176574e6c6SJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 3186574e6c6SJussi Kivilinna return nbytes; 3196574e6c6SJussi Kivilinna } 3206574e6c6SJussi Kivilinna 32109c0f03bSEric Biggers static int ctr_crypt(struct skcipher_request *req) 3226574e6c6SJussi Kivilinna { 32309c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 32409c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 32509c0f03bSEric Biggers struct skcipher_walk walk; 32609c0f03bSEric Biggers unsigned int nbytes; 3276574e6c6SJussi Kivilinna int err; 3286574e6c6SJussi Kivilinna 32909c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 3306574e6c6SJussi Kivilinna 3316574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) { 33209c0f03bSEric Biggers nbytes = __ctr_crypt(ctx, &walk); 33309c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 3346574e6c6SJussi Kivilinna } 3356574e6c6SJussi Kivilinna 33609c0f03bSEric Biggers if (nbytes) { 33709c0f03bSEric Biggers ctr_crypt_final(ctx, &walk); 33809c0f03bSEric Biggers err = skcipher_walk_done(&walk, 0); 3396574e6c6SJussi Kivilinna } 3406574e6c6SJussi Kivilinna 3416574e6c6SJussi Kivilinna return err; 3426574e6c6SJussi Kivilinna } 3436574e6c6SJussi Kivilinna 3446574e6c6SJussi Kivilinna static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key, 3456574e6c6SJussi Kivilinna unsigned int keylen) 3466574e6c6SJussi Kivilinna { 3476574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm); 3486574e6c6SJussi Kivilinna u32 i, j, tmp; 3496574e6c6SJussi Kivilinna int err; 3506574e6c6SJussi Kivilinna 351*cc1d24b9SArd Biesheuvel err = des3_ede_expand_key(&ctx->enc, key, keylen); 352*cc1d24b9SArd Biesheuvel if (err == -ENOKEY) { 353*cc1d24b9SArd Biesheuvel if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS) 354*cc1d24b9SArd Biesheuvel err = -EINVAL; 355*cc1d24b9SArd Biesheuvel else 356*cc1d24b9SArd Biesheuvel err = 0; 357*cc1d24b9SArd Biesheuvel } 3584fd4be05SArd Biesheuvel 359*cc1d24b9SArd Biesheuvel if (err) { 360*cc1d24b9SArd Biesheuvel memset(ctx, 0, sizeof(*ctx)); 3616574e6c6SJussi Kivilinna return err; 362*cc1d24b9SArd Biesheuvel } 3636574e6c6SJussi Kivilinna 3646574e6c6SJussi Kivilinna /* Fix encryption context for this implementation and form decryption 3656574e6c6SJussi Kivilinna * context. */ 3666574e6c6SJussi Kivilinna j = DES3_EDE_EXPKEY_WORDS - 2; 3676574e6c6SJussi Kivilinna for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) { 368*cc1d24b9SArd Biesheuvel tmp = ror32(ctx->enc.expkey[i + 1], 4); 369*cc1d24b9SArd Biesheuvel ctx->enc.expkey[i + 1] = tmp; 3706574e6c6SJussi Kivilinna 371*cc1d24b9SArd Biesheuvel ctx->dec.expkey[j + 0] = ctx->enc.expkey[i + 0]; 372*cc1d24b9SArd Biesheuvel ctx->dec.expkey[j + 1] = tmp; 3736574e6c6SJussi Kivilinna } 3746574e6c6SJussi Kivilinna 3756574e6c6SJussi Kivilinna return 0; 3766574e6c6SJussi Kivilinna } 3776574e6c6SJussi Kivilinna 37809c0f03bSEric Biggers static int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm, 37909c0f03bSEric Biggers const u8 *key, 38009c0f03bSEric Biggers unsigned int keylen) 38109c0f03bSEric Biggers { 38209c0f03bSEric Biggers return des3_ede_x86_setkey(&tfm->base, key, keylen); 38309c0f03bSEric Biggers } 38409c0f03bSEric Biggers 38509c0f03bSEric Biggers static struct crypto_alg des3_ede_cipher = { 3866574e6c6SJussi Kivilinna .cra_name = "des3_ede", 3876574e6c6SJussi Kivilinna .cra_driver_name = "des3_ede-asm", 3886574e6c6SJussi Kivilinna .cra_priority = 200, 3896574e6c6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 3906574e6c6SJussi Kivilinna .cra_blocksize = DES3_EDE_BLOCK_SIZE, 3916574e6c6SJussi Kivilinna .cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 3926574e6c6SJussi Kivilinna .cra_alignmask = 0, 3936574e6c6SJussi Kivilinna .cra_module = THIS_MODULE, 3946574e6c6SJussi Kivilinna .cra_u = { 3956574e6c6SJussi Kivilinna .cipher = { 3966574e6c6SJussi Kivilinna .cia_min_keysize = DES3_EDE_KEY_SIZE, 3976574e6c6SJussi Kivilinna .cia_max_keysize = DES3_EDE_KEY_SIZE, 3986574e6c6SJussi Kivilinna .cia_setkey = des3_ede_x86_setkey, 3996574e6c6SJussi Kivilinna .cia_encrypt = des3_ede_x86_encrypt, 4006574e6c6SJussi Kivilinna .cia_decrypt = des3_ede_x86_decrypt, 4016574e6c6SJussi Kivilinna } 4026574e6c6SJussi Kivilinna } 40309c0f03bSEric Biggers }; 40409c0f03bSEric Biggers 4059cc16b4dSWu Fengguang static struct skcipher_alg des3_ede_skciphers[] = { 40609c0f03bSEric Biggers { 40709c0f03bSEric Biggers .base.cra_name = "ecb(des3_ede)", 40809c0f03bSEric Biggers .base.cra_driver_name = "ecb-des3_ede-asm", 40909c0f03bSEric Biggers .base.cra_priority = 300, 41009c0f03bSEric Biggers .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 41109c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 41209c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4136574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4146574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 41509c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4166574e6c6SJussi Kivilinna .encrypt = ecb_encrypt, 4176574e6c6SJussi Kivilinna .decrypt = ecb_decrypt, 4186574e6c6SJussi Kivilinna }, { 41909c0f03bSEric Biggers .base.cra_name = "cbc(des3_ede)", 42009c0f03bSEric Biggers .base.cra_driver_name = "cbc-des3_ede-asm", 42109c0f03bSEric Biggers .base.cra_priority = 300, 42209c0f03bSEric Biggers .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 42309c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 42409c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4256574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4266574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4276574e6c6SJussi Kivilinna .ivsize = DES3_EDE_BLOCK_SIZE, 42809c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4296574e6c6SJussi Kivilinna .encrypt = cbc_encrypt, 4306574e6c6SJussi Kivilinna .decrypt = cbc_decrypt, 4316574e6c6SJussi Kivilinna }, { 43209c0f03bSEric Biggers .base.cra_name = "ctr(des3_ede)", 43309c0f03bSEric Biggers .base.cra_driver_name = "ctr-des3_ede-asm", 43409c0f03bSEric Biggers .base.cra_priority = 300, 43509c0f03bSEric Biggers .base.cra_blocksize = 1, 43609c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 43709c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4386574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4396574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4406574e6c6SJussi Kivilinna .ivsize = DES3_EDE_BLOCK_SIZE, 44109c0f03bSEric Biggers .chunksize = DES3_EDE_BLOCK_SIZE, 44209c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4436574e6c6SJussi Kivilinna .encrypt = ctr_crypt, 4446574e6c6SJussi Kivilinna .decrypt = ctr_crypt, 44509c0f03bSEric Biggers } 44609c0f03bSEric Biggers }; 4476574e6c6SJussi Kivilinna 4486574e6c6SJussi Kivilinna static bool is_blacklisted_cpu(void) 4496574e6c6SJussi Kivilinna { 4506574e6c6SJussi Kivilinna if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 4516574e6c6SJussi Kivilinna return false; 4526574e6c6SJussi Kivilinna 4536574e6c6SJussi Kivilinna if (boot_cpu_data.x86 == 0x0f) { 4546574e6c6SJussi Kivilinna /* 4556574e6c6SJussi Kivilinna * On Pentium 4, des3_ede-x86_64 is slower than generic C 4566574e6c6SJussi Kivilinna * implementation because use of 64bit rotates (which are really 4576574e6c6SJussi Kivilinna * slow on P4). Therefore blacklist P4s. 4586574e6c6SJussi Kivilinna */ 4596574e6c6SJussi Kivilinna return true; 4606574e6c6SJussi Kivilinna } 4616574e6c6SJussi Kivilinna 4626574e6c6SJussi Kivilinna return false; 4636574e6c6SJussi Kivilinna } 4646574e6c6SJussi Kivilinna 4656574e6c6SJussi Kivilinna static int force; 4666574e6c6SJussi Kivilinna module_param(force, int, 0); 4676574e6c6SJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 4686574e6c6SJussi Kivilinna 4696574e6c6SJussi Kivilinna static int __init des3_ede_x86_init(void) 4706574e6c6SJussi Kivilinna { 47109c0f03bSEric Biggers int err; 47209c0f03bSEric Biggers 4736574e6c6SJussi Kivilinna if (!force && is_blacklisted_cpu()) { 4746574e6c6SJussi Kivilinna pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n"); 4756574e6c6SJussi Kivilinna return -ENODEV; 4766574e6c6SJussi Kivilinna } 4776574e6c6SJussi Kivilinna 47809c0f03bSEric Biggers err = crypto_register_alg(&des3_ede_cipher); 47909c0f03bSEric Biggers if (err) 48009c0f03bSEric Biggers return err; 48109c0f03bSEric Biggers 48209c0f03bSEric Biggers err = crypto_register_skciphers(des3_ede_skciphers, 48309c0f03bSEric Biggers ARRAY_SIZE(des3_ede_skciphers)); 48409c0f03bSEric Biggers if (err) 48509c0f03bSEric Biggers crypto_unregister_alg(&des3_ede_cipher); 48609c0f03bSEric Biggers 48709c0f03bSEric Biggers return err; 4886574e6c6SJussi Kivilinna } 4896574e6c6SJussi Kivilinna 4906574e6c6SJussi Kivilinna static void __exit des3_ede_x86_fini(void) 4916574e6c6SJussi Kivilinna { 49209c0f03bSEric Biggers crypto_unregister_alg(&des3_ede_cipher); 49309c0f03bSEric Biggers crypto_unregister_skciphers(des3_ede_skciphers, 49409c0f03bSEric Biggers ARRAY_SIZE(des3_ede_skciphers)); 4956574e6c6SJussi Kivilinna } 4966574e6c6SJussi Kivilinna 4976574e6c6SJussi Kivilinna module_init(des3_ede_x86_init); 4986574e6c6SJussi Kivilinna module_exit(des3_ede_x86_fini); 4996574e6c6SJussi Kivilinna 5006574e6c6SJussi Kivilinna MODULE_LICENSE("GPL"); 5016574e6c6SJussi Kivilinna MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized"); 5025d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede"); 5035d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede-asm"); 5046574e6c6SJussi Kivilinna MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>"); 505