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