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