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 236574e6c6SJussi Kivilinna #include <asm/processor.h> 246574e6c6SJussi Kivilinna #include <crypto/des.h> 256574e6c6SJussi Kivilinna #include <linux/crypto.h> 266574e6c6SJussi Kivilinna #include <linux/init.h> 276574e6c6SJussi Kivilinna #include <linux/module.h> 286574e6c6SJussi Kivilinna #include <linux/types.h> 296574e6c6SJussi Kivilinna #include <crypto/algapi.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 866574e6c6SJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 876574e6c6SJussi Kivilinna const u32 *expkey) 886574e6c6SJussi Kivilinna { 896574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 906574e6c6SJussi Kivilinna unsigned int nbytes; 916574e6c6SJussi Kivilinna int err; 926574e6c6SJussi Kivilinna 936574e6c6SJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 946574e6c6SJussi Kivilinna 956574e6c6SJussi Kivilinna while ((nbytes = walk->nbytes)) { 966574e6c6SJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 976574e6c6SJussi Kivilinna 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: 1246574e6c6SJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 1256574e6c6SJussi Kivilinna } 1266574e6c6SJussi Kivilinna 1276574e6c6SJussi Kivilinna return err; 1286574e6c6SJussi Kivilinna } 1296574e6c6SJussi Kivilinna 1306574e6c6SJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 1316574e6c6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 1326574e6c6SJussi Kivilinna { 1336574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 1346574e6c6SJussi Kivilinna struct blkcipher_walk walk; 1356574e6c6SJussi Kivilinna 1366574e6c6SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 1376574e6c6SJussi Kivilinna return ecb_crypt(desc, &walk, ctx->enc_expkey); 1386574e6c6SJussi Kivilinna } 1396574e6c6SJussi Kivilinna 1406574e6c6SJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 1416574e6c6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 1426574e6c6SJussi Kivilinna { 1436574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 1446574e6c6SJussi Kivilinna struct blkcipher_walk walk; 1456574e6c6SJussi Kivilinna 1466574e6c6SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 1476574e6c6SJussi Kivilinna return ecb_crypt(desc, &walk, ctx->dec_expkey); 1486574e6c6SJussi Kivilinna } 1496574e6c6SJussi Kivilinna 1506574e6c6SJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 1516574e6c6SJussi Kivilinna struct blkcipher_walk *walk) 1526574e6c6SJussi Kivilinna { 1536574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 1546574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 1556574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 1566574e6c6SJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 1576574e6c6SJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 1586574e6c6SJussi Kivilinna u64 *iv = (u64 *)walk->iv; 1596574e6c6SJussi Kivilinna 1606574e6c6SJussi Kivilinna do { 1616574e6c6SJussi Kivilinna *dst = *src ^ *iv; 1626574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 1636574e6c6SJussi Kivilinna iv = dst; 1646574e6c6SJussi Kivilinna 1656574e6c6SJussi Kivilinna src += 1; 1666574e6c6SJussi Kivilinna dst += 1; 1676574e6c6SJussi Kivilinna nbytes -= bsize; 1686574e6c6SJussi Kivilinna } while (nbytes >= bsize); 1696574e6c6SJussi Kivilinna 1706574e6c6SJussi Kivilinna *(u64 *)walk->iv = *iv; 1716574e6c6SJussi Kivilinna return nbytes; 1726574e6c6SJussi Kivilinna } 1736574e6c6SJussi Kivilinna 1746574e6c6SJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 1756574e6c6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 1766574e6c6SJussi Kivilinna { 1776574e6c6SJussi Kivilinna struct blkcipher_walk walk; 1786574e6c6SJussi Kivilinna int err; 1796574e6c6SJussi Kivilinna 1806574e6c6SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 1816574e6c6SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 1826574e6c6SJussi Kivilinna 1836574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 1846574e6c6SJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 1856574e6c6SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 1866574e6c6SJussi Kivilinna } 1876574e6c6SJussi Kivilinna 1886574e6c6SJussi Kivilinna return err; 1896574e6c6SJussi Kivilinna } 1906574e6c6SJussi Kivilinna 1916574e6c6SJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 1926574e6c6SJussi Kivilinna struct blkcipher_walk *walk) 1936574e6c6SJussi Kivilinna { 1946574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 1956574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 1966574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 1976574e6c6SJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 1986574e6c6SJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 1996574e6c6SJussi Kivilinna u64 ivs[3 - 1]; 2006574e6c6SJussi Kivilinna u64 last_iv; 2016574e6c6SJussi Kivilinna 2026574e6c6SJussi Kivilinna /* Start of the last block. */ 2036574e6c6SJussi Kivilinna src += nbytes / bsize - 1; 2046574e6c6SJussi Kivilinna dst += nbytes / bsize - 1; 2056574e6c6SJussi Kivilinna 2066574e6c6SJussi Kivilinna last_iv = *src; 2076574e6c6SJussi Kivilinna 2086574e6c6SJussi Kivilinna /* Process four block batch */ 2096574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 2106574e6c6SJussi Kivilinna do { 2116574e6c6SJussi Kivilinna nbytes -= bsize * 3 - bsize; 2126574e6c6SJussi Kivilinna src -= 3 - 1; 2136574e6c6SJussi Kivilinna dst -= 3 - 1; 2146574e6c6SJussi Kivilinna 2156574e6c6SJussi Kivilinna ivs[0] = src[0]; 2166574e6c6SJussi Kivilinna ivs[1] = src[1]; 2176574e6c6SJussi Kivilinna 2186574e6c6SJussi Kivilinna des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src); 2196574e6c6SJussi Kivilinna 2206574e6c6SJussi Kivilinna dst[1] ^= ivs[0]; 2216574e6c6SJussi Kivilinna dst[2] ^= ivs[1]; 2226574e6c6SJussi Kivilinna 2236574e6c6SJussi Kivilinna nbytes -= bsize; 2246574e6c6SJussi Kivilinna if (nbytes < bsize) 2256574e6c6SJussi Kivilinna goto done; 2266574e6c6SJussi Kivilinna 2276574e6c6SJussi Kivilinna *dst ^= *(src - 1); 2286574e6c6SJussi Kivilinna src -= 1; 2296574e6c6SJussi Kivilinna dst -= 1; 2306574e6c6SJussi Kivilinna } while (nbytes >= bsize * 3); 2316574e6c6SJussi Kivilinna } 2326574e6c6SJussi Kivilinna 2336574e6c6SJussi Kivilinna /* Handle leftovers */ 2346574e6c6SJussi Kivilinna for (;;) { 2356574e6c6SJussi Kivilinna des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src); 2366574e6c6SJussi Kivilinna 2376574e6c6SJussi Kivilinna nbytes -= bsize; 2386574e6c6SJussi Kivilinna if (nbytes < bsize) 2396574e6c6SJussi Kivilinna break; 2406574e6c6SJussi Kivilinna 2416574e6c6SJussi Kivilinna *dst ^= *(src - 1); 2426574e6c6SJussi Kivilinna src -= 1; 2436574e6c6SJussi Kivilinna dst -= 1; 2446574e6c6SJussi Kivilinna } 2456574e6c6SJussi Kivilinna 2466574e6c6SJussi Kivilinna done: 2476574e6c6SJussi Kivilinna *dst ^= *(u64 *)walk->iv; 2486574e6c6SJussi Kivilinna *(u64 *)walk->iv = last_iv; 2496574e6c6SJussi Kivilinna 2506574e6c6SJussi Kivilinna return nbytes; 2516574e6c6SJussi Kivilinna } 2526574e6c6SJussi Kivilinna 2536574e6c6SJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 2546574e6c6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 2556574e6c6SJussi Kivilinna { 2566574e6c6SJussi Kivilinna struct blkcipher_walk walk; 2576574e6c6SJussi Kivilinna int err; 2586574e6c6SJussi Kivilinna 2596574e6c6SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 2606574e6c6SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 2616574e6c6SJussi Kivilinna 2626574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes)) { 2636574e6c6SJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 2646574e6c6SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 2656574e6c6SJussi Kivilinna } 2666574e6c6SJussi Kivilinna 2676574e6c6SJussi Kivilinna return err; 2686574e6c6SJussi Kivilinna } 2696574e6c6SJussi Kivilinna 2706574e6c6SJussi Kivilinna static void ctr_crypt_final(struct des3_ede_x86_ctx *ctx, 2716574e6c6SJussi Kivilinna struct blkcipher_walk *walk) 2726574e6c6SJussi Kivilinna { 2736574e6c6SJussi Kivilinna u8 *ctrblk = walk->iv; 2746574e6c6SJussi Kivilinna u8 keystream[DES3_EDE_BLOCK_SIZE]; 2756574e6c6SJussi Kivilinna u8 *src = walk->src.virt.addr; 2766574e6c6SJussi Kivilinna u8 *dst = walk->dst.virt.addr; 2776574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 2786574e6c6SJussi Kivilinna 2796574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, keystream, ctrblk); 2806574e6c6SJussi Kivilinna crypto_xor(keystream, src, nbytes); 2816574e6c6SJussi Kivilinna memcpy(dst, keystream, nbytes); 2826574e6c6SJussi Kivilinna 2836574e6c6SJussi Kivilinna crypto_inc(ctrblk, DES3_EDE_BLOCK_SIZE); 2846574e6c6SJussi Kivilinna } 2856574e6c6SJussi Kivilinna 2866574e6c6SJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 2876574e6c6SJussi Kivilinna struct blkcipher_walk *walk) 2886574e6c6SJussi Kivilinna { 2896574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 2906574e6c6SJussi Kivilinna unsigned int bsize = DES3_EDE_BLOCK_SIZE; 2916574e6c6SJussi Kivilinna unsigned int nbytes = walk->nbytes; 2925e50d43dSJussi Kivilinna __be64 *src = (__be64 *)walk->src.virt.addr; 2935e50d43dSJussi Kivilinna __be64 *dst = (__be64 *)walk->dst.virt.addr; 2946574e6c6SJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 2956574e6c6SJussi Kivilinna __be64 ctrblocks[3]; 2966574e6c6SJussi Kivilinna 2976574e6c6SJussi Kivilinna /* Process four block batch */ 2986574e6c6SJussi Kivilinna if (nbytes >= bsize * 3) { 2996574e6c6SJussi Kivilinna do { 3006574e6c6SJussi Kivilinna /* create ctrblks for parallel encrypt */ 3016574e6c6SJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 3026574e6c6SJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 3036574e6c6SJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 3046574e6c6SJussi Kivilinna 3056574e6c6SJussi Kivilinna des3_ede_enc_blk_3way(ctx, (u8 *)ctrblocks, 3066574e6c6SJussi Kivilinna (u8 *)ctrblocks); 3076574e6c6SJussi Kivilinna 3086574e6c6SJussi Kivilinna dst[0] = src[0] ^ ctrblocks[0]; 3096574e6c6SJussi Kivilinna dst[1] = src[1] ^ ctrblocks[1]; 3106574e6c6SJussi Kivilinna dst[2] = src[2] ^ ctrblocks[2]; 3116574e6c6SJussi Kivilinna 3126574e6c6SJussi Kivilinna src += 3; 3136574e6c6SJussi Kivilinna dst += 3; 3146574e6c6SJussi Kivilinna } while ((nbytes -= bsize * 3) >= bsize * 3); 3156574e6c6SJussi Kivilinna 3166574e6c6SJussi Kivilinna if (nbytes < bsize) 3176574e6c6SJussi Kivilinna goto done; 3186574e6c6SJussi Kivilinna } 3196574e6c6SJussi Kivilinna 3206574e6c6SJussi Kivilinna /* Handle leftovers */ 3216574e6c6SJussi Kivilinna do { 3226574e6c6SJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 3236574e6c6SJussi Kivilinna 3246574e6c6SJussi Kivilinna des3_ede_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); 3256574e6c6SJussi Kivilinna 3266574e6c6SJussi Kivilinna dst[0] = src[0] ^ ctrblocks[0]; 3276574e6c6SJussi Kivilinna 3286574e6c6SJussi Kivilinna src += 1; 3296574e6c6SJussi Kivilinna dst += 1; 3306574e6c6SJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 3316574e6c6SJussi Kivilinna 3326574e6c6SJussi Kivilinna done: 3336574e6c6SJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 3346574e6c6SJussi Kivilinna return nbytes; 3356574e6c6SJussi Kivilinna } 3366574e6c6SJussi Kivilinna 3376574e6c6SJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 3386574e6c6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 3396574e6c6SJussi Kivilinna { 3406574e6c6SJussi Kivilinna struct blkcipher_walk walk; 3416574e6c6SJussi Kivilinna int err; 3426574e6c6SJussi Kivilinna 3436574e6c6SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 3446574e6c6SJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, DES3_EDE_BLOCK_SIZE); 3456574e6c6SJussi Kivilinna 3466574e6c6SJussi Kivilinna while ((nbytes = walk.nbytes) >= DES3_EDE_BLOCK_SIZE) { 3476574e6c6SJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 3486574e6c6SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 3496574e6c6SJussi Kivilinna } 3506574e6c6SJussi Kivilinna 3516574e6c6SJussi Kivilinna if (walk.nbytes) { 3526574e6c6SJussi Kivilinna ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk); 3536574e6c6SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 3546574e6c6SJussi Kivilinna } 3556574e6c6SJussi Kivilinna 3566574e6c6SJussi Kivilinna return err; 3576574e6c6SJussi Kivilinna } 3586574e6c6SJussi Kivilinna 3596574e6c6SJussi Kivilinna static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key, 3606574e6c6SJussi Kivilinna unsigned int keylen) 3616574e6c6SJussi Kivilinna { 3626574e6c6SJussi Kivilinna struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm); 3636574e6c6SJussi Kivilinna u32 i, j, tmp; 3646574e6c6SJussi Kivilinna int err; 3656574e6c6SJussi Kivilinna 3666574e6c6SJussi Kivilinna /* Generate encryption context using generic implementation. */ 3676574e6c6SJussi Kivilinna err = __des3_ede_setkey(ctx->enc_expkey, &tfm->crt_flags, key, keylen); 3686574e6c6SJussi Kivilinna if (err < 0) 3696574e6c6SJussi Kivilinna return err; 3706574e6c6SJussi Kivilinna 3716574e6c6SJussi Kivilinna /* Fix encryption context for this implementation and form decryption 3726574e6c6SJussi Kivilinna * context. */ 3736574e6c6SJussi Kivilinna j = DES3_EDE_EXPKEY_WORDS - 2; 3746574e6c6SJussi Kivilinna for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) { 3756574e6c6SJussi Kivilinna tmp = ror32(ctx->enc_expkey[i + 1], 4); 3766574e6c6SJussi Kivilinna ctx->enc_expkey[i + 1] = tmp; 3776574e6c6SJussi Kivilinna 3786574e6c6SJussi Kivilinna ctx->dec_expkey[j + 0] = ctx->enc_expkey[i + 0]; 3796574e6c6SJussi Kivilinna ctx->dec_expkey[j + 1] = tmp; 3806574e6c6SJussi Kivilinna } 3816574e6c6SJussi Kivilinna 3826574e6c6SJussi Kivilinna return 0; 3836574e6c6SJussi Kivilinna } 3846574e6c6SJussi Kivilinna 3856574e6c6SJussi Kivilinna static struct crypto_alg des3_ede_algs[4] = { { 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 } 4036574e6c6SJussi Kivilinna }, { 4046574e6c6SJussi Kivilinna .cra_name = "ecb(des3_ede)", 4056574e6c6SJussi Kivilinna .cra_driver_name = "ecb-des3_ede-asm", 4066574e6c6SJussi Kivilinna .cra_priority = 300, 4076574e6c6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 4086574e6c6SJussi Kivilinna .cra_blocksize = DES3_EDE_BLOCK_SIZE, 4096574e6c6SJussi Kivilinna .cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 4106574e6c6SJussi Kivilinna .cra_alignmask = 0, 4116574e6c6SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 4126574e6c6SJussi Kivilinna .cra_module = THIS_MODULE, 4136574e6c6SJussi Kivilinna .cra_u = { 4146574e6c6SJussi Kivilinna .blkcipher = { 4156574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4166574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4176574e6c6SJussi Kivilinna .setkey = des3_ede_x86_setkey, 4186574e6c6SJussi Kivilinna .encrypt = ecb_encrypt, 4196574e6c6SJussi Kivilinna .decrypt = ecb_decrypt, 4206574e6c6SJussi Kivilinna }, 4216574e6c6SJussi Kivilinna }, 4226574e6c6SJussi Kivilinna }, { 4236574e6c6SJussi Kivilinna .cra_name = "cbc(des3_ede)", 4246574e6c6SJussi Kivilinna .cra_driver_name = "cbc-des3_ede-asm", 4256574e6c6SJussi Kivilinna .cra_priority = 300, 4266574e6c6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 4276574e6c6SJussi Kivilinna .cra_blocksize = DES3_EDE_BLOCK_SIZE, 4286574e6c6SJussi Kivilinna .cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 4296574e6c6SJussi Kivilinna .cra_alignmask = 0, 4306574e6c6SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 4316574e6c6SJussi Kivilinna .cra_module = THIS_MODULE, 4326574e6c6SJussi Kivilinna .cra_u = { 4336574e6c6SJussi Kivilinna .blkcipher = { 4346574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4356574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4366574e6c6SJussi Kivilinna .ivsize = DES3_EDE_BLOCK_SIZE, 4376574e6c6SJussi Kivilinna .setkey = des3_ede_x86_setkey, 4386574e6c6SJussi Kivilinna .encrypt = cbc_encrypt, 4396574e6c6SJussi Kivilinna .decrypt = cbc_decrypt, 4406574e6c6SJussi Kivilinna }, 4416574e6c6SJussi Kivilinna }, 4426574e6c6SJussi Kivilinna }, { 4436574e6c6SJussi Kivilinna .cra_name = "ctr(des3_ede)", 4446574e6c6SJussi Kivilinna .cra_driver_name = "ctr-des3_ede-asm", 4456574e6c6SJussi Kivilinna .cra_priority = 300, 4466574e6c6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 4476574e6c6SJussi Kivilinna .cra_blocksize = 1, 4486574e6c6SJussi Kivilinna .cra_ctxsize = sizeof(struct des3_ede_x86_ctx), 4496574e6c6SJussi Kivilinna .cra_alignmask = 0, 4506574e6c6SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 4516574e6c6SJussi Kivilinna .cra_module = THIS_MODULE, 4526574e6c6SJussi Kivilinna .cra_u = { 4536574e6c6SJussi Kivilinna .blkcipher = { 4546574e6c6SJussi Kivilinna .min_keysize = DES3_EDE_KEY_SIZE, 4556574e6c6SJussi Kivilinna .max_keysize = DES3_EDE_KEY_SIZE, 4566574e6c6SJussi Kivilinna .ivsize = DES3_EDE_BLOCK_SIZE, 4576574e6c6SJussi Kivilinna .setkey = des3_ede_x86_setkey, 4586574e6c6SJussi Kivilinna .encrypt = ctr_crypt, 4596574e6c6SJussi Kivilinna .decrypt = ctr_crypt, 4606574e6c6SJussi Kivilinna }, 4616574e6c6SJussi Kivilinna }, 4626574e6c6SJussi Kivilinna } }; 4636574e6c6SJussi Kivilinna 4646574e6c6SJussi Kivilinna static bool is_blacklisted_cpu(void) 4656574e6c6SJussi Kivilinna { 4666574e6c6SJussi Kivilinna if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 4676574e6c6SJussi Kivilinna return false; 4686574e6c6SJussi Kivilinna 4696574e6c6SJussi Kivilinna if (boot_cpu_data.x86 == 0x0f) { 4706574e6c6SJussi Kivilinna /* 4716574e6c6SJussi Kivilinna * On Pentium 4, des3_ede-x86_64 is slower than generic C 4726574e6c6SJussi Kivilinna * implementation because use of 64bit rotates (which are really 4736574e6c6SJussi Kivilinna * slow on P4). Therefore blacklist P4s. 4746574e6c6SJussi Kivilinna */ 4756574e6c6SJussi Kivilinna return true; 4766574e6c6SJussi Kivilinna } 4776574e6c6SJussi Kivilinna 4786574e6c6SJussi Kivilinna return false; 4796574e6c6SJussi Kivilinna } 4806574e6c6SJussi Kivilinna 4816574e6c6SJussi Kivilinna static int force; 4826574e6c6SJussi Kivilinna module_param(force, int, 0); 4836574e6c6SJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 4846574e6c6SJussi Kivilinna 4856574e6c6SJussi Kivilinna static int __init des3_ede_x86_init(void) 4866574e6c6SJussi Kivilinna { 4876574e6c6SJussi Kivilinna if (!force && is_blacklisted_cpu()) { 4886574e6c6SJussi Kivilinna pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n"); 4896574e6c6SJussi Kivilinna return -ENODEV; 4906574e6c6SJussi Kivilinna } 4916574e6c6SJussi Kivilinna 4926574e6c6SJussi Kivilinna return crypto_register_algs(des3_ede_algs, ARRAY_SIZE(des3_ede_algs)); 4936574e6c6SJussi Kivilinna } 4946574e6c6SJussi Kivilinna 4956574e6c6SJussi Kivilinna static void __exit des3_ede_x86_fini(void) 4966574e6c6SJussi Kivilinna { 4976574e6c6SJussi Kivilinna crypto_unregister_algs(des3_ede_algs, ARRAY_SIZE(des3_ede_algs)); 4986574e6c6SJussi Kivilinna } 4996574e6c6SJussi Kivilinna 5006574e6c6SJussi Kivilinna module_init(des3_ede_x86_init); 5016574e6c6SJussi Kivilinna module_exit(des3_ede_x86_fini); 5026574e6c6SJussi Kivilinna 5036574e6c6SJussi Kivilinna MODULE_LICENSE("GPL"); 5046574e6c6SJussi Kivilinna MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized"); 505*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede"); 506*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("des3_ede-asm"); 507*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("des"); 508*5d26a105SKees Cook MODULE_ALIAS_CRYPTO("des-asm"); 5096574e6c6SJussi Kivilinna MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>"); 510