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 23*09c0f03bSEric Biggers #include <crypto/algapi.h> 246574e6c6SJussi Kivilinna #include <crypto/des.h> 25*09c0f03bSEric 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 86*09c0f03bSEric Biggers static int ecb_crypt(struct skcipher_request *req, const u32 *expkey) 876574e6c6SJussi Kivilinna { 88*09c0f03bSEric Biggers const unsigned int bsize = DES3_EDE_BLOCK_SIZE; 89*09c0f03bSEric Biggers struct skcipher_walk walk; 906574e6c6SJussi Kivilinna unsigned int nbytes; 916574e6c6SJussi Kivilinna int err; 926574e6c6SJussi Kivilinna 93*09c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 946574e6c6SJussi Kivilinna 95*09c0f03bSEric Biggers while ((nbytes = walk.nbytes)) { 96*09c0f03bSEric Biggers u8 *wsrc = walk.src.virt.addr; 97*09c0f03bSEric 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: 124*09c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 1256574e6c6SJussi Kivilinna } 1266574e6c6SJussi Kivilinna 1276574e6c6SJussi Kivilinna return err; 1286574e6c6SJussi Kivilinna } 1296574e6c6SJussi Kivilinna 130*09c0f03bSEric Biggers static int ecb_encrypt(struct skcipher_request *req) 1316574e6c6SJussi Kivilinna { 132*09c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 133*09c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 1346574e6c6SJussi Kivilinna 135*09c0f03bSEric Biggers return ecb_crypt(req, ctx->enc_expkey); 1366574e6c6SJussi Kivilinna } 1376574e6c6SJussi Kivilinna 138*09c0f03bSEric Biggers static int ecb_decrypt(struct skcipher_request *req) 1396574e6c6SJussi Kivilinna { 140*09c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 141*09c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 1426574e6c6SJussi Kivilinna 143*09c0f03bSEric Biggers return ecb_crypt(req, ctx->dec_expkey); 1446574e6c6SJussi Kivilinna } 1456574e6c6SJussi Kivilinna 146*09c0f03bSEric Biggers static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx, 147*09c0f03bSEric 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 169*09c0f03bSEric Biggers static int cbc_encrypt(struct skcipher_request *req) 1706574e6c6SJussi Kivilinna { 171*09c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 172*09c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 173*09c0f03bSEric Biggers struct skcipher_walk walk; 174*09c0f03bSEric Biggers unsigned int nbytes; 1756574e6c6SJussi Kivilinna int err; 1766574e6c6SJussi Kivilinna 177*09c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 1786574e6c6SJussi Kivilinna 1796574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 180*09c0f03bSEric Biggers nbytes = __cbc_encrypt(ctx, &walk); 181*09c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 1826574e6c6SJussi Kivilinna } 1836574e6c6SJussi Kivilinna 1846574e6c6SJussi Kivilinna return err; 1856574e6c6SJussi Kivilinna } 1866574e6c6SJussi Kivilinna 187*09c0f03bSEric Biggers static unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx, 188*09c0f03bSEric 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 248*09c0f03bSEric Biggers static int cbc_decrypt(struct skcipher_request *req) 2496574e6c6SJussi Kivilinna { 250*09c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 251*09c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 252*09c0f03bSEric Biggers struct skcipher_walk walk; 253*09c0f03bSEric Biggers unsigned int nbytes; 2546574e6c6SJussi Kivilinna int err; 2556574e6c6SJussi Kivilinna 256*09c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 2576574e6c6SJussi Kivilinna 2586574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 259*09c0f03bSEric Biggers nbytes = __cbc_decrypt(ctx, &walk); 260*09c0f03bSEric 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, 267*09c0f03bSEric 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 281*09c0f03bSEric Biggers static unsigned int __ctr_crypt(struct des3_ede_x86_ctx *ctx, 282*09c0f03bSEric 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 331*09c0f03bSEric Biggers static int ctr_crypt(struct skcipher_request *req) 3326574e6c6SJussi Kivilinna { 333*09c0f03bSEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 334*09c0f03bSEric Biggers struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm); 335*09c0f03bSEric Biggers struct skcipher_walk walk; 336*09c0f03bSEric Biggers unsigned int nbytes; 3376574e6c6SJussi Kivilinna int err; 3386574e6c6SJussi Kivilinna 339*09c0f03bSEric Biggers err = skcipher_walk_virt(&walk, req, false); 3406574e6c6SJussi Kivilinna 3416574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) { 342*09c0f03bSEric Biggers nbytes = __ctr_crypt(ctx, &walk); 343*09c0f03bSEric Biggers err = skcipher_walk_done(&walk, nbytes); 3446574e6c6SJussi Kivilinna } 3456574e6c6SJussi Kivilinna 346*09c0f03bSEric Biggers if (nbytes) { 347*09c0f03bSEric Biggers ctr_crypt_final(ctx, &walk); 348*09c0f03bSEric 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 380*09c0f03bSEric Biggers static int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm, 381*09c0f03bSEric Biggers const u8 *key, 382*09c0f03bSEric Biggers unsigned int keylen) 383*09c0f03bSEric Biggers { 384*09c0f03bSEric Biggers return des3_ede_x86_setkey(&tfm->base, key, keylen); 385*09c0f03bSEric Biggers } 386*09c0f03bSEric Biggers 387*09c0f03bSEric 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 } 405*09c0f03bSEric Biggers }; 406*09c0f03bSEric Biggers 407*09c0f03bSEric Biggers struct skcipher_alg des3_ede_skciphers[] = { 408*09c0f03bSEric Biggers { 409*09c0f03bSEric Biggers .base.cra_name = "ecb(des3_ede)", 410*09c0f03bSEric Biggers .base.cra_driver_name = "ecb-des3_ede-asm", 411*09c0f03bSEric Biggers .base.cra_priority = 300, 412*09c0f03bSEric Biggers .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 413*09c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 414*09c0f03bSEric Biggers .base.cra_module = THIS_MODULE, 4156574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4166574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 417*09c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4186574e6c6SJussi Kivilinna .encrypt = ecb_encrypt, 4196574e6c6SJussi Kivilinna .decrypt = ecb_decrypt, 4206574e6c6SJussi Kivilinna }, { 421*09c0f03bSEric Biggers .base.cra_name = "cbc(des3_ede)", 422*09c0f03bSEric Biggers .base.cra_driver_name = "cbc-des3_ede-asm", 423*09c0f03bSEric Biggers .base.cra_priority = 300, 424*09c0f03bSEric Biggers .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 425*09c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 426*09c0f03bSEric 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, 430*09c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4316574e6c6SJussi Kivilinna .encrypt = cbc_encrypt, 4326574e6c6SJussi Kivilinna .decrypt = cbc_decrypt, 4336574e6c6SJussi Kivilinna }, { 434*09c0f03bSEric Biggers .base.cra_name = "ctr(des3_ede)", 435*09c0f03bSEric Biggers .base.cra_driver_name = "ctr-des3_ede-asm", 436*09c0f03bSEric Biggers .base.cra_priority = 300, 437*09c0f03bSEric Biggers .base.cra_blocksize = 1, 438*09c0f03bSEric Biggers .base.cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 439*09c0f03bSEric 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, 443*09c0f03bSEric Biggers .chunksize = DES3_EDE_BLOCK_SIZE, 444*09c0f03bSEric Biggers .setkey = des3_ede_x86_setkey_skcipher, 4456574e6c6SJussi Kivilinna .encrypt = ctr_crypt, 4466574e6c6SJussi Kivilinna .decrypt = ctr_crypt, 447*09c0f03bSEric Biggers } 448*09c0f03bSEric 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 { 473*09c0f03bSEric Biggers int err; 474*09c0f03bSEric 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 480*09c0f03bSEric Biggers err = crypto_register_alg(&des3_ede_cipher); 481*09c0f03bSEric Biggers if (err) 482*09c0f03bSEric Biggers return err; 483*09c0f03bSEric Biggers 484*09c0f03bSEric Biggers err = crypto_register_skciphers(des3_ede_skciphers, 485*09c0f03bSEric Biggers ARRAY_SIZE(des3_ede_skciphers)); 486*09c0f03bSEric Biggers if (err) 487*09c0f03bSEric Biggers crypto_unregister_alg(&des3_ede_cipher); 488*09c0f03bSEric Biggers 489*09c0f03bSEric Biggers return err; 4906574e6c6SJussi Kivilinna } 4916574e6c6SJussi Kivilinna 4926574e6c6SJussi Kivilinna static void __exit des3_ede_x86_fini(void) 4936574e6c6SJussi Kivilinna { 494*09c0f03bSEric Biggers crypto_unregister_alg(&des3_ede_cipher); 495*09c0f03bSEric Biggers crypto_unregister_skciphers(des3_ede_skciphers, 496*09c0f03bSEric 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