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