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