1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Glue code for MD5 hashing optimized for sparc64 crypto opcodes. 3 * 4 * This is based largely upon arch/x86/crypto/sha1_ssse3_glue.c 5 * and crypto/md5.c which are: 6 * 7 * Copyright (c) Alan Smithee. 8 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> 9 * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> 10 * Copyright (c) Mathias Krause <minipli@googlemail.com> 11 * Copyright (c) Cryptoapi developers. 12 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 13 */ 14 15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 17 #include <crypto/internal/hash.h> 18 #include <linux/init.h> 19 #include <linux/module.h> 20 #include <linux/mm.h> 21 #include <linux/types.h> 22 #include <crypto/md5.h> 23 24 #include <asm/pstate.h> 25 #include <asm/elf.h> 26 27 #include "opcodes.h" 28 29 asmlinkage void md5_sparc64_transform(u32 *digest, const char *data, 30 unsigned int rounds); 31 32 static int md5_sparc64_init(struct shash_desc *desc) 33 { 34 struct md5_state *mctx = shash_desc_ctx(desc); 35 36 mctx->hash[0] = MD5_H0; 37 mctx->hash[1] = MD5_H1; 38 mctx->hash[2] = MD5_H2; 39 mctx->hash[3] = MD5_H3; 40 le32_to_cpu_array(mctx->hash, 4); 41 mctx->byte_count = 0; 42 43 return 0; 44 } 45 46 static void __md5_sparc64_update(struct md5_state *sctx, const u8 *data, 47 unsigned int len, unsigned int partial) 48 { 49 unsigned int done = 0; 50 51 sctx->byte_count += len; 52 if (partial) { 53 done = MD5_HMAC_BLOCK_SIZE - partial; 54 memcpy((u8 *)sctx->block + partial, data, done); 55 md5_sparc64_transform(sctx->hash, (u8 *)sctx->block, 1); 56 } 57 if (len - done >= MD5_HMAC_BLOCK_SIZE) { 58 const unsigned int rounds = (len - done) / MD5_HMAC_BLOCK_SIZE; 59 60 md5_sparc64_transform(sctx->hash, data + done, rounds); 61 done += rounds * MD5_HMAC_BLOCK_SIZE; 62 } 63 64 memcpy(sctx->block, data + done, len - done); 65 } 66 67 static int md5_sparc64_update(struct shash_desc *desc, const u8 *data, 68 unsigned int len) 69 { 70 struct md5_state *sctx = shash_desc_ctx(desc); 71 unsigned int partial = sctx->byte_count % MD5_HMAC_BLOCK_SIZE; 72 73 /* Handle the fast case right here */ 74 if (partial + len < MD5_HMAC_BLOCK_SIZE) { 75 sctx->byte_count += len; 76 memcpy((u8 *)sctx->block + partial, data, len); 77 } else 78 __md5_sparc64_update(sctx, data, len, partial); 79 80 return 0; 81 } 82 83 /* Add padding and return the message digest. */ 84 static int md5_sparc64_final(struct shash_desc *desc, u8 *out) 85 { 86 struct md5_state *sctx = shash_desc_ctx(desc); 87 unsigned int i, index, padlen; 88 u32 *dst = (u32 *)out; 89 __le64 bits; 90 static const u8 padding[MD5_HMAC_BLOCK_SIZE] = { 0x80, }; 91 92 bits = cpu_to_le64(sctx->byte_count << 3); 93 94 /* Pad out to 56 mod 64 and append length */ 95 index = sctx->byte_count % MD5_HMAC_BLOCK_SIZE; 96 padlen = (index < 56) ? (56 - index) : ((MD5_HMAC_BLOCK_SIZE+56) - index); 97 98 /* We need to fill a whole block for __md5_sparc64_update() */ 99 if (padlen <= 56) { 100 sctx->byte_count += padlen; 101 memcpy((u8 *)sctx->block + index, padding, padlen); 102 } else { 103 __md5_sparc64_update(sctx, padding, padlen, index); 104 } 105 __md5_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 56); 106 107 /* Store state in digest */ 108 for (i = 0; i < MD5_HASH_WORDS; i++) 109 dst[i] = sctx->hash[i]; 110 111 /* Wipe context */ 112 memset(sctx, 0, sizeof(*sctx)); 113 114 return 0; 115 } 116 117 static int md5_sparc64_export(struct shash_desc *desc, void *out) 118 { 119 struct md5_state *sctx = shash_desc_ctx(desc); 120 121 memcpy(out, sctx, sizeof(*sctx)); 122 123 return 0; 124 } 125 126 static int md5_sparc64_import(struct shash_desc *desc, const void *in) 127 { 128 struct md5_state *sctx = shash_desc_ctx(desc); 129 130 memcpy(sctx, in, sizeof(*sctx)); 131 132 return 0; 133 } 134 135 static struct shash_alg alg = { 136 .digestsize = MD5_DIGEST_SIZE, 137 .init = md5_sparc64_init, 138 .update = md5_sparc64_update, 139 .final = md5_sparc64_final, 140 .export = md5_sparc64_export, 141 .import = md5_sparc64_import, 142 .descsize = sizeof(struct md5_state), 143 .statesize = sizeof(struct md5_state), 144 .base = { 145 .cra_name = "md5", 146 .cra_driver_name= "md5-sparc64", 147 .cra_priority = SPARC_CR_OPCODE_PRIORITY, 148 .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 149 .cra_module = THIS_MODULE, 150 } 151 }; 152 153 static bool __init sparc64_has_md5_opcode(void) 154 { 155 unsigned long cfr; 156 157 if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) 158 return false; 159 160 __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); 161 if (!(cfr & CFR_MD5)) 162 return false; 163 164 return true; 165 } 166 167 static int __init md5_sparc64_mod_init(void) 168 { 169 if (sparc64_has_md5_opcode()) { 170 pr_info("Using sparc64 md5 opcode optimized MD5 implementation\n"); 171 return crypto_register_shash(&alg); 172 } 173 pr_info("sparc64 md5 opcode not available.\n"); 174 return -ENODEV; 175 } 176 177 static void __exit md5_sparc64_mod_fini(void) 178 { 179 crypto_unregister_shash(&alg); 180 } 181 182 module_init(md5_sparc64_mod_init); 183 module_exit(md5_sparc64_mod_fini); 184 185 MODULE_LICENSE("GPL"); 186 MODULE_DESCRIPTION("MD5 Message Digest Algorithm, sparc64 md5 opcode accelerated"); 187 188 MODULE_ALIAS_CRYPTO("md5"); 189 190 #include "crop_devid.c" 191