xref: /openbmc/linux/crypto/crc32_generic.c (revision 6943546c)
1a7c58ac0SHerbert Xu /* GPL HEADER START
2a7c58ac0SHerbert Xu  *
3a7c58ac0SHerbert Xu  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4a7c58ac0SHerbert Xu  *
5a7c58ac0SHerbert Xu  * This program is free software; you can redistribute it and/or modify
6a7c58ac0SHerbert Xu  * it under the terms of the GNU General Public License version 2 only,
7a7c58ac0SHerbert Xu  * as published by the Free Software Foundation.
8a7c58ac0SHerbert Xu  *
9a7c58ac0SHerbert Xu  * This program is distributed in the hope that it will be useful, but
10a7c58ac0SHerbert Xu  * WITHOUT ANY WARRANTY; without even the implied warranty of
11a7c58ac0SHerbert Xu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12a7c58ac0SHerbert Xu  * General Public License version 2 for more details (a copy is included
13a7c58ac0SHerbert Xu  * in the LICENSE file that accompanied this code).
14a7c58ac0SHerbert Xu  *
15a7c58ac0SHerbert Xu  * You should have received a copy of the GNU General Public License
16a7c58ac0SHerbert Xu  * version 2 along with this program; If not, see http://www.gnu.org/licenses
17a7c58ac0SHerbert Xu  *
18a7c58ac0SHerbert Xu  * Please  visit http://www.xyratex.com/contact if you need additional
19a7c58ac0SHerbert Xu  * information or have any questions.
20a7c58ac0SHerbert Xu  *
21a7c58ac0SHerbert Xu  * GPL HEADER END
22a7c58ac0SHerbert Xu  */
23a7c58ac0SHerbert Xu 
24a7c58ac0SHerbert Xu /*
25a7c58ac0SHerbert Xu  * Copyright 2012 Xyratex Technology Limited
26a7c58ac0SHerbert Xu  */
27a7c58ac0SHerbert Xu 
28a7c58ac0SHerbert Xu /*
29a7c58ac0SHerbert Xu  * This is crypto api shash wrappers to crc32_le.
30a7c58ac0SHerbert Xu  */
31a7c58ac0SHerbert Xu 
32fffe7d92SEric Biggers #include <asm/unaligned.h>
33a7c58ac0SHerbert Xu #include <linux/crc32.h>
34a7c58ac0SHerbert Xu #include <crypto/internal/hash.h>
35a7c58ac0SHerbert Xu #include <linux/init.h>
36a7c58ac0SHerbert Xu #include <linux/module.h>
37a7c58ac0SHerbert Xu #include <linux/string.h>
38a7c58ac0SHerbert Xu #include <linux/kernel.h>
39a7c58ac0SHerbert Xu 
40a7c58ac0SHerbert Xu #define CHKSUM_BLOCK_SIZE	1
41a7c58ac0SHerbert Xu #define CHKSUM_DIGEST_SIZE	4
42a7c58ac0SHerbert Xu 
43a7c58ac0SHerbert Xu /** No default init with ~0 */
44a7c58ac0SHerbert Xu static int crc32_cra_init(struct crypto_tfm *tfm)
45a7c58ac0SHerbert Xu {
46a7c58ac0SHerbert Xu 	u32 *key = crypto_tfm_ctx(tfm);
47a7c58ac0SHerbert Xu 
48a7c58ac0SHerbert Xu 	*key = 0;
49a7c58ac0SHerbert Xu 
50a7c58ac0SHerbert Xu 	return 0;
51a7c58ac0SHerbert Xu }
52a7c58ac0SHerbert Xu 
53a7c58ac0SHerbert Xu /*
54a7c58ac0SHerbert Xu  * Setting the seed allows arbitrary accumulators and flexible XOR policy
55a7c58ac0SHerbert Xu  * If your algorithm starts with ~0, then XOR with ~0 before you set
56a7c58ac0SHerbert Xu  * the seed.
57a7c58ac0SHerbert Xu  */
58a7c58ac0SHerbert Xu static int crc32_setkey(struct crypto_shash *hash, const u8 *key,
59a7c58ac0SHerbert Xu 			unsigned int keylen)
60a7c58ac0SHerbert Xu {
61a7c58ac0SHerbert Xu 	u32 *mctx = crypto_shash_ctx(hash);
62a7c58ac0SHerbert Xu 
63a7c58ac0SHerbert Xu 	if (keylen != sizeof(u32)) {
64a7c58ac0SHerbert Xu 		crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
65a7c58ac0SHerbert Xu 		return -EINVAL;
66a7c58ac0SHerbert Xu 	}
67fffe7d92SEric Biggers 	*mctx = get_unaligned_le32(key);
68a7c58ac0SHerbert Xu 	return 0;
69a7c58ac0SHerbert Xu }
70a7c58ac0SHerbert Xu 
71a7c58ac0SHerbert Xu static int crc32_init(struct shash_desc *desc)
72a7c58ac0SHerbert Xu {
73a7c58ac0SHerbert Xu 	u32 *mctx = crypto_shash_ctx(desc->tfm);
74a7c58ac0SHerbert Xu 	u32 *crcp = shash_desc_ctx(desc);
75a7c58ac0SHerbert Xu 
76a7c58ac0SHerbert Xu 	*crcp = *mctx;
77a7c58ac0SHerbert Xu 
78a7c58ac0SHerbert Xu 	return 0;
79a7c58ac0SHerbert Xu }
80a7c58ac0SHerbert Xu 
81a7c58ac0SHerbert Xu static int crc32_update(struct shash_desc *desc, const u8 *data,
82a7c58ac0SHerbert Xu 			unsigned int len)
83a7c58ac0SHerbert Xu {
84a7c58ac0SHerbert Xu 	u32 *crcp = shash_desc_ctx(desc);
85a7c58ac0SHerbert Xu 
866943546cSEric Biggers 	*crcp = crc32_le(*crcp, data, len);
87a7c58ac0SHerbert Xu 	return 0;
88a7c58ac0SHerbert Xu }
89a7c58ac0SHerbert Xu 
90a7c58ac0SHerbert Xu /* No final XOR 0xFFFFFFFF, like crc32_le */
91a7c58ac0SHerbert Xu static int __crc32_finup(u32 *crcp, const u8 *data, unsigned int len,
92a7c58ac0SHerbert Xu 			 u8 *out)
93a7c58ac0SHerbert Xu {
946943546cSEric Biggers 	put_unaligned_le32(crc32_le(*crcp, data, len), out);
95a7c58ac0SHerbert Xu 	return 0;
96a7c58ac0SHerbert Xu }
97a7c58ac0SHerbert Xu 
98a7c58ac0SHerbert Xu static int crc32_finup(struct shash_desc *desc, const u8 *data,
99a7c58ac0SHerbert Xu 		       unsigned int len, u8 *out)
100a7c58ac0SHerbert Xu {
101a7c58ac0SHerbert Xu 	return __crc32_finup(shash_desc_ctx(desc), data, len, out);
102a7c58ac0SHerbert Xu }
103a7c58ac0SHerbert Xu 
104a7c58ac0SHerbert Xu static int crc32_final(struct shash_desc *desc, u8 *out)
105a7c58ac0SHerbert Xu {
106a7c58ac0SHerbert Xu 	u32 *crcp = shash_desc_ctx(desc);
107a7c58ac0SHerbert Xu 
108fffe7d92SEric Biggers 	put_unaligned_le32(*crcp, out);
109a7c58ac0SHerbert Xu 	return 0;
110a7c58ac0SHerbert Xu }
111a7c58ac0SHerbert Xu 
112a7c58ac0SHerbert Xu static int crc32_digest(struct shash_desc *desc, const u8 *data,
113a7c58ac0SHerbert Xu 			unsigned int len, u8 *out)
114a7c58ac0SHerbert Xu {
115a7c58ac0SHerbert Xu 	return __crc32_finup(crypto_shash_ctx(desc->tfm), data, len,
116a7c58ac0SHerbert Xu 			     out);
117a7c58ac0SHerbert Xu }
118a7c58ac0SHerbert Xu static struct shash_alg alg = {
119a7c58ac0SHerbert Xu 	.setkey		= crc32_setkey,
120a7c58ac0SHerbert Xu 	.init		= crc32_init,
121a7c58ac0SHerbert Xu 	.update		= crc32_update,
122a7c58ac0SHerbert Xu 	.final		= crc32_final,
123a7c58ac0SHerbert Xu 	.finup		= crc32_finup,
124a7c58ac0SHerbert Xu 	.digest		= crc32_digest,
125a7c58ac0SHerbert Xu 	.descsize	= sizeof(u32),
126a7c58ac0SHerbert Xu 	.digestsize	= CHKSUM_DIGEST_SIZE,
127a7c58ac0SHerbert Xu 	.base		= {
128a7c58ac0SHerbert Xu 		.cra_name		= "crc32",
129a7c58ac0SHerbert Xu 		.cra_driver_name	= "crc32-generic",
130a7c58ac0SHerbert Xu 		.cra_priority		= 100,
131a208fa8fSEric Biggers 		.cra_flags		= CRYPTO_ALG_OPTIONAL_KEY,
132a7c58ac0SHerbert Xu 		.cra_blocksize		= CHKSUM_BLOCK_SIZE,
133a7c58ac0SHerbert Xu 		.cra_ctxsize		= sizeof(u32),
134a7c58ac0SHerbert Xu 		.cra_module		= THIS_MODULE,
135a7c58ac0SHerbert Xu 		.cra_init		= crc32_cra_init,
136a7c58ac0SHerbert Xu 	}
137a7c58ac0SHerbert Xu };
138a7c58ac0SHerbert Xu 
139a7c58ac0SHerbert Xu static int __init crc32_mod_init(void)
140a7c58ac0SHerbert Xu {
141a7c58ac0SHerbert Xu 	return crypto_register_shash(&alg);
142a7c58ac0SHerbert Xu }
143a7c58ac0SHerbert Xu 
144a7c58ac0SHerbert Xu static void __exit crc32_mod_fini(void)
145a7c58ac0SHerbert Xu {
146a7c58ac0SHerbert Xu 	crypto_unregister_shash(&alg);
147a7c58ac0SHerbert Xu }
148a7c58ac0SHerbert Xu 
149a7c58ac0SHerbert Xu module_init(crc32_mod_init);
150a7c58ac0SHerbert Xu module_exit(crc32_mod_fini);
151a7c58ac0SHerbert Xu 
152a7c58ac0SHerbert Xu MODULE_AUTHOR("Alexander Boyko <alexander_boyko@xyratex.com>");
153a7c58ac0SHerbert Xu MODULE_DESCRIPTION("CRC32 calculations wrapper for lib/crc32");
154a7c58ac0SHerbert Xu MODULE_LICENSE("GPL");
155a7c58ac0SHerbert Xu MODULE_ALIAS_CRYPTO("crc32");
156a7c58ac0SHerbert Xu MODULE_ALIAS_CRYPTO("crc32-generic");
157