1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Glue code for MD5 implementation for PPC assembler 4 * 5 * Based on generic implementation. 6 * 7 * Copyright (c) 2015 Markus Stockhausen <stockhausen@collogia.de> 8 */ 9 10 #include <crypto/internal/hash.h> 11 #include <linux/init.h> 12 #include <linux/module.h> 13 #include <linux/mm.h> 14 #include <linux/cryptohash.h> 15 #include <linux/types.h> 16 #include <crypto/md5.h> 17 #include <asm/byteorder.h> 18 19 extern void ppc_md5_transform(u32 *state, const u8 *src, u32 blocks); 20 21 static inline void ppc_md5_clear_context(struct md5_state *sctx) 22 { 23 int count = sizeof(struct md5_state) >> 2; 24 u32 *ptr = (u32 *)sctx; 25 26 /* make sure we can clear the fast way */ 27 BUILD_BUG_ON(sizeof(struct md5_state) % 4); 28 do { *ptr++ = 0; } while (--count); 29 } 30 31 static int ppc_md5_init(struct shash_desc *desc) 32 { 33 struct md5_state *sctx = shash_desc_ctx(desc); 34 35 sctx->hash[0] = MD5_H0; 36 sctx->hash[1] = MD5_H1; 37 sctx->hash[2] = MD5_H2; 38 sctx->hash[3] = MD5_H3; 39 sctx->byte_count = 0; 40 41 return 0; 42 } 43 44 static int ppc_md5_update(struct shash_desc *desc, const u8 *data, 45 unsigned int len) 46 { 47 struct md5_state *sctx = shash_desc_ctx(desc); 48 const unsigned int offset = sctx->byte_count & 0x3f; 49 unsigned int avail = 64 - offset; 50 const u8 *src = data; 51 52 sctx->byte_count += len; 53 54 if (avail > len) { 55 memcpy((char *)sctx->block + offset, src, len); 56 return 0; 57 } 58 59 if (offset) { 60 memcpy((char *)sctx->block + offset, src, avail); 61 ppc_md5_transform(sctx->hash, (const u8 *)sctx->block, 1); 62 len -= avail; 63 src += avail; 64 } 65 66 if (len > 63) { 67 ppc_md5_transform(sctx->hash, src, len >> 6); 68 src += len & ~0x3f; 69 len &= 0x3f; 70 } 71 72 memcpy((char *)sctx->block, src, len); 73 return 0; 74 } 75 76 static int ppc_md5_final(struct shash_desc *desc, u8 *out) 77 { 78 struct md5_state *sctx = shash_desc_ctx(desc); 79 const unsigned int offset = sctx->byte_count & 0x3f; 80 const u8 *src = (const u8 *)sctx->block; 81 u8 *p = (u8 *)src + offset; 82 int padlen = 55 - offset; 83 __le64 *pbits = (__le64 *)((char *)sctx->block + 56); 84 __le32 *dst = (__le32 *)out; 85 86 *p++ = 0x80; 87 88 if (padlen < 0) { 89 memset(p, 0x00, padlen + sizeof (u64)); 90 ppc_md5_transform(sctx->hash, src, 1); 91 p = (char *)sctx->block; 92 padlen = 56; 93 } 94 95 memset(p, 0, padlen); 96 *pbits = cpu_to_le64(sctx->byte_count << 3); 97 ppc_md5_transform(sctx->hash, src, 1); 98 99 dst[0] = cpu_to_le32(sctx->hash[0]); 100 dst[1] = cpu_to_le32(sctx->hash[1]); 101 dst[2] = cpu_to_le32(sctx->hash[2]); 102 dst[3] = cpu_to_le32(sctx->hash[3]); 103 104 ppc_md5_clear_context(sctx); 105 return 0; 106 } 107 108 static int ppc_md5_export(struct shash_desc *desc, void *out) 109 { 110 struct md5_state *sctx = shash_desc_ctx(desc); 111 112 memcpy(out, sctx, sizeof(*sctx)); 113 return 0; 114 } 115 116 static int ppc_md5_import(struct shash_desc *desc, const void *in) 117 { 118 struct md5_state *sctx = shash_desc_ctx(desc); 119 120 memcpy(sctx, in, sizeof(*sctx)); 121 return 0; 122 } 123 124 static struct shash_alg alg = { 125 .digestsize = MD5_DIGEST_SIZE, 126 .init = ppc_md5_init, 127 .update = ppc_md5_update, 128 .final = ppc_md5_final, 129 .export = ppc_md5_export, 130 .import = ppc_md5_import, 131 .descsize = sizeof(struct md5_state), 132 .statesize = sizeof(struct md5_state), 133 .base = { 134 .cra_name = "md5", 135 .cra_driver_name= "md5-ppc", 136 .cra_priority = 200, 137 .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 138 .cra_module = THIS_MODULE, 139 } 140 }; 141 142 static int __init ppc_md5_mod_init(void) 143 { 144 return crypto_register_shash(&alg); 145 } 146 147 static void __exit ppc_md5_mod_fini(void) 148 { 149 crypto_unregister_shash(&alg); 150 } 151 152 module_init(ppc_md5_mod_init); 153 module_exit(ppc_md5_mod_fini); 154 155 MODULE_LICENSE("GPL"); 156 MODULE_DESCRIPTION("MD5 Secure Hash Algorithm, PPC assembler"); 157 158 MODULE_ALIAS_CRYPTO("md5"); 159 MODULE_ALIAS_CRYPTO("md5-ppc"); 160