16574e6c6SJussi Kivilinna /* 26574e6c6SJussi Kivilinna * Glue Code for assembler optimized version of 3DES 36574e6c6SJussi Kivilinna * 46574e6c6SJussi Kivilinna * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 56574e6c6SJussi Kivilinna * 66574e6c6SJussi Kivilinna * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 76574e6c6SJussi Kivilinna * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 86574e6c6SJussi Kivilinna * CTR part based on code (crypto/ctr.c) by: 96574e6c6SJussi Kivilinna * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> 106574e6c6SJussi Kivilinna * 116574e6c6SJussi Kivilinna * This program is free software; you can redistribute it and/or modify 126574e6c6SJussi Kivilinna * it under the terms of the GNU General Public License as published by 136574e6c6SJussi Kivilinna * the Free Software Foundation; either version 2 of the License, or 146574e6c6SJussi Kivilinna * (at your option) any later version. 156574e6c6SJussi Kivilinna * 166574e6c6SJussi Kivilinna * This program is distributed in the hope that it will be useful, 176574e6c6SJussi Kivilinna * but WITHOUT ANY WARRANTY; without even the implied warranty of 186574e6c6SJussi Kivilinna * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 196574e6c6SJussi Kivilinna * GNU General Public License for more details. 206574e6c6SJussi Kivilinna * 216574e6c6SJussi Kivilinna */ 226574e6c6SJussi Kivilinna 2309c0f03bSEric Biggers #include <crypto/algapi.h> 246574e6c6SJussi Kivilinna #include <crypto/des.h> 2509c0f03bSEric Biggers #include <crypto/internal/skcipher.h> 266574e6c6SJussi Kivilinna #include <linux/crypto.h> 276574e6c6SJussi Kivilinna #include <linux/init.h> 286574e6c6SJussi Kivilinna #include <linux/module.h> 296574e6c6SJussi Kivilinna #include <linux/types.h> 306574e6c6SJussi Kivilinna 316574e6c6SJussi Kivilinna struct des3_ede_x86_ctx { 326574e6c6SJussi Kivilinna u32 enc_expkey[DES3_EDE_EXPKEY_WORDS]; 336574e6c6SJussi Kivilinna u32 dec_expkey[DES3_EDE_EXPKEY_WORDS]; 346574e6c6SJussi Kivilinna }; 356574e6c6SJussi Kivilinna 366574e6c6SJussi Kivilinna /* regular block cipher functions */ 376574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk(const u32 *expkey, u8 *dst, 386574e6c6SJussi Kivilinna const u8 *src); 396574e6c6SJussi Kivilinna 406574e6c6SJussi Kivilinna /* 3-way parallel cipher functions */ 416574e6c6SJussi Kivilinna asmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst, 426574e6c6SJussi Kivilinna const u8 *src); 436574e6c6SJussi Kivilinna 446574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, 456574e6c6SJussi Kivilinna const u8 *src) 466574e6c6SJussi Kivilinna { 476574e6c6SJussi Kivilinna u32 *enc_ctx = ctx->enc_expkey; 486574e6c6SJussi Kivilinna 496574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk(enc_ctx, dst, src); 506574e6c6SJussi Kivilinna } 516574e6c6SJussi Kivilinna 526574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst, 536574e6c6SJussi Kivilinna const u8 *src) 546574e6c6SJussi Kivilinna { 556574e6c6SJussi Kivilinna u32 *dec_ctx = ctx->dec_expkey; 566574e6c6SJussi Kivilinna 576574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk(dec_ctx, dst, src); 586574e6c6SJussi Kivilinna } 596574e6c6SJussi Kivilinna 606574e6c6SJussi Kivilinna static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, 616574e6c6SJussi Kivilinna const u8 *src) 626574e6c6SJussi Kivilinna { 636574e6c6SJussi Kivilinna u32 *enc_ctx = ctx->enc_expkey; 646574e6c6SJussi Kivilinna 656574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src); 666574e6c6SJussi Kivilinna } 676574e6c6SJussi Kivilinna 686574e6c6SJussi Kivilinna static inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst, 696574e6c6SJussi Kivilinna const u8 *src) 706574e6c6SJussi Kivilinna { 716574e6c6SJussi Kivilinna u32 *dec_ctx = ctx->dec_expkey; 726574e6c6SJussi Kivilinna 736574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src); 746574e6c6SJussi Kivilinna } 756574e6c6SJussi Kivilinna 766574e6c6SJussi Kivilinna static void des3_ede_x86_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 776574e6c6SJussi Kivilinna { 786574e6c6SJussi Kivilinna des3_ede_enc_blk(crypto_tfm_ctx(tfm), dst, src); 796574e6c6SJussi Kivilinna } 806574e6c6SJussi Kivilinna 816574e6c6SJussi Kivilinna static void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 826574e6c6SJussi Kivilinna { 836574e6c6SJussi Kivilinna des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src); 846574e6c6SJussi Kivilinna } 856574e6c6SJussi Kivilinna 8609c0f03bSEric Biggers static int ecb_crypt(struct skcipher_request *req, const u32 *expkey) 876574e6c6SJussi Kivilinna { 8809c0f03bSEric Biggers const unsigned int bsize = DES3_EDE_BLOCK_SIZE; 8909c0f03bSEric Biggers struct skcipher_walk walk; 906574e6c6SJussi Kivilinna unsigned int nbytes; 916574e6c6SJussi Kivilinna int err; 926574e6c6SJussi Kivilinna 9309c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 946574e6c6SJussi Kivilinna 9509c0f03bSEric Biggers while ((nbytes = walk.nbytes)) { 9609c0f03bSEric Biggers u8 *wsrc = walk.src.virt.addr; 9709c0f03bSEric Biggers u8 *wdst = walk.dst.virt.addr; 986574e6c6SJussi Kivilinna 996574e6c6SJussi Kivilinna /* Process four block batch */ 1006574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 1016574e6c6SJussi Kivilinna do { 1026574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk_3way(expkey, wdst, 1036574e6c6SJussi Kivilinna wsrc); 1046574e6c6SJussi Kivilinna 1056574e6c6SJussi Kivilinna wsrc += bsize * 3; 1066574e6c6SJussi Kivilinna wdst += bsize * 3; 1076574e6c6SJussi Kivilinna nbytes -= bsize * 3; 1086574e6c6SJussi Kivilinna } while (nbytes >= bsize * 3); 1096574e6c6SJussi Kivilinna 1106574e6c6SJussi Kivilinna if (nbytes < bsize) 1116574e6c6SJussi Kivilinna goto done; 1126574e6c6SJussi Kivilinna } 1136574e6c6SJussi Kivilinna 1146574e6c6SJussi Kivilinna /* Handle leftovers */ 1156574e6c6SJussi Kivilinna do { 1166574e6c6SJussi Kivilinna des3_ede_x86_64_crypt_blk(expkey, wdst, wsrc); 1176574e6c6SJussi Kivilinna 1186574e6c6SJussi Kivilinna wsrc += bsize; 1196574e6c6SJussi Kivilinna wdst += bsize; 1206574e6c6SJussi Kivilinna nbytes -= bsize; 1216574e6c6SJussi Kivilinna } while (nbytes >= bsize); 1226574e6c6SJussi Kivilinna 1236574e6c6SJussi Kivilinna done: 12409c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 1256574e6c6SJussi Kivilinna } 1266574e6c6SJussi Kivilinna 1276574e6c6SJussi Kivilinna return err; 1286574e6c6SJussi Kivilinna } 1296574e6c6SJussi Kivilinna 13009c0f03bSEric Biggers static int ecb_encrypt(struct skcipher_request *req) 1316574e6c6SJussi Kivilinna { 13209c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 13309c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 1346574e6c6SJussi Kivilinna 13509c0f03bSEric Biggers return ecb_crypt(req, ctx->enc_expkey); 1366574e6c6SJussi Kivilinna } 1376574e6c6SJussi Kivilinna 13809c0f03bSEric Biggers static int ecb_decrypt(struct skcipher_request *req) 1396574e6c6SJussi Kivilinna { 14009c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 14109c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 1426574e6c6SJussi Kivilinna 14309c0f03bSEric Biggers return ecb_crypt(req, ctx->dec_expkey); 1446574e6c6SJussi Kivilinna } 1456574e6c6SJussi Kivilinna 14609c0f03bSEric Biggers static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx, 14709c0f03bSEric Biggers struct skcipher_walk *walk) 1486574e6c6SJussi Kivilinna { 1496574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 1506574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 1516574e6c6SJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 1526574e6c6SJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 1536574e6c6SJussi Kivilinna u64 *iv = (u64 *)walk->iv; 1546574e6c6SJussi Kivilinna 1556574e6c6SJussi Kivilinna do { 1566574e6c6SJussi Kivilinna *dst = *src ^ *iv; 1576574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 1586574e6c6SJussi Kivilinna iv = dst; 1596574e6c6SJussi Kivilinna 1606574e6c6SJussi Kivilinna src += 1; 1616574e6c6SJussi Kivilinna dst += 1; 1626574e6c6SJussi Kivilinna nbytes -= bsize; 1636574e6c6SJussi Kivilinna } while (nbytes >= bsize); 1646574e6c6SJussi Kivilinna 1656574e6c6SJussi Kivilinna *(u64 *)walk->iv = *iv; 1666574e6c6SJussi Kivilinna return nbytes; 1676574e6c6SJussi Kivilinna } 1686574e6c6SJussi Kivilinna 16909c0f03bSEric Biggers static int cbc_encrypt(struct skcipher_request *req) 1706574e6c6SJussi Kivilinna { 17109c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 17209c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 17309c0f03bSEric Biggers struct skcipher_walk walk; 17409c0f03bSEric Biggers unsigned int nbytes; 1756574e6c6SJussi Kivilinna int err; 1766574e6c6SJussi Kivilinna 17709c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 1786574e6c6SJussi Kivilinna 1796574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 18009c0f03bSEric Biggers nbytes = __cbc_encrypt(ctx, &walk); 18109c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 1826574e6c6SJussi Kivilinna } 1836574e6c6SJussi Kivilinna 1846574e6c6SJussi Kivilinna return err; 1856574e6c6SJussi Kivilinna } 1866574e6c6SJussi Kivilinna 18709c0f03bSEric Biggers static unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx, 18809c0f03bSEric Biggers struct skcipher_walk *walk) 1896574e6c6SJussi Kivilinna { 1906574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 1916574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 1926574e6c6SJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 1936574e6c6SJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 1946574e6c6SJussi Kivilinna u64 ivs[3 - 1]; 1956574e6c6SJussi Kivilinna u64 last_iv; 1966574e6c6SJussi Kivilinna 1976574e6c6SJussi Kivilinna /* Start of the last block. */ 1986574e6c6SJussi Kivilinna src += nbytes / bsize - 1; 1996574e6c6SJussi Kivilinna dst += nbytes / bsize - 1; 2006574e6c6SJussi Kivilinna 2016574e6c6SJussi Kivilinna last_iv = *src; 2026574e6c6SJussi Kivilinna 2036574e6c6SJussi Kivilinna /* Process four block batch */ 2046574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 2056574e6c6SJussi Kivilinna do { 2066574e6c6SJussi Kivilinna nbytes -= bsize * 3 - bsize; 2076574e6c6SJussi Kivilinna src -= 3 - 1; 2086574e6c6SJussi Kivilinna dst -= 3 - 1; 2096574e6c6SJussi Kivilinna 2106574e6c6SJussi Kivilinna ivs[0] = src[0]; 2116574e6c6SJussi Kivilinna ivs[1] = src[1]; 2126574e6c6SJussi Kivilinna 2136574e6c6SJussi Kivilinna des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src); 2146574e6c6SJussi Kivilinna 2156574e6c6SJussi Kivilinna dst[1] ^= ivs[0]; 2166574e6c6SJussi Kivilinna dst[2] ^= ivs[1]; 2176574e6c6SJussi Kivilinna 2186574e6c6SJussi Kivilinna nbytes -= bsize; 2196574e6c6SJussi Kivilinna if (nbytes < bsize) 2206574e6c6SJussi Kivilinna goto done; 2216574e6c6SJussi Kivilinna 2226574e6c6SJussi Kivilinna *dst ^= *(src - 1); 2236574e6c6SJussi Kivilinna src -= 1; 2246574e6c6SJussi Kivilinna dst -= 1; 2256574e6c6SJussi Kivilinna } while (nbytes >= bsize * 3); 2266574e6c6SJussi Kivilinna } 2276574e6c6SJussi Kivilinna 2286574e6c6SJussi Kivilinna /* Handle leftovers */ 2296574e6c6SJussi Kivilinna for (;;) { 2306574e6c6SJussi Kivilinna des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src); 2316574e6c6SJussi Kivilinna 2326574e6c6SJussi Kivilinna nbytes -= bsize; 2336574e6c6SJussi Kivilinna if (nbytes < bsize) 2346574e6c6SJussi Kivilinna break; 2356574e6c6SJussi Kivilinna 2366574e6c6SJussi Kivilinna *dst ^= *(src - 1); 2376574e6c6SJussi Kivilinna src -= 1; 2386574e6c6SJussi Kivilinna dst -= 1; 2396574e6c6SJussi Kivilinna } 2406574e6c6SJussi Kivilinna 2416574e6c6SJussi Kivilinna done: 2426574e6c6SJussi Kivilinna *dst ^= *(u64 *)walk->iv; 2436574e6c6SJussi Kivilinna *(u64 *)walk->iv = last_iv; 2446574e6c6SJussi Kivilinna 2456574e6c6SJussi Kivilinna return nbytes; 2466574e6c6SJussi Kivilinna } 2476574e6c6SJussi Kivilinna 24809c0f03bSEric Biggers static int cbc_decrypt(struct skcipher_request *req) 2496574e6c6SJussi Kivilinna { 25009c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 25109c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 25209c0f03bSEric Biggers struct skcipher_walk walk; 25309c0f03bSEric Biggers unsigned int nbytes; 2546574e6c6SJussi Kivilinna int err; 2556574e6c6SJussi Kivilinna 25609c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 2576574e6c6SJussi Kivilinna 2586574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 25909c0f03bSEric Biggers nbytes = __cbc_decrypt(ctx, &walk); 26009c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 2616574e6c6SJussi Kivilinna } 2626574e6c6SJussi Kivilinna 2636574e6c6SJussi Kivilinna return err; 2646574e6c6SJussi Kivilinna } 2656574e6c6SJussi Kivilinna 2666574e6c6SJussi Kivilinna static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx, 26709c0f03bSEric Biggers struct skcipher_walk *walk) 2686574e6c6SJussi Kivilinna { 2696574e6c6SJussi Kivilinna u8 *ctrblk = walk->iv; 2706574e6c6SJussi Kivilinna u8 keystream[DES3_EDE_BLOCK_SIZE]; 2716574e6c6SJussi Kivilinna u8 *src = walk->src.virt.addr; 2726574e6c6SJussi Kivilinna u8 *dst = walk->dst.virt.addr; 2736574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 2746574e6c6SJussi Kivilinna 2756574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, keystream, ctrblk); 27645fe93dfSArd Biesheuvel crypto_xor_cpy(dst, keystream, src, nbytes); 2776574e6c6SJussi Kivilinna 2786574e6c6SJussi Kivilinna crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE); 2796574e6c6SJussi Kivilinna } 2806574e6c6SJussi Kivilinna 28109c0f03bSEric Biggers static unsigned int __ctr_crypt(struct des3_ede_x86_ctx *ctx, 28209c0f03bSEric Biggers struct skcipher_walk *walk) 2836574e6c6SJussi Kivilinna { 2846574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 2856574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 2865e50d43dSJussi Kivilinna __be64 *src = (__be64 *)walk->src.virt.addr; 2875e50d43dSJussi Kivilinna __be64 *dst = (__be64 *)walk->dst.virt.addr; 2886574e6c6SJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 2896574e6c6SJussi Kivilinna __be64 ctrblocks[3]; 2906574e6c6SJussi Kivilinna 2916574e6c6SJussi Kivilinna /* Process four block batch */ 2926574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 2936574e6c6SJussi Kivilinna do { 2946574e6c6SJussi Kivilinna /* create ctrblks for parallel encrypt */ 2956574e6c6SJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 2966574e6c6SJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 2976574e6c6SJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 2986574e6c6SJussi Kivilinna 2996574e6c6SJussi Kivilinna des3_ede_enc_blk_3way(ctx, (u8 *)ctrblocks, 3006574e6c6SJussi Kivilinna (u8 *)ctrblocks); 3016574e6c6SJussi Kivilinna 3026574e6c6SJussi Kivilinna dst[0] = src[0] ^ ctrblocks[0]; 3036574e6c6SJussi Kivilinna dst[1] = src[1] ^ ctrblocks[1]; 3046574e6c6SJussi Kivilinna dst[2] = src[2] ^ ctrblocks[2]; 3056574e6c6SJussi Kivilinna 3066574e6c6SJussi Kivilinna src += 3; 3076574e6c6SJussi Kivilinna dst += 3; 3086574e6c6SJussi Kivilinna } while ((nbytes -= bsize * 3) >= bsize * 3); 3096574e6c6SJussi Kivilinna 3106574e6c6SJussi Kivilinna if (nbytes < bsize) 3116574e6c6SJussi Kivilinna goto done; 3126574e6c6SJussi Kivilinna } 3136574e6c6SJussi Kivilinna 3146574e6c6SJussi Kivilinna /* Handle leftovers */ 3156574e6c6SJussi Kivilinna do { 3166574e6c6SJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 3176574e6c6SJussi Kivilinna 3186574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); 3196574e6c6SJussi Kivilinna 3206574e6c6SJussi Kivilinna dst[0] = src[0] ^ ctrblocks[0]; 3216574e6c6SJussi Kivilinna 3226574e6c6SJussi Kivilinna src += 1; 3236574e6c6SJussi Kivilinna dst += 1; 3246574e6c6SJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 3256574e6c6SJussi Kivilinna 3266574e6c6SJussi Kivilinna done: 3276574e6c6SJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 3286574e6c6SJussi Kivilinna return nbytes; 3296574e6c6SJussi Kivilinna } 3306574e6c6SJussi Kivilinna 33109c0f03bSEric Biggers static int ctr_crypt(struct skcipher_request *req) 3326574e6c6SJussi Kivilinna { 33309c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 33409c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 33509c0f03bSEric Biggers struct skcipher_walk walk; 33609c0f03bSEric Biggers unsigned int nbytes; 3376574e6c6SJussi Kivilinna int err; 3386574e6c6SJussi Kivilinna 33909c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 3406574e6c6SJussi Kivilinna 3416574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) { 34209c0f03bSEric Biggers nbytes = __ctr_crypt(ctx, &walk); 34309c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 3446574e6c6SJussi Kivilinna } 3456574e6c6SJussi Kivilinna 34609c0f03bSEric Biggers if (nbytes) { 34709c0f03bSEric Biggers ctr_crypt_final(ctx, &walk); 34809c0f03bSEric Biggers err = skcipher_walk_done(&walk, 0); 3496574e6c6SJussi Kivilinna } 3506574e6c6SJussi Kivilinna 3516574e6c6SJussi Kivilinna return err; 3526574e6c6SJussi Kivilinna } 3536574e6c6SJussi Kivilinna 3546574e6c6SJussi Kivilinna static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key, 3556574e6c6SJussi Kivilinna unsigned int keylen) 3566574e6c6SJussi Kivilinna { 3576574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm); 3586574e6c6SJussi Kivilinna u32 i, j, tmp; 3596574e6c6SJussi Kivilinna int err; 3606574e6c6SJussi Kivilinna 3616574e6c6SJussi Kivilinna /* Generate encryption context using generic implementation. */ 3626574e6c6SJussi Kivilinna err = __des3_ede_setkey(ctx->enc_expkey, &tfm->crt_flags, key, keylen); 3636574e6c6SJussi Kivilinna if (err < 0) 3646574e6c6SJussi Kivilinna return err; 3656574e6c6SJussi Kivilinna 3666574e6c6SJussi Kivilinna /* Fix encryption context for this implementation and form decryption 3676574e6c6SJussi Kivilinna * context. */ 3686574e6c6SJussi Kivilinna j = DES3_EDE_EXPKEY_WORDS - 2; 3696574e6c6SJussi Kivilinna for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) { 3706574e6c6SJussi Kivilinna tmp = ror32(ctx->enc_expkey[i + 1], 4); 3716574e6c6SJussi Kivilinna ctx->enc_expkey[i + 1] = tmp; 3726574e6c6SJussi Kivilinna 3736574e6c6SJussi Kivilinna ctx->dec_expkey[j + 0] = ctx->enc_expkey[i + 0]; 3746574e6c6SJussi Kivilinna ctx->dec_expkey[j + 1] = tmp; 3756574e6c6SJussi Kivilinna } 3766574e6c6SJussi Kivilinna 3776574e6c6SJussi Kivilinna return 0; 3786574e6c6SJussi Kivilinna } 3796574e6c6SJussi Kivilinna 38009c0f03bSEric Biggers static int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm, 38109c0f03bSEric Biggers const u8 *key, 38209c0f03bSEric Biggers unsigned int keylen) 38309c0f03bSEric Biggers { 38409c0f03bSEric Biggers return des3_ede_x86_setkey(&tfm->base, key, keylen); 38509c0f03bSEric Biggers } 38609c0f03bSEric Biggers 38709c0f03bSEric Biggers static struct crypto_alg des3_ede_cipher = { 3886574e6c6SJussi Kivilinna .cra_name = "des3_ede", 3896574e6c6SJussi Kivilinna .cra_driver_name = "des3_ede-asm", 3906574e6c6SJussi Kivilinna .cra_priority = 200, 3916574e6c6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 3926574e6c6SJussi Kivilinna .cra_blocksize = DES3_EDE_BLOCK_SIZE, 3936574e6c6SJussi Kivilinna .cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 3946574e6c6SJussi Kivilinna .cra_alignmask = 0, 3956574e6c6SJussi Kivilinna .cra_module = THIS_MODULE, 3966574e6c6SJussi Kivilinna .cra_u = { 3976574e6c6SJussi Kivilinna .cipher = { 3986574e6c6SJussi Kivilinna .cia_min_keysize = DES3_EDE_KEY_SIZE, 3996574e6c6SJussi Kivilinna .cia_max_keysize = DES3_EDE_KEY_SIZE, 4006574e6c6SJussi Kivilinna .cia_setkey = des3_ede_x86_setkey, 4016574e6c6SJussi Kivilinna .cia_encrypt = des3_ede_x86_encrypt, 4026574e6c6SJussi Kivilinna .cia_decrypt = des3_ede_x86_decrypt, 4036574e6c6SJussi Kivilinna } 4046574e6c6SJussi Kivilinna } 40509c0f03bSEric Biggers }; 40609c0f03bSEric Biggers 407*9cc16b4dSWu Fengguang static struct skcipher_alg des3_ede_skciphers[] = { 40809c0f03bSEric Biggers { 40909c0f03bSEric Biggers .base.cra_name = "ecb(des3_ede)", 41009c0f03bSEric Biggers .base.cra_driver_name = "ecb-des3_ede-asm", 41109c0f03bSEric Biggers .base.cra_priority = 300, 41209c0f03bSEric Biggers .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 41309c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 41409c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4156574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4166574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 41709c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4186574e6c6SJussi Kivilinna .encrypt = ecb_encrypt, 4196574e6c6SJussi Kivilinna .decrypt = ecb_decrypt, 4206574e6c6SJussi Kivilinna }, { 42109c0f03bSEric Biggers .base.cra_name = "cbc(des3_ede)", 42209c0f03bSEric Biggers .base.cra_driver_name = "cbc-des3_ede-asm", 42309c0f03bSEric Biggers .base.cra_priority = 300, 42409c0f03bSEric Biggers .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 42509c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 42609c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4276574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4286574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4296574e6c6SJussi Kivilinna .ivsize = DES3_EDE_BLOCK_SIZE, 43009c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4316574e6c6SJussi Kivilinna .encrypt = cbc_encrypt, 4326574e6c6SJussi Kivilinna .decrypt = cbc_decrypt, 4336574e6c6SJussi Kivilinna }, { 43409c0f03bSEric Biggers .base.cra_name = "ctr(des3_ede)", 43509c0f03bSEric Biggers .base.cra_driver_name = "ctr-des3_ede-asm", 43609c0f03bSEric Biggers .base.cra_priority = 300, 43709c0f03bSEric Biggers .base.cra_blocksize = 1, 43809c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 43909c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4406574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4416574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4426574e6c6SJussi Kivilinna .ivsize = DES3_EDE_BLOCK_SIZE, 44309c0f03bSEric Biggers .chunksize = DES3_EDE_BLOCK_SIZE, 44409c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4456574e6c6SJussi Kivilinna .encrypt = ctr_crypt, 4466574e6c6SJussi Kivilinna .decrypt = ctr_crypt, 44709c0f03bSEric Biggers } 44809c0f03bSEric Biggers }; 4496574e6c6SJussi Kivilinna 4506574e6c6SJussi Kivilinna static bool is_blacklisted_cpu(void) 4516574e6c6SJussi Kivilinna { 4526574e6c6SJussi Kivilinna if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 4536574e6c6SJussi Kivilinna return false; 4546574e6c6SJussi Kivilinna 4556574e6c6SJussi Kivilinna if (boot_cpu_data.x86 == 0x0f) { 4566574e6c6SJussi Kivilinna /* 4576574e6c6SJussi Kivilinna * On Pentium 4, des3_ede-x86_64 is slower than generic C 4586574e6c6SJussi Kivilinna * implementation because use of 64bit rotates (which are really 4596574e6c6SJussi Kivilinna * slow on P4). Therefore blacklist P4s. 4606574e6c6SJussi Kivilinna */ 4616574e6c6SJussi Kivilinna return true; 4626574e6c6SJussi Kivilinna } 4636574e6c6SJussi Kivilinna 4646574e6c6SJussi Kivilinna return false; 4656574e6c6SJussi Kivilinna } 4666574e6c6SJussi Kivilinna 4676574e6c6SJussi Kivilinna static int force; 4686574e6c6SJussi Kivilinna module_param(force, int, 0); 4696574e6c6SJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 4706574e6c6SJussi Kivilinna 4716574e6c6SJussi Kivilinna static int __init des3_ede_x86_init(void) 4726574e6c6SJussi Kivilinna { 47309c0f03bSEric Biggers int err; 47409c0f03bSEric Biggers 4756574e6c6SJussi Kivilinna if (!force && is_blacklisted_cpu()) { 4766574e6c6SJussi Kivilinna pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n"); 4776574e6c6SJussi Kivilinna return -ENODEV; 4786574e6c6SJussi Kivilinna } 4796574e6c6SJussi Kivilinna 48009c0f03bSEric Biggers err = crypto_register_alg(&des3_ede_cipher); 48109c0f03bSEric Biggers if (err) 48209c0f03bSEric Biggers return err; 48309c0f03bSEric Biggers 48409c0f03bSEric Biggers err = crypto_register_skciphers(des3_ede_skciphers, 48509c0f03bSEric Biggers ARRAY_SIZE(des3_ede_skciphers)); 48609c0f03bSEric Biggers if (err) 48709c0f03bSEric Biggers crypto_unregister_alg(&des3_ede_cipher); 48809c0f03bSEric Biggers 48909c0f03bSEric Biggers return err; 4906574e6c6SJussi Kivilinna } 4916574e6c6SJussi Kivilinna 4926574e6c6SJussi Kivilinna static void __exit des3_ede_x86_fini(void) 4936574e6c6SJussi Kivilinna { 49409c0f03bSEric Biggers crypto_unregister_alg(&des3_ede_cipher); 49509c0f03bSEric Biggers crypto_unregister_skciphers(des3_ede_skciphers, 49609c0f03bSEric Biggers ARRAY_SIZE(des3_ede_skciphers)); 4976574e6c6SJussi Kivilinna } 4986574e6c6SJussi Kivilinna 4996574e6c6SJussi Kivilinna module_init(des3_ede_x86_init); 5006574e6c6SJussi Kivilinna module_exit(des3_ede_x86_fini); 5016574e6c6SJussi Kivilinna 5026574e6c6SJussi Kivilinna MODULE_LICENSE("GPL"); 5036574e6c6SJussi Kivilinna MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized"); 5045d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede"); 5055d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede-asm"); 5066574e6c6SJussi Kivilinna MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>"); 507