xref: /linux/crypto/xcbc.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C)2006 USAGI/WIDE Project
4  *
5  * Author:
6  * 	Kazunori Miyazawa <miyazawa@linux-ipv6.org>
7  */
8 
9 #include <crypto/internal/cipher.h>
10 #include <crypto/internal/hash.h>
11 #include <crypto/utils.h>
12 #include <linux/err.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 
18 static u_int32_t ks[12] = {0x01010101, 0x01010101, 0x01010101, 0x01010101,
19 			   0x02020202, 0x02020202, 0x02020202, 0x02020202,
20 			   0x03030303, 0x03030303, 0x03030303, 0x03030303};
21 
22 /*
23  * +------------------------
24  * | <parent tfm>
25  * +------------------------
26  * | xcbc_tfm_ctx
27  * +------------------------
28  * | consts (block size * 2)
29  * +------------------------
30  */
31 struct xcbc_tfm_ctx {
32 	struct crypto_cipher *child;
33 	u8 consts[];
34 };
35 
36 #define XCBC_BLOCKSIZE	16
37 
crypto_xcbc_digest_setkey(struct crypto_shash * parent,const u8 * inkey,unsigned int keylen)38 static int crypto_xcbc_digest_setkey(struct crypto_shash *parent,
39 				     const u8 *inkey, unsigned int keylen)
40 {
41 	struct xcbc_tfm_ctx *ctx = crypto_shash_ctx(parent);
42 	u8 *consts = ctx->consts;
43 	int err = 0;
44 	u8 key1[XCBC_BLOCKSIZE];
45 	int bs = sizeof(key1);
46 
47 	if ((err = crypto_cipher_setkey(ctx->child, inkey, keylen)))
48 		return err;
49 
50 	crypto_cipher_encrypt_one(ctx->child, consts, (u8 *)ks + bs);
51 	crypto_cipher_encrypt_one(ctx->child, consts + bs, (u8 *)ks + bs * 2);
52 	crypto_cipher_encrypt_one(ctx->child, key1, (u8 *)ks);
53 
54 	return crypto_cipher_setkey(ctx->child, key1, bs);
55 
56 }
57 
crypto_xcbc_digest_init(struct shash_desc * pdesc)58 static int crypto_xcbc_digest_init(struct shash_desc *pdesc)
59 {
60 	int bs = crypto_shash_blocksize(pdesc->tfm);
61 	u8 *prev = shash_desc_ctx(pdesc);
62 
63 	memset(prev, 0, bs);
64 	return 0;
65 }
66 
crypto_xcbc_digest_update(struct shash_desc * pdesc,const u8 * p,unsigned int len)67 static int crypto_xcbc_digest_update(struct shash_desc *pdesc, const u8 *p,
68 				     unsigned int len)
69 {
70 	struct crypto_shash *parent = pdesc->tfm;
71 	struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
72 	struct crypto_cipher *tfm = tctx->child;
73 	int bs = crypto_shash_blocksize(parent);
74 	u8 *prev = shash_desc_ctx(pdesc);
75 
76 	do {
77 		crypto_xor(prev, p, bs);
78 		crypto_cipher_encrypt_one(tfm, prev, prev);
79 		p += bs;
80 		len -= bs;
81 	} while (len >= bs);
82 	return len;
83 }
84 
crypto_xcbc_digest_finup(struct shash_desc * pdesc,const u8 * src,unsigned int len,u8 * out)85 static int crypto_xcbc_digest_finup(struct shash_desc *pdesc, const u8 *src,
86 				    unsigned int len, u8 *out)
87 {
88 	struct crypto_shash *parent = pdesc->tfm;
89 	struct xcbc_tfm_ctx *tctx = crypto_shash_ctx(parent);
90 	struct crypto_cipher *tfm = tctx->child;
91 	int bs = crypto_shash_blocksize(parent);
92 	u8 *prev = shash_desc_ctx(pdesc);
93 	unsigned int offset = 0;
94 
95 	crypto_xor(prev, src, len);
96 	if (len != bs) {
97 		prev[len] ^= 0x80;
98 		offset += bs;
99 	}
100 	crypto_xor(prev, &tctx->consts[offset], bs);
101 	crypto_cipher_encrypt_one(tfm, out, prev);
102 	return 0;
103 }
104 
xcbc_init_tfm(struct crypto_tfm * tfm)105 static int xcbc_init_tfm(struct crypto_tfm *tfm)
106 {
107 	struct crypto_cipher *cipher;
108 	struct crypto_instance *inst = (void *)tfm->__crt_alg;
109 	struct crypto_cipher_spawn *spawn = crypto_instance_ctx(inst);
110 	struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
111 
112 	cipher = crypto_spawn_cipher(spawn);
113 	if (IS_ERR(cipher))
114 		return PTR_ERR(cipher);
115 
116 	ctx->child = cipher;
117 
118 	return 0;
119 };
120 
xcbc_exit_tfm(struct crypto_tfm * tfm)121 static void xcbc_exit_tfm(struct crypto_tfm *tfm)
122 {
123 	struct xcbc_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
124 	crypto_free_cipher(ctx->child);
125 }
126 
xcbc_create(struct crypto_template * tmpl,struct rtattr ** tb)127 static int xcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
128 {
129 	struct shash_instance *inst;
130 	struct crypto_cipher_spawn *spawn;
131 	struct crypto_alg *alg;
132 	u32 mask;
133 	int err;
134 
135 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH, &mask);
136 	if (err)
137 		return err;
138 
139 	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
140 	if (!inst)
141 		return -ENOMEM;
142 	spawn = shash_instance_ctx(inst);
143 
144 	err = crypto_grab_cipher(spawn, shash_crypto_instance(inst),
145 				 crypto_attr_alg_name(tb[1]), 0, mask);
146 	if (err)
147 		goto err_free_inst;
148 	alg = crypto_spawn_cipher_alg(spawn);
149 
150 	err = -EINVAL;
151 	if (alg->cra_blocksize != XCBC_BLOCKSIZE)
152 		goto err_free_inst;
153 
154 	err = crypto_inst_setname(shash_crypto_instance(inst), tmpl->name, alg);
155 	if (err)
156 		goto err_free_inst;
157 
158 	inst->alg.base.cra_priority = alg->cra_priority;
159 	inst->alg.base.cra_blocksize = alg->cra_blocksize;
160 	inst->alg.base.cra_ctxsize = sizeof(struct xcbc_tfm_ctx) +
161 				     alg->cra_blocksize * 2;
162 	inst->alg.base.cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY |
163 				   CRYPTO_AHASH_ALG_FINAL_NONZERO;
164 
165 	inst->alg.digestsize = alg->cra_blocksize;
166 	inst->alg.descsize = alg->cra_blocksize;
167 
168 	inst->alg.base.cra_init = xcbc_init_tfm;
169 	inst->alg.base.cra_exit = xcbc_exit_tfm;
170 
171 	inst->alg.init = crypto_xcbc_digest_init;
172 	inst->alg.update = crypto_xcbc_digest_update;
173 	inst->alg.finup = crypto_xcbc_digest_finup;
174 	inst->alg.setkey = crypto_xcbc_digest_setkey;
175 
176 	inst->free = shash_free_singlespawn_instance;
177 
178 	err = shash_register_instance(tmpl, inst);
179 	if (err) {
180 err_free_inst:
181 		shash_free_singlespawn_instance(inst);
182 	}
183 	return err;
184 }
185 
186 static struct crypto_template crypto_xcbc_tmpl = {
187 	.name = "xcbc",
188 	.create = xcbc_create,
189 	.module = THIS_MODULE,
190 };
191 
crypto_xcbc_module_init(void)192 static int __init crypto_xcbc_module_init(void)
193 {
194 	return crypto_register_template(&crypto_xcbc_tmpl);
195 }
196 
crypto_xcbc_module_exit(void)197 static void __exit crypto_xcbc_module_exit(void)
198 {
199 	crypto_unregister_template(&crypto_xcbc_tmpl);
200 }
201 
202 module_init(crypto_xcbc_module_init);
203 module_exit(crypto_xcbc_module_exit);
204 
205 MODULE_LICENSE("GPL");
206 MODULE_DESCRIPTION("XCBC keyed hash algorithm");
207 MODULE_ALIAS_CRYPTO("xcbc");
208 MODULE_IMPORT_NS("CRYPTO_INTERNAL");
209