1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23265c4baSKim Phillips /*
33265c4baSKim Phillips * Glue code for MD5 implementation for PPC assembler
43265c4baSKim Phillips *
53265c4baSKim Phillips * Based on generic implementation.
63265c4baSKim Phillips *
73265c4baSKim Phillips * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de>
83265c4baSKim Phillips */
93265c4baSKim Phillips
103265c4baSKim Phillips #include <crypto/internal/hash.h>
113265c4baSKim Phillips #include <linux/init.h>
123265c4baSKim Phillips #include <linux/module.h>
133265c4baSKim Phillips #include <linux/mm.h>
143265c4baSKim Phillips #include <linux/types.h>
153265c4baSKim Phillips #include <crypto/md5.h>
163265c4baSKim Phillips #include <asm/byteorder.h>
173265c4baSKim Phillips
183265c4baSKim Phillips extern void ppc_md5_transform(u32 *state, const u8 *src, u32 blocks);
193265c4baSKim Phillips
ppc_md5_clear_context(struct md5_state * sctx)203265c4baSKim Phillips static inline void ppc_md5_clear_context(struct md5_state *sctx)
213265c4baSKim Phillips {
223265c4baSKim Phillips int count = sizeof(struct md5_state) >> 2;
233265c4baSKim Phillips u32 *ptr = (u32 *)sctx;
243265c4baSKim Phillips
253265c4baSKim Phillips /* make sure we can clear the fast way */
263265c4baSKim Phillips BUILD_BUG_ON(sizeof(struct md5_state) % 4);
273265c4baSKim Phillips do { *ptr++ = 0; } while (--count);
283265c4baSKim Phillips }
293265c4baSKim Phillips
ppc_md5_init(struct shash_desc * desc)303265c4baSKim Phillips static int ppc_md5_init(struct shash_desc *desc)
313265c4baSKim Phillips {
323265c4baSKim Phillips struct md5_state *sctx = shash_desc_ctx(desc);
333265c4baSKim Phillips
34a4015213SLABBE Corentin sctx->hash[0] = MD5_H0;
35a4015213SLABBE Corentin sctx->hash[1] = MD5_H1;
36a4015213SLABBE Corentin sctx->hash[2] = MD5_H2;
37a4015213SLABBE Corentin sctx->hash[3] = MD5_H3;
383265c4baSKim Phillips sctx->byte_count = 0;
393265c4baSKim Phillips
403265c4baSKim Phillips return 0;
413265c4baSKim Phillips }
423265c4baSKim Phillips
ppc_md5_update(struct shash_desc * desc,const u8 * data,unsigned int len)433265c4baSKim Phillips static int ppc_md5_update(struct shash_desc *desc, const u8 *data,
443265c4baSKim Phillips unsigned int len)
453265c4baSKim Phillips {
463265c4baSKim Phillips struct md5_state *sctx = shash_desc_ctx(desc);
473265c4baSKim Phillips const unsigned int offset = sctx->byte_count & 0x3f;
483265c4baSKim Phillips unsigned int avail = 64 - offset;
493265c4baSKim Phillips const u8 *src = data;
503265c4baSKim Phillips
513265c4baSKim Phillips sctx->byte_count += len;
523265c4baSKim Phillips
533265c4baSKim Phillips if (avail > len) {
543265c4baSKim Phillips memcpy((char *)sctx->block + offset, src, len);
553265c4baSKim Phillips return 0;
563265c4baSKim Phillips }
573265c4baSKim Phillips
583265c4baSKim Phillips if (offset) {
593265c4baSKim Phillips memcpy((char *)sctx->block + offset, src, avail);
603265c4baSKim Phillips ppc_md5_transform(sctx->hash, (const u8 *)sctx->block, 1);
613265c4baSKim Phillips len -= avail;
623265c4baSKim Phillips src += avail;
633265c4baSKim Phillips }
643265c4baSKim Phillips
653265c4baSKim Phillips if (len > 63) {
663265c4baSKim Phillips ppc_md5_transform(sctx->hash, src, len >> 6);
673265c4baSKim Phillips src += len & ~0x3f;
683265c4baSKim Phillips len &= 0x3f;
693265c4baSKim Phillips }
703265c4baSKim Phillips
713265c4baSKim Phillips memcpy((char *)sctx->block, src, len);
723265c4baSKim Phillips return 0;
733265c4baSKim Phillips }
743265c4baSKim Phillips
ppc_md5_final(struct shash_desc * desc,u8 * out)753265c4baSKim Phillips static int ppc_md5_final(struct shash_desc *desc, u8 *out)
763265c4baSKim Phillips {
773265c4baSKim Phillips struct md5_state *sctx = shash_desc_ctx(desc);
783265c4baSKim Phillips const unsigned int offset = sctx->byte_count & 0x3f;
793265c4baSKim Phillips const u8 *src = (const u8 *)sctx->block;
803265c4baSKim Phillips u8 *p = (u8 *)src + offset;
813265c4baSKim Phillips int padlen = 55 - offset;
823265c4baSKim Phillips __le64 *pbits = (__le64 *)((char *)sctx->block + 56);
833265c4baSKim Phillips __le32 *dst = (__le32 *)out;
843265c4baSKim Phillips
853265c4baSKim Phillips *p++ = 0x80;
863265c4baSKim Phillips
873265c4baSKim Phillips if (padlen < 0) {
883265c4baSKim Phillips memset(p, 0x00, padlen + sizeof (u64));
893265c4baSKim Phillips ppc_md5_transform(sctx->hash, src, 1);
903265c4baSKim Phillips p = (char *)sctx->block;
913265c4baSKim Phillips padlen = 56;
923265c4baSKim Phillips }
933265c4baSKim Phillips
943265c4baSKim Phillips memset(p, 0, padlen);
953265c4baSKim Phillips *pbits = cpu_to_le64(sctx->byte_count << 3);
963265c4baSKim Phillips ppc_md5_transform(sctx->hash, src, 1);
973265c4baSKim Phillips
983265c4baSKim Phillips dst[0] = cpu_to_le32(sctx->hash[0]);
993265c4baSKim Phillips dst[1] = cpu_to_le32(sctx->hash[1]);
1003265c4baSKim Phillips dst[2] = cpu_to_le32(sctx->hash[2]);
1013265c4baSKim Phillips dst[3] = cpu_to_le32(sctx->hash[3]);
1023265c4baSKim Phillips
1033265c4baSKim Phillips ppc_md5_clear_context(sctx);
1043265c4baSKim Phillips return 0;
1053265c4baSKim Phillips }
1063265c4baSKim Phillips
ppc_md5_export(struct shash_desc * desc,void * out)1073265c4baSKim Phillips static int ppc_md5_export(struct shash_desc *desc, void *out)
1083265c4baSKim Phillips {
1093265c4baSKim Phillips struct md5_state *sctx = shash_desc_ctx(desc);
1103265c4baSKim Phillips
1113265c4baSKim Phillips memcpy(out, sctx, sizeof(*sctx));
1123265c4baSKim Phillips return 0;
1133265c4baSKim Phillips }
1143265c4baSKim Phillips
ppc_md5_import(struct shash_desc * desc,const void * in)1153265c4baSKim Phillips static int ppc_md5_import(struct shash_desc *desc, const void *in)
1163265c4baSKim Phillips {
1173265c4baSKim Phillips struct md5_state *sctx = shash_desc_ctx(desc);
1183265c4baSKim Phillips
1193265c4baSKim Phillips memcpy(sctx, in, sizeof(*sctx));
1203265c4baSKim Phillips return 0;
1213265c4baSKim Phillips }
1223265c4baSKim Phillips
1233265c4baSKim Phillips static struct shash_alg alg = {
1243265c4baSKim Phillips .digestsize = MD5_DIGEST_SIZE,
1253265c4baSKim Phillips .init = ppc_md5_init,
1263265c4baSKim Phillips .update = ppc_md5_update,
1273265c4baSKim Phillips .final = ppc_md5_final,
1283265c4baSKim Phillips .export = ppc_md5_export,
1293265c4baSKim Phillips .import = ppc_md5_import,
1303265c4baSKim Phillips .descsize = sizeof(struct md5_state),
1313265c4baSKim Phillips .statesize = sizeof(struct md5_state),
1323265c4baSKim Phillips .base = {
1333265c4baSKim Phillips .cra_name = "md5",
1343265c4baSKim Phillips .cra_driver_name= "md5-ppc",
1353265c4baSKim Phillips .cra_priority = 200,
1363265c4baSKim Phillips .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
1373265c4baSKim Phillips .cra_module = THIS_MODULE,
1383265c4baSKim Phillips }
1393265c4baSKim Phillips };
1403265c4baSKim Phillips
ppc_md5_mod_init(void)1413265c4baSKim Phillips static int __init ppc_md5_mod_init(void)
1423265c4baSKim Phillips {
1433265c4baSKim Phillips return crypto_register_shash(&alg);
1443265c4baSKim Phillips }
1453265c4baSKim Phillips
ppc_md5_mod_fini(void)1463265c4baSKim Phillips static void __exit ppc_md5_mod_fini(void)
1473265c4baSKim Phillips {
1483265c4baSKim Phillips crypto_unregister_shash(&alg);
1493265c4baSKim Phillips }
1503265c4baSKim Phillips
1513265c4baSKim Phillips module_init(ppc_md5_mod_init);
1523265c4baSKim Phillips module_exit(ppc_md5_mod_fini);
1533265c4baSKim Phillips
1543265c4baSKim Phillips MODULE_LICENSE("GPL");
1553265c4baSKim Phillips MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, PPC assembler");
1563265c4baSKim Phillips
1573265c4baSKim Phillips MODULE_ALIAS_CRYPTO("md5");
1583265c4baSKim Phillips MODULE_ALIAS_CRYPTO("md5-ppc");
159