brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · c7aa366 Raw
317 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * CMAC: Cipher Block Mode for Authentication4 *5 * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>6 *7 * Based on work by:8 *  Copyright © 2013 Tom St Denis <tstdenis@elliptictech.com>9 * Based on crypto/xcbc.c:10 *  Copyright © 2006 USAGI/WIDE Project,11 *   Author: Kazunori Miyazawa <miyazawa@linux-ipv6.org>12 */13 14#include <crypto/internal/cipher.h>15#include <crypto/internal/hash.h>16#include <linux/err.h>17#include <linux/kernel.h>18#include <linux/module.h>19 20/*21 * +------------------------22 * | <parent tfm>23 * +------------------------24 * | cmac_tfm_ctx25 * +------------------------26 * | consts (block size * 2)27 * +------------------------28 */29struct cmac_tfm_ctx {30	struct crypto_cipher *child;31	__be64 consts[];32};33 34/*35 * +------------------------36 * | <shash desc>37 * +------------------------38 * | cmac_desc_ctx39 * +------------------------40 * | odds (block size)41 * +------------------------42 * | prev (block size)43 * +------------------------44 */45struct cmac_desc_ctx {46	unsigned int len;47	u8 odds[];48};49 50static int crypto_cmac_digest_setkey(struct crypto_shash *parent,51				     const u8 *inkey, unsigned int keylen)52{53	struct cmac_tfm_ctx *ctx = crypto_shash_ctx(parent);54	unsigned int bs = crypto_shash_blocksize(parent);55	__be64 *consts = ctx->consts;56	u64 _const[2];57	int i, err = 0;58	u8 msb_mask, gfmask;59 60	err = crypto_cipher_setkey(ctx->child, inkey, keylen);61	if (err)62		return err;63 64	/* encrypt the zero block */65	memset(consts, 0, bs);66	crypto_cipher_encrypt_one(ctx->child, (u8 *)consts, (u8 *)consts);67 68	switch (bs) {69	case 16:70		gfmask = 0x87;71		_const[0] = be64_to_cpu(consts[1]);72		_const[1] = be64_to_cpu(consts[0]);73 74		/* gf(2^128) multiply zero-ciphertext with u and u^2 */75		for (i = 0; i < 4; i += 2) {76			msb_mask = ((s64)_const[1] >> 63) & gfmask;77			_const[1] = (_const[1] << 1) | (_const[0] >> 63);78			_const[0] = (_const[0] << 1) ^ msb_mask;79 80			consts[i + 0] = cpu_to_be64(_const[1]);81			consts[i + 1] = cpu_to_be64(_const[0]);82		}83 84		break;85	case 8:86		gfmask = 0x1B;87		_const[0] = be64_to_cpu(consts[0]);88 89		/* gf(2^64) multiply zero-ciphertext with u and u^2 */90		for (i = 0; i < 2; i++) {91			msb_mask = ((s64)_const[0] >> 63) & gfmask;92			_const[0] = (_const[0] << 1) ^ msb_mask;93 94			consts[i] = cpu_to_be64(_const[0]);95		}96 97		break;98	}99 100	return 0;101}102 103static int crypto_cmac_digest_init(struct shash_desc *pdesc)104{105	struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc);106	int bs = crypto_shash_blocksize(pdesc->tfm);107	u8 *prev = &ctx->odds[bs];108 109	ctx->len = 0;110	memset(prev, 0, bs);111 112	return 0;113}114 115static int crypto_cmac_digest_update(struct shash_desc *pdesc, const u8 *p,116				     unsigned int len)117{118	struct crypto_shash *parent = pdesc->tfm;119	struct cmac_tfm_ctx *tctx = crypto_shash_ctx(parent);120	struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc);121	struct crypto_cipher *tfm = tctx->child;122	int bs = crypto_shash_blocksize(parent);123	u8 *odds = ctx->odds;124	u8 *prev = odds + bs;125 126	/* checking the data can fill the block */127	if ((ctx->len + len) <= bs) {128		memcpy(odds + ctx->len, p, len);129		ctx->len += len;130		return 0;131	}132 133	/* filling odds with new data and encrypting it */134	memcpy(odds + ctx->len, p, bs - ctx->len);135	len -= bs - ctx->len;136	p += bs - ctx->len;137 138	crypto_xor(prev, odds, bs);139	crypto_cipher_encrypt_one(tfm, prev, prev);140 141	/* clearing the length */142	ctx->len = 0;143 144	/* encrypting the rest of data */145	while (len > bs) {146		crypto_xor(prev, p, bs);147		crypto_cipher_encrypt_one(tfm, prev, prev);148		p += bs;149		len -= bs;150	}151 152	/* keeping the surplus of blocksize */153	if (len) {154		memcpy(odds, p, len);155		ctx->len = len;156	}157 158	return 0;159}160 161static int crypto_cmac_digest_final(struct shash_desc *pdesc, u8 *out)162{163	struct crypto_shash *parent = pdesc->tfm;164	struct cmac_tfm_ctx *tctx = crypto_shash_ctx(parent);165	struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc);166	struct crypto_cipher *tfm = tctx->child;167	int bs = crypto_shash_blocksize(parent);168	u8 *odds = ctx->odds;169	u8 *prev = odds + bs;170	unsigned int offset = 0;171 172	if (ctx->len != bs) {173		unsigned int rlen;174		u8 *p = odds + ctx->len;175 176		*p = 0x80;177		p++;178 179		rlen = bs - ctx->len - 1;180		if (rlen)181			memset(p, 0, rlen);182 183		offset += bs;184	}185 186	crypto_xor(prev, odds, bs);187	crypto_xor(prev, (const u8 *)tctx->consts + offset, bs);188 189	crypto_cipher_encrypt_one(tfm, out, prev);190 191	return 0;192}193 194static int cmac_init_tfm(struct crypto_shash *tfm)195{196	struct shash_instance *inst = shash_alg_instance(tfm);197	struct cmac_tfm_ctx *ctx = crypto_shash_ctx(tfm);198	struct crypto_cipher_spawn *spawn;199	struct crypto_cipher *cipher;200 201	spawn = shash_instance_ctx(inst);202	cipher = crypto_spawn_cipher(spawn);203	if (IS_ERR(cipher))204		return PTR_ERR(cipher);205 206	ctx->child = cipher;207 208	return 0;209}210 211static int cmac_clone_tfm(struct crypto_shash *tfm, struct crypto_shash *otfm)212{213	struct cmac_tfm_ctx *octx = crypto_shash_ctx(otfm);214	struct cmac_tfm_ctx *ctx = crypto_shash_ctx(tfm);215	struct crypto_cipher *cipher;216 217	cipher = crypto_clone_cipher(octx->child);218	if (IS_ERR(cipher))219		return PTR_ERR(cipher);220 221	ctx->child = cipher;222 223	return 0;224}225 226static void cmac_exit_tfm(struct crypto_shash *tfm)227{228	struct cmac_tfm_ctx *ctx = crypto_shash_ctx(tfm);229	crypto_free_cipher(ctx->child);230}231 232static int cmac_create(struct crypto_template *tmpl, struct rtattr **tb)233{234	struct shash_instance *inst;235	struct crypto_cipher_spawn *spawn;236	struct crypto_alg *alg;237	u32 mask;238	int err;239 240	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH, &mask);241	if (err)242		return err;243 244	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);245	if (!inst)246		return -ENOMEM;247	spawn = shash_instance_ctx(inst);248 249	err = crypto_grab_cipher(spawn, shash_crypto_instance(inst),250				 crypto_attr_alg_name(tb[1]), 0, mask);251	if (err)252		goto err_free_inst;253	alg = crypto_spawn_cipher_alg(spawn);254 255	switch (alg->cra_blocksize) {256	case 16:257	case 8:258		break;259	default:260		err = -EINVAL;261		goto err_free_inst;262	}263 264	err = crypto_inst_setname(shash_crypto_instance(inst), tmpl->name, alg);265	if (err)266		goto err_free_inst;267 268	inst->alg.base.cra_priority = alg->cra_priority;269	inst->alg.base.cra_blocksize = alg->cra_blocksize;270	inst->alg.base.cra_ctxsize = sizeof(struct cmac_tfm_ctx) +271				     alg->cra_blocksize * 2;272 273	inst->alg.digestsize = alg->cra_blocksize;274	inst->alg.descsize = sizeof(struct cmac_desc_ctx) +275			     alg->cra_blocksize * 2;276	inst->alg.init = crypto_cmac_digest_init;277	inst->alg.update = crypto_cmac_digest_update;278	inst->alg.final = crypto_cmac_digest_final;279	inst->alg.setkey = crypto_cmac_digest_setkey;280	inst->alg.init_tfm = cmac_init_tfm;281	inst->alg.clone_tfm = cmac_clone_tfm;282	inst->alg.exit_tfm = cmac_exit_tfm;283 284	inst->free = shash_free_singlespawn_instance;285 286	err = shash_register_instance(tmpl, inst);287	if (err) {288err_free_inst:289		shash_free_singlespawn_instance(inst);290	}291	return err;292}293 294static struct crypto_template crypto_cmac_tmpl = {295	.name = "cmac",296	.create = cmac_create,297	.module = THIS_MODULE,298};299 300static int __init crypto_cmac_module_init(void)301{302	return crypto_register_template(&crypto_cmac_tmpl);303}304 305static void __exit crypto_cmac_module_exit(void)306{307	crypto_unregister_template(&crypto_cmac_tmpl);308}309 310subsys_initcall(crypto_cmac_module_init);311module_exit(crypto_cmac_module_exit);312 313MODULE_LICENSE("GPL");314MODULE_DESCRIPTION("CMAC keyed hash algorithm");315MODULE_ALIAS_CRYPTO("cmac");316MODULE_IMPORT_NS(CRYPTO_INTERNAL);317