1333b0d7eSKazunori MIYAZAWA /* 2333b0d7eSKazunori MIYAZAWA * Copyright (C)2006 USAGI/WIDE Project 3333b0d7eSKazunori MIYAZAWA * 4333b0d7eSKazunori MIYAZAWA * This program is free software; you can redistribute it and/or modify 5333b0d7eSKazunori MIYAZAWA * it under the terms of the GNU General Public License as published by 6333b0d7eSKazunori MIYAZAWA * the Free Software Foundation; either version 2 of the License, or 7333b0d7eSKazunori MIYAZAWA * (at your option) any later version. 8333b0d7eSKazunori MIYAZAWA * 9333b0d7eSKazunori MIYAZAWA * This program is distributed in the hope that it will be useful, 10333b0d7eSKazunori MIYAZAWA * but WITHOUT ANY WARRANTY; without even the implied warranty of 11333b0d7eSKazunori MIYAZAWA * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12333b0d7eSKazunori MIYAZAWA * GNU General Public License for more details. 13333b0d7eSKazunori MIYAZAWA * 14333b0d7eSKazunori MIYAZAWA * You should have received a copy of the GNU General Public License 15333b0d7eSKazunori MIYAZAWA * along with this program; if not, write to the Free Software 16333b0d7eSKazunori MIYAZAWA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17333b0d7eSKazunori MIYAZAWA * 18333b0d7eSKazunori MIYAZAWA * Author: 19333b0d7eSKazunori MIYAZAWA * Kazunori Miyazawa <miyazawa@linux-ipv6.org> 20333b0d7eSKazunori MIYAZAWA */ 21333b0d7eSKazunori MIYAZAWA 223106caabSHerbert Xu #include <crypto/internal/hash.h> 23333b0d7eSKazunori MIYAZAWA #include <linux/err.h> 24333b0d7eSKazunori MIYAZAWA #include <linux/kernel.h> 254bb33cc8SPaul Gortmaker #include <linux/module.h> 26333b0d7eSKazunori MIYAZAWA 275b37538aSAdrian Bunk static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101, 28333b0d7eSKazunori MIYAZAWA 0x02020202, 0x02020202, 0x02020202, 0x02020202, 29333b0d7eSKazunori MIYAZAWA 0x03030303, 0x03030303, 0x03030303, 0x03030303}; 30ac95301fSHerbert Xu 31333b0d7eSKazunori MIYAZAWA /* 32333b0d7eSKazunori MIYAZAWA * +------------------------ 33333b0d7eSKazunori MIYAZAWA * | <parent tfm> 34333b0d7eSKazunori MIYAZAWA * +------------------------ 35ac95301fSHerbert Xu * | xcbc_tfm_ctx 36ac95301fSHerbert Xu * +------------------------ 37ac95301fSHerbert Xu * | consts (block size * 2) 38ac95301fSHerbert Xu * +------------------------ 39ac95301fSHerbert Xu */ 40ac95301fSHerbert Xu struct xcbc_tfm_ctx { 41ac95301fSHerbert Xu struct crypto_cipher *child; 42ac95301fSHerbert Xu u8 ctx[]; 43ac95301fSHerbert Xu }; 44ac95301fSHerbert Xu 45ac95301fSHerbert Xu /* 46ac95301fSHerbert Xu * +------------------------ 47ac95301fSHerbert Xu * | <shash desc> 48ac95301fSHerbert Xu * +------------------------ 49ac95301fSHerbert Xu * | xcbc_desc_ctx 50333b0d7eSKazunori MIYAZAWA * +------------------------ 51333b0d7eSKazunori MIYAZAWA * | odds (block size) 52333b0d7eSKazunori MIYAZAWA * +------------------------ 53333b0d7eSKazunori MIYAZAWA * | prev (block size) 54333b0d7eSKazunori MIYAZAWA * +------------------------ 55333b0d7eSKazunori MIYAZAWA */ 56ac95301fSHerbert Xu struct xcbc_desc_ctx { 57333b0d7eSKazunori MIYAZAWA unsigned int len; 58ac95301fSHerbert Xu u8 ctx[]; 59333b0d7eSKazunori MIYAZAWA }; 60333b0d7eSKazunori MIYAZAWA 613106caabSHerbert Xu static int crypto_xcbc_digest_setkey(struct crypto_shash *parent, 62333b0d7eSKazunori MIYAZAWA const u8 *inkey, unsigned int keylen) 63333b0d7eSKazunori MIYAZAWA { 64ac95301fSHerbert Xu unsigned long alignmask = crypto_shash_alignmask(parent); 65ac95301fSHerbert Xu struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent); 66ac95301fSHerbert Xu int bs = crypto_shash_blocksize(parent); 67ac95301fSHerbert Xu u8 *consts = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); 68ac95301fSHerbert Xu int err = 0; 69ac95301fSHerbert Xu u8 key1[bs]; 70333b0d7eSKazunori MIYAZAWA 71ac95301fSHerbert Xu if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen))) 72ac95301fSHerbert Xu return err; 73333b0d7eSKazunori MIYAZAWA 74ac95301fSHerbert Xu crypto_cipher_encrypt_one(ctx->child, consts, (u8 *)ks + bs); 75ac95301fSHerbert Xu crypto_cipher_encrypt_one(ctx->child, consts + bs, (u8 *)ks + bs * 2); 76ac95301fSHerbert Xu crypto_cipher_encrypt_one(ctx->child, key1, (u8 *)ks); 77333b0d7eSKazunori MIYAZAWA 78ac95301fSHerbert Xu return crypto_cipher_setkey(ctx->child, key1, bs); 79ac95301fSHerbert Xu 80333b0d7eSKazunori MIYAZAWA } 81333b0d7eSKazunori MIYAZAWA 823106caabSHerbert Xu static int crypto_xcbc_digest_init(struct shash_desc *pdesc) 83333b0d7eSKazunori MIYAZAWA { 84ac95301fSHerbert Xu unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm); 85ac95301fSHerbert Xu struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc); 863106caabSHerbert Xu int bs = crypto_shash_blocksize(pdesc->tfm); 87ac95301fSHerbert Xu u8 *prev = PTR_ALIGN(&ctx->ctx[0], alignmask + 1) + bs; 88333b0d7eSKazunori MIYAZAWA 89333b0d7eSKazunori MIYAZAWA ctx->len = 0; 90ac95301fSHerbert Xu memset(prev, 0, bs); 91333b0d7eSKazunori MIYAZAWA 92333b0d7eSKazunori MIYAZAWA return 0; 93333b0d7eSKazunori MIYAZAWA } 94333b0d7eSKazunori MIYAZAWA 953106caabSHerbert Xu static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p, 963106caabSHerbert Xu unsigned int len) 97333b0d7eSKazunori MIYAZAWA { 983106caabSHerbert Xu struct crypto_shash *parent = pdesc->tfm; 99ac95301fSHerbert Xu unsigned long alignmask = crypto_shash_alignmask(parent); 100ac95301fSHerbert Xu struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent); 101ac95301fSHerbert Xu struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc); 102ac95301fSHerbert Xu struct crypto_cipher *tfm = tctx->child; 1033106caabSHerbert Xu int bs = crypto_shash_blocksize(parent); 104ac95301fSHerbert Xu u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); 105ac95301fSHerbert Xu u8 *prev = odds + bs; 106333b0d7eSKazunori MIYAZAWA 107333b0d7eSKazunori MIYAZAWA /* checking the data can fill the block */ 108333b0d7eSKazunori MIYAZAWA if ((ctx->len + len) <= bs) { 109ac95301fSHerbert Xu memcpy(odds + ctx->len, p, len); 110333b0d7eSKazunori MIYAZAWA ctx->len += len; 1113106caabSHerbert Xu return 0; 112333b0d7eSKazunori MIYAZAWA } 113333b0d7eSKazunori MIYAZAWA 114333b0d7eSKazunori MIYAZAWA /* filling odds with new data and encrypting it */ 115ac95301fSHerbert Xu memcpy(odds + ctx->len, p, bs - ctx->len); 116333b0d7eSKazunori MIYAZAWA len -= bs - ctx->len; 117333b0d7eSKazunori MIYAZAWA p += bs - ctx->len; 118333b0d7eSKazunori MIYAZAWA 119ac95301fSHerbert Xu crypto_xor(prev, odds, bs); 120ac95301fSHerbert Xu crypto_cipher_encrypt_one(tfm, prev, prev); 121333b0d7eSKazunori MIYAZAWA 122333b0d7eSKazunori MIYAZAWA /* clearing the length */ 123333b0d7eSKazunori MIYAZAWA ctx->len = 0; 124333b0d7eSKazunori MIYAZAWA 125333b0d7eSKazunori MIYAZAWA /* encrypting the rest of data */ 126333b0d7eSKazunori MIYAZAWA while (len > bs) { 127ac95301fSHerbert Xu crypto_xor(prev, p, bs); 128ac95301fSHerbert Xu crypto_cipher_encrypt_one(tfm, prev, prev); 129333b0d7eSKazunori MIYAZAWA p += bs; 130333b0d7eSKazunori MIYAZAWA len -= bs; 131333b0d7eSKazunori MIYAZAWA } 132333b0d7eSKazunori MIYAZAWA 133333b0d7eSKazunori MIYAZAWA /* keeping the surplus of blocksize */ 134333b0d7eSKazunori MIYAZAWA if (len) { 135ac95301fSHerbert Xu memcpy(odds, p, len); 136333b0d7eSKazunori MIYAZAWA ctx->len = len; 137333b0d7eSKazunori MIYAZAWA } 138333b0d7eSKazunori MIYAZAWA 139333b0d7eSKazunori MIYAZAWA return 0; 140333b0d7eSKazunori MIYAZAWA } 141333b0d7eSKazunori MIYAZAWA 1423106caabSHerbert Xu static int crypto_xcbc_digest_final(struct shash_desc *pdesc, u8 *out) 143fb469840SHerbert Xu { 1443106caabSHerbert Xu struct crypto_shash *parent = pdesc->tfm; 145ac95301fSHerbert Xu unsigned long alignmask = crypto_shash_alignmask(parent); 146ac95301fSHerbert Xu struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent); 147ac95301fSHerbert Xu struct xcbc_desc_ctx *ctx = shash_desc_ctx(pdesc); 148ac95301fSHerbert Xu struct crypto_cipher *tfm = tctx->child; 1493106caabSHerbert Xu int bs = crypto_shash_blocksize(parent); 150ac95301fSHerbert Xu u8 *consts = PTR_ALIGN(&tctx->ctx[0], alignmask + 1); 151ac95301fSHerbert Xu u8 *odds = PTR_ALIGN(&ctx->ctx[0], alignmask + 1); 152ac95301fSHerbert Xu u8 *prev = odds + bs; 153ac95301fSHerbert Xu unsigned int offset = 0; 154333b0d7eSKazunori MIYAZAWA 155ac95301fSHerbert Xu if (ctx->len != bs) { 156333b0d7eSKazunori MIYAZAWA unsigned int rlen; 157ac95301fSHerbert Xu u8 *p = odds + ctx->len; 158ac95301fSHerbert Xu 159333b0d7eSKazunori MIYAZAWA *p = 0x80; 160333b0d7eSKazunori MIYAZAWA p++; 161333b0d7eSKazunori MIYAZAWA 162333b0d7eSKazunori MIYAZAWA rlen = bs - ctx->len -1; 163333b0d7eSKazunori MIYAZAWA if (rlen) 164333b0d7eSKazunori MIYAZAWA memset(p, 0, rlen); 165333b0d7eSKazunori MIYAZAWA 166ac95301fSHerbert Xu offset += bs; 167333b0d7eSKazunori MIYAZAWA } 168333b0d7eSKazunori MIYAZAWA 169ac95301fSHerbert Xu crypto_xor(prev, odds, bs); 170ac95301fSHerbert Xu crypto_xor(prev, consts + offset, bs); 171ac95301fSHerbert Xu 172ac95301fSHerbert Xu crypto_cipher_encrypt_one(tfm, out, prev); 173ac95301fSHerbert Xu 174333b0d7eSKazunori MIYAZAWA return 0; 175333b0d7eSKazunori MIYAZAWA } 176333b0d7eSKazunori MIYAZAWA 177333b0d7eSKazunori MIYAZAWA static int xcbc_init_tfm(struct crypto_tfm *tfm) 178333b0d7eSKazunori MIYAZAWA { 1792e306ee0SHerbert Xu struct crypto_cipher *cipher; 180333b0d7eSKazunori MIYAZAWA struct crypto_instance *inst = (void *)tfm->__crt_alg; 181333b0d7eSKazunori MIYAZAWA struct crypto_spawn *spawn = crypto_instance_ctx(inst); 182ac95301fSHerbert Xu struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm); 183333b0d7eSKazunori MIYAZAWA 1842e306ee0SHerbert Xu cipher = crypto_spawn_cipher(spawn); 1852e306ee0SHerbert Xu if (IS_ERR(cipher)) 1862e306ee0SHerbert Xu return PTR_ERR(cipher); 187333b0d7eSKazunori MIYAZAWA 1882e306ee0SHerbert Xu ctx->child = cipher; 189333b0d7eSKazunori MIYAZAWA 190333b0d7eSKazunori MIYAZAWA return 0; 191333b0d7eSKazunori MIYAZAWA }; 192333b0d7eSKazunori MIYAZAWA 193333b0d7eSKazunori MIYAZAWA static void xcbc_exit_tfm(struct crypto_tfm *tfm) 194333b0d7eSKazunori MIYAZAWA { 195ac95301fSHerbert Xu struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm); 196333b0d7eSKazunori MIYAZAWA crypto_free_cipher(ctx->child); 197333b0d7eSKazunori MIYAZAWA } 198333b0d7eSKazunori MIYAZAWA 1993106caabSHerbert Xu static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb) 200333b0d7eSKazunori MIYAZAWA { 2013106caabSHerbert Xu struct shash_instance *inst; 202333b0d7eSKazunori MIYAZAWA struct crypto_alg *alg; 20336f87a4aSSteffen Klassert unsigned long alignmask; 204ebc610e5SHerbert Xu int err; 205ebc610e5SHerbert Xu 2063106caabSHerbert Xu err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); 207ebc610e5SHerbert Xu if (err) 2083106caabSHerbert Xu return err; 209ebc610e5SHerbert Xu 210ebc610e5SHerbert Xu alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, 211ebc610e5SHerbert Xu CRYPTO_ALG_TYPE_MASK); 212333b0d7eSKazunori MIYAZAWA if (IS_ERR(alg)) 2133106caabSHerbert Xu return PTR_ERR(alg); 214333b0d7eSKazunori MIYAZAWA 215333b0d7eSKazunori MIYAZAWA switch(alg->cra_blocksize) { 216333b0d7eSKazunori MIYAZAWA case 16: 217333b0d7eSKazunori MIYAZAWA break; 218333b0d7eSKazunori MIYAZAWA default: 2191b87887dSHerbert Xu goto out_put_alg; 220333b0d7eSKazunori MIYAZAWA } 221333b0d7eSKazunori MIYAZAWA 2223106caabSHerbert Xu inst = shash_alloc_instance("xcbc", alg); 223b5ebd44eSHerbert Xu err = PTR_ERR(inst); 224333b0d7eSKazunori MIYAZAWA if (IS_ERR(inst)) 225333b0d7eSKazunori MIYAZAWA goto out_put_alg; 226333b0d7eSKazunori MIYAZAWA 2273106caabSHerbert Xu err = crypto_init_spawn(shash_instance_ctx(inst), alg, 2283106caabSHerbert Xu shash_crypto_instance(inst), 2293106caabSHerbert Xu CRYPTO_ALG_TYPE_MASK); 2303106caabSHerbert Xu if (err) 2313106caabSHerbert Xu goto out_free_inst; 232333b0d7eSKazunori MIYAZAWA 23336f87a4aSSteffen Klassert alignmask = alg->cra_alignmask | 3; 23436f87a4aSSteffen Klassert inst->alg.base.cra_alignmask = alignmask; 2353106caabSHerbert Xu inst->alg.base.cra_priority = alg->cra_priority; 2363106caabSHerbert Xu inst->alg.base.cra_blocksize = alg->cra_blocksize; 237333b0d7eSKazunori MIYAZAWA 2383106caabSHerbert Xu inst->alg.digestsize = alg->cra_blocksize; 239ac95301fSHerbert Xu inst->alg.descsize = ALIGN(sizeof(struct xcbc_desc_ctx), 240ac95301fSHerbert Xu crypto_tfm_ctx_alignment()) + 24136f87a4aSSteffen Klassert (alignmask & 242ac95301fSHerbert Xu ~(crypto_tfm_ctx_alignment() - 1)) + 243ac95301fSHerbert Xu alg->cra_blocksize * 2; 244ac95301fSHerbert Xu 245ac95301fSHerbert Xu inst->alg.base.cra_ctxsize = ALIGN(sizeof(struct xcbc_tfm_ctx), 24636f87a4aSSteffen Klassert alignmask + 1) + 247ac95301fSHerbert Xu alg->cra_blocksize * 2; 2483106caabSHerbert Xu inst->alg.base.cra_init = xcbc_init_tfm; 2493106caabSHerbert Xu inst->alg.base.cra_exit = xcbc_exit_tfm; 2503106caabSHerbert Xu 2513106caabSHerbert Xu inst->alg.init = crypto_xcbc_digest_init; 2523106caabSHerbert Xu inst->alg.update = crypto_xcbc_digest_update; 2533106caabSHerbert Xu inst->alg.final = crypto_xcbc_digest_final; 2543106caabSHerbert Xu inst->alg.setkey = crypto_xcbc_digest_setkey; 2553106caabSHerbert Xu 2563106caabSHerbert Xu err = shash_register_instance(tmpl, inst); 2573106caabSHerbert Xu if (err) { 2583106caabSHerbert Xu out_free_inst: 2593106caabSHerbert Xu shash_free_instance(shash_crypto_instance(inst)); 2603106caabSHerbert Xu } 261333b0d7eSKazunori MIYAZAWA 262333b0d7eSKazunori MIYAZAWA out_put_alg: 263333b0d7eSKazunori MIYAZAWA crypto_mod_put(alg); 2643106caabSHerbert Xu return err; 265333b0d7eSKazunori MIYAZAWA } 266333b0d7eSKazunori MIYAZAWA 267333b0d7eSKazunori MIYAZAWA static struct crypto_template crypto_xcbc_tmpl = { 268333b0d7eSKazunori MIYAZAWA .name = "xcbc", 2693106caabSHerbert Xu .create = xcbc_create, 2703106caabSHerbert Xu .free = shash_free_instance, 271333b0d7eSKazunori MIYAZAWA .module = THIS_MODULE, 272333b0d7eSKazunori MIYAZAWA }; 273333b0d7eSKazunori MIYAZAWA 274333b0d7eSKazunori MIYAZAWA static int __init crypto_xcbc_module_init(void) 275333b0d7eSKazunori MIYAZAWA { 276333b0d7eSKazunori MIYAZAWA return crypto_register_template(&crypto_xcbc_tmpl); 277333b0d7eSKazunori MIYAZAWA } 278333b0d7eSKazunori MIYAZAWA 279333b0d7eSKazunori MIYAZAWA static void __exit crypto_xcbc_module_exit(void) 280333b0d7eSKazunori MIYAZAWA { 281333b0d7eSKazunori MIYAZAWA crypto_unregister_template(&crypto_xcbc_tmpl); 282333b0d7eSKazunori MIYAZAWA } 283333b0d7eSKazunori MIYAZAWA 284333b0d7eSKazunori MIYAZAWA module_init(crypto_xcbc_module_init); 285333b0d7eSKazunori MIYAZAWA module_exit(crypto_xcbc_module_exit); 286333b0d7eSKazunori MIYAZAWA 287333b0d7eSKazunori MIYAZAWA MODULE_LICENSE("GPL"); 288333b0d7eSKazunori MIYAZAWA MODULE_DESCRIPTION("XCBC keyed hash algorithm"); 289*4943ba16SKees Cook MODULE_ALIAS_CRYPTO("xcbc"); 290