162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CMAC: Cipher Block Mode for Authentication 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on work by: 862306a36Sopenharmony_ci * Copyright © 2013 Tom St Denis <tstdenis@elliptictech.com> 962306a36Sopenharmony_ci * Based on crypto/xcbc.c: 1062306a36Sopenharmony_ci * Copyright © 2006 USAGI/WIDE Project, 1162306a36Sopenharmony_ci * Author: Kazunori Miyazawa <miyazawa@linux-ipv6.org> 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <crypto/internal/cipher.h> 1562306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * +------------------------ 2262306a36Sopenharmony_ci * | <parent tfm> 2362306a36Sopenharmony_ci * +------------------------ 2462306a36Sopenharmony_ci * | cmac_tfm_ctx 2562306a36Sopenharmony_ci * +------------------------ 2662306a36Sopenharmony_ci * | consts (block size * 2) 2762306a36Sopenharmony_ci * +------------------------ 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistruct cmac_tfm_ctx { 3062306a36Sopenharmony_ci struct crypto_cipher *child; 3162306a36Sopenharmony_ci u8 ctx[]; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * +------------------------ 3662306a36Sopenharmony_ci * | <shash desc> 3762306a36Sopenharmony_ci * +------------------------ 3862306a36Sopenharmony_ci * | cmac_desc_ctx 3962306a36Sopenharmony_ci * +------------------------ 4062306a36Sopenharmony_ci * | odds (block size) 4162306a36Sopenharmony_ci * +------------------------ 4262306a36Sopenharmony_ci * | prev (block size) 4362306a36Sopenharmony_ci * +------------------------ 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistruct cmac_desc_ctx { 4662306a36Sopenharmony_ci unsigned int len; 4762306a36Sopenharmony_ci u8 ctx[]; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int crypto_cmac_digest_setkey(struct crypto_shash *parent, 5162306a36Sopenharmony_ci const u8 *inkey, unsigned int keylen) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned long alignmask = crypto_shash_alignmask(parent); 5462306a36Sopenharmony_ci struct cmac_tfm_ctx *ctx = crypto_shash_ctx(parent); 5562306a36Sopenharmony_ci unsigned int bs = crypto_shash_blocksize(parent); 5662306a36Sopenharmony_ci __be64 *consts = PTR_ALIGN((void *)ctx->ctx, 5762306a36Sopenharmony_ci (alignmask | (__alignof__(__be64) - 1)) + 1); 5862306a36Sopenharmony_ci u64 _const[2]; 5962306a36Sopenharmony_ci int i, err = 0; 6062306a36Sopenharmony_ci u8 msb_mask, gfmask; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci err = crypto_cipher_setkey(ctx->child, inkey, keylen); 6362306a36Sopenharmony_ci if (err) 6462306a36Sopenharmony_ci return err; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* encrypt the zero block */ 6762306a36Sopenharmony_ci memset(consts, 0, bs); 6862306a36Sopenharmony_ci crypto_cipher_encrypt_one(ctx->child, (u8 *)consts, (u8 *)consts); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci switch (bs) { 7162306a36Sopenharmony_ci case 16: 7262306a36Sopenharmony_ci gfmask = 0x87; 7362306a36Sopenharmony_ci _const[0] = be64_to_cpu(consts[1]); 7462306a36Sopenharmony_ci _const[1] = be64_to_cpu(consts[0]); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* gf(2^128) multiply zero-ciphertext with u and u^2 */ 7762306a36Sopenharmony_ci for (i = 0; i < 4; i += 2) { 7862306a36Sopenharmony_ci msb_mask = ((s64)_const[1] >> 63) & gfmask; 7962306a36Sopenharmony_ci _const[1] = (_const[1] << 1) | (_const[0] >> 63); 8062306a36Sopenharmony_ci _const[0] = (_const[0] << 1) ^ msb_mask; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci consts[i + 0] = cpu_to_be64(_const[1]); 8362306a36Sopenharmony_ci consts[i + 1] = cpu_to_be64(_const[0]); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci case 8: 8862306a36Sopenharmony_ci gfmask = 0x1B; 8962306a36Sopenharmony_ci _const[0] = be64_to_cpu(consts[0]); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* gf(2^64) multiply zero-ciphertext with u and u^2 */ 9262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 9362306a36Sopenharmony_ci msb_mask = ((s64)_const[0] >> 63) & gfmask; 9462306a36Sopenharmony_ci _const[0] = (_const[0] << 1) ^ msb_mask; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci consts[i] = cpu_to_be64(_const[0]); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int crypto_cmac_digest_init(struct shash_desc *pdesc) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm); 10862306a36Sopenharmony_ci struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc); 10962306a36Sopenharmony_ci int bs = crypto_shash_blocksize(pdesc->tfm); 11062306a36Sopenharmony_ci u8 *prev = PTR_ALIGN((void *)ctx->ctx, alignmask + 1) + bs; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci ctx->len = 0; 11362306a36Sopenharmony_ci memset(prev, 0, bs); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int crypto_cmac_digest_update(struct shash_desc *pdesc, const u8 *p, 11962306a36Sopenharmony_ci unsigned int len) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct crypto_shash *parent = pdesc->tfm; 12262306a36Sopenharmony_ci unsigned long alignmask = crypto_shash_alignmask(parent); 12362306a36Sopenharmony_ci struct cmac_tfm_ctx *tctx = crypto_shash_ctx(parent); 12462306a36Sopenharmony_ci struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc); 12562306a36Sopenharmony_ci struct crypto_cipher *tfm = tctx->child; 12662306a36Sopenharmony_ci int bs = crypto_shash_blocksize(parent); 12762306a36Sopenharmony_ci u8 *odds = PTR_ALIGN((void *)ctx->ctx, alignmask + 1); 12862306a36Sopenharmony_ci u8 *prev = odds + bs; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* checking the data can fill the block */ 13162306a36Sopenharmony_ci if ((ctx->len + len) <= bs) { 13262306a36Sopenharmony_ci memcpy(odds + ctx->len, p, len); 13362306a36Sopenharmony_ci ctx->len += len; 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* filling odds with new data and encrypting it */ 13862306a36Sopenharmony_ci memcpy(odds + ctx->len, p, bs - ctx->len); 13962306a36Sopenharmony_ci len -= bs - ctx->len; 14062306a36Sopenharmony_ci p += bs - ctx->len; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci crypto_xor(prev, odds, bs); 14362306a36Sopenharmony_ci crypto_cipher_encrypt_one(tfm, prev, prev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* clearing the length */ 14662306a36Sopenharmony_ci ctx->len = 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* encrypting the rest of data */ 14962306a36Sopenharmony_ci while (len > bs) { 15062306a36Sopenharmony_ci crypto_xor(prev, p, bs); 15162306a36Sopenharmony_ci crypto_cipher_encrypt_one(tfm, prev, prev); 15262306a36Sopenharmony_ci p += bs; 15362306a36Sopenharmony_ci len -= bs; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* keeping the surplus of blocksize */ 15762306a36Sopenharmony_ci if (len) { 15862306a36Sopenharmony_ci memcpy(odds, p, len); 15962306a36Sopenharmony_ci ctx->len = len; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int crypto_cmac_digest_final(struct shash_desc *pdesc, u8 *out) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct crypto_shash *parent = pdesc->tfm; 16862306a36Sopenharmony_ci unsigned long alignmask = crypto_shash_alignmask(parent); 16962306a36Sopenharmony_ci struct cmac_tfm_ctx *tctx = crypto_shash_ctx(parent); 17062306a36Sopenharmony_ci struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc); 17162306a36Sopenharmony_ci struct crypto_cipher *tfm = tctx->child; 17262306a36Sopenharmony_ci int bs = crypto_shash_blocksize(parent); 17362306a36Sopenharmony_ci u8 *consts = PTR_ALIGN((void *)tctx->ctx, 17462306a36Sopenharmony_ci (alignmask | (__alignof__(__be64) - 1)) + 1); 17562306a36Sopenharmony_ci u8 *odds = PTR_ALIGN((void *)ctx->ctx, alignmask + 1); 17662306a36Sopenharmony_ci u8 *prev = odds + bs; 17762306a36Sopenharmony_ci unsigned int offset = 0; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (ctx->len != bs) { 18062306a36Sopenharmony_ci unsigned int rlen; 18162306a36Sopenharmony_ci u8 *p = odds + ctx->len; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci *p = 0x80; 18462306a36Sopenharmony_ci p++; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci rlen = bs - ctx->len - 1; 18762306a36Sopenharmony_ci if (rlen) 18862306a36Sopenharmony_ci memset(p, 0, rlen); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci offset += bs; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci crypto_xor(prev, odds, bs); 19462306a36Sopenharmony_ci crypto_xor(prev, consts + offset, bs); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci crypto_cipher_encrypt_one(tfm, out, prev); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int cmac_init_tfm(struct crypto_shash *tfm) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct shash_instance *inst = shash_alg_instance(tfm); 20462306a36Sopenharmony_ci struct cmac_tfm_ctx *ctx = crypto_shash_ctx(tfm); 20562306a36Sopenharmony_ci struct crypto_cipher_spawn *spawn; 20662306a36Sopenharmony_ci struct crypto_cipher *cipher; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spawn = shash_instance_ctx(inst); 20962306a36Sopenharmony_ci cipher = crypto_spawn_cipher(spawn); 21062306a36Sopenharmony_ci if (IS_ERR(cipher)) 21162306a36Sopenharmony_ci return PTR_ERR(cipher); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ctx->child = cipher; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int cmac_clone_tfm(struct crypto_shash *tfm, struct crypto_shash *otfm) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct cmac_tfm_ctx *octx = crypto_shash_ctx(otfm); 22162306a36Sopenharmony_ci struct cmac_tfm_ctx *ctx = crypto_shash_ctx(tfm); 22262306a36Sopenharmony_ci struct crypto_cipher *cipher; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci cipher = crypto_clone_cipher(octx->child); 22562306a36Sopenharmony_ci if (IS_ERR(cipher)) 22662306a36Sopenharmony_ci return PTR_ERR(cipher); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ctx->child = cipher; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void cmac_exit_tfm(struct crypto_shash *tfm) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct cmac_tfm_ctx *ctx = crypto_shash_ctx(tfm); 23662306a36Sopenharmony_ci crypto_free_cipher(ctx->child); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int cmac_create(struct crypto_template *tmpl, struct rtattr **tb) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct shash_instance *inst; 24262306a36Sopenharmony_ci struct crypto_cipher_spawn *spawn; 24362306a36Sopenharmony_ci struct crypto_alg *alg; 24462306a36Sopenharmony_ci unsigned long alignmask; 24562306a36Sopenharmony_ci u32 mask; 24662306a36Sopenharmony_ci int err; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH, &mask); 24962306a36Sopenharmony_ci if (err) 25062306a36Sopenharmony_ci return err; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); 25362306a36Sopenharmony_ci if (!inst) 25462306a36Sopenharmony_ci return -ENOMEM; 25562306a36Sopenharmony_ci spawn = shash_instance_ctx(inst); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci err = crypto_grab_cipher(spawn, shash_crypto_instance(inst), 25862306a36Sopenharmony_ci crypto_attr_alg_name(tb[1]), 0, mask); 25962306a36Sopenharmony_ci if (err) 26062306a36Sopenharmony_ci goto err_free_inst; 26162306a36Sopenharmony_ci alg = crypto_spawn_cipher_alg(spawn); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci switch (alg->cra_blocksize) { 26462306a36Sopenharmony_ci case 16: 26562306a36Sopenharmony_ci case 8: 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci default: 26862306a36Sopenharmony_ci err = -EINVAL; 26962306a36Sopenharmony_ci goto err_free_inst; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci err = crypto_inst_setname(shash_crypto_instance(inst), tmpl->name, alg); 27362306a36Sopenharmony_ci if (err) 27462306a36Sopenharmony_ci goto err_free_inst; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci alignmask = alg->cra_alignmask; 27762306a36Sopenharmony_ci inst->alg.base.cra_alignmask = alignmask; 27862306a36Sopenharmony_ci inst->alg.base.cra_priority = alg->cra_priority; 27962306a36Sopenharmony_ci inst->alg.base.cra_blocksize = alg->cra_blocksize; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci inst->alg.digestsize = alg->cra_blocksize; 28262306a36Sopenharmony_ci inst->alg.descsize = 28362306a36Sopenharmony_ci ALIGN(sizeof(struct cmac_desc_ctx), crypto_tfm_ctx_alignment()) 28462306a36Sopenharmony_ci + (alignmask & ~(crypto_tfm_ctx_alignment() - 1)) 28562306a36Sopenharmony_ci + alg->cra_blocksize * 2; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci inst->alg.base.cra_ctxsize = 28862306a36Sopenharmony_ci ALIGN(sizeof(struct cmac_tfm_ctx), crypto_tfm_ctx_alignment()) 28962306a36Sopenharmony_ci + ((alignmask | (__alignof__(__be64) - 1)) & 29062306a36Sopenharmony_ci ~(crypto_tfm_ctx_alignment() - 1)) 29162306a36Sopenharmony_ci + alg->cra_blocksize * 2; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci inst->alg.init = crypto_cmac_digest_init; 29462306a36Sopenharmony_ci inst->alg.update = crypto_cmac_digest_update; 29562306a36Sopenharmony_ci inst->alg.final = crypto_cmac_digest_final; 29662306a36Sopenharmony_ci inst->alg.setkey = crypto_cmac_digest_setkey; 29762306a36Sopenharmony_ci inst->alg.init_tfm = cmac_init_tfm; 29862306a36Sopenharmony_ci inst->alg.clone_tfm = cmac_clone_tfm; 29962306a36Sopenharmony_ci inst->alg.exit_tfm = cmac_exit_tfm; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci inst->free = shash_free_singlespawn_instance; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci err = shash_register_instance(tmpl, inst); 30462306a36Sopenharmony_ci if (err) { 30562306a36Sopenharmony_cierr_free_inst: 30662306a36Sopenharmony_ci shash_free_singlespawn_instance(inst); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci return err; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic struct crypto_template crypto_cmac_tmpl = { 31262306a36Sopenharmony_ci .name = "cmac", 31362306a36Sopenharmony_ci .create = cmac_create, 31462306a36Sopenharmony_ci .module = THIS_MODULE, 31562306a36Sopenharmony_ci}; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int __init crypto_cmac_module_init(void) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci return crypto_register_template(&crypto_cmac_tmpl); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void __exit crypto_cmac_module_exit(void) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci crypto_unregister_template(&crypto_cmac_tmpl); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cisubsys_initcall(crypto_cmac_module_init); 32862306a36Sopenharmony_cimodule_exit(crypto_cmac_module_exit); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 33162306a36Sopenharmony_ciMODULE_DESCRIPTION("CMAC keyed hash algorithm"); 33262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("cmac"); 33362306a36Sopenharmony_ciMODULE_IMPORT_NS(CRYPTO_INTERNAL); 334