diff options
Diffstat (limited to 'arch/sparc/crypto/sha512_glue.c')
| -rw-r--r-- | arch/sparc/crypto/sha512_glue.c | 228 | 
1 files changed, 228 insertions, 0 deletions
diff --git a/arch/sparc/crypto/sha512_glue.c b/arch/sparc/crypto/sha512_glue.c new file mode 100644 index 00000000000..f04d1994d19 --- /dev/null +++ b/arch/sparc/crypto/sha512_glue.c @@ -0,0 +1,228 @@ +/* Glue code for SHA512 hashing optimized for sparc64 crypto opcodes. + * + * This is based largely upon crypto/sha512_generic.c + * + * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com> + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> + * Copyright (c) 2003 Kyle McMartin <kyle@debian.org> + */ + +#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt + +#include <crypto/internal/hash.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/cryptohash.h> +#include <linux/types.h> +#include <crypto/sha.h> + +#include <asm/pstate.h> +#include <asm/elf.h> + +#include "opcodes.h" + +asmlinkage void sha512_sparc64_transform(u64 *digest, const char *data, +					 unsigned int rounds); + +static int sha512_sparc64_init(struct shash_desc *desc) +{ +	struct sha512_state *sctx = shash_desc_ctx(desc); +	sctx->state[0] = SHA512_H0; +	sctx->state[1] = SHA512_H1; +	sctx->state[2] = SHA512_H2; +	sctx->state[3] = SHA512_H3; +	sctx->state[4] = SHA512_H4; +	sctx->state[5] = SHA512_H5; +	sctx->state[6] = SHA512_H6; +	sctx->state[7] = SHA512_H7; +	sctx->count[0] = sctx->count[1] = 0; + +	return 0; +} + +static int sha384_sparc64_init(struct shash_desc *desc) +{ +	struct sha512_state *sctx = shash_desc_ctx(desc); +	sctx->state[0] = SHA384_H0; +	sctx->state[1] = SHA384_H1; +	sctx->state[2] = SHA384_H2; +	sctx->state[3] = SHA384_H3; +	sctx->state[4] = SHA384_H4; +	sctx->state[5] = SHA384_H5; +	sctx->state[6] = SHA384_H6; +	sctx->state[7] = SHA384_H7; +	sctx->count[0] = sctx->count[1] = 0; + +	return 0; +} + +static void __sha512_sparc64_update(struct sha512_state *sctx, const u8 *data, +				    unsigned int len, unsigned int partial) +{ +	unsigned int done = 0; + +	if ((sctx->count[0] += len) < len) +		sctx->count[1]++; +	if (partial) { +		done = SHA512_BLOCK_SIZE - partial; +		memcpy(sctx->buf + partial, data, done); +		sha512_sparc64_transform(sctx->state, sctx->buf, 1); +	} +	if (len - done >= SHA512_BLOCK_SIZE) { +		const unsigned int rounds = (len - done) / SHA512_BLOCK_SIZE; + +		sha512_sparc64_transform(sctx->state, data + done, rounds); +		done += rounds * SHA512_BLOCK_SIZE; +	} + +	memcpy(sctx->buf, data + done, len - done); +} + +static int sha512_sparc64_update(struct shash_desc *desc, const u8 *data, +				 unsigned int len) +{ +	struct sha512_state *sctx = shash_desc_ctx(desc); +	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE; + +	/* Handle the fast case right here */ +	if (partial + len < SHA512_BLOCK_SIZE) { +		if ((sctx->count[0] += len) < len) +			sctx->count[1]++; +		memcpy(sctx->buf + partial, data, len); +	} else +		__sha512_sparc64_update(sctx, data, len, partial); + +	return 0; +} + +static int sha512_sparc64_final(struct shash_desc *desc, u8 *out) +{ +	struct sha512_state *sctx = shash_desc_ctx(desc); +	unsigned int i, index, padlen; +	__be64 *dst = (__be64 *)out; +	__be64 bits[2]; +	static const u8 padding[SHA512_BLOCK_SIZE] = { 0x80, }; + +	/* Save number of bits */ +	bits[1] = cpu_to_be64(sctx->count[0] << 3); +	bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); + +	/* Pad out to 112 mod 128 and append length */ +	index = sctx->count[0] % SHA512_BLOCK_SIZE; +	padlen = (index < 112) ? (112 - index) : ((SHA512_BLOCK_SIZE+112) - index); + +	/* We need to fill a whole block for __sha512_sparc64_update() */ +	if (padlen <= 112) { +		if ((sctx->count[0] += padlen) < padlen) +			sctx->count[1]++; +		memcpy(sctx->buf + index, padding, padlen); +	} else { +		__sha512_sparc64_update(sctx, padding, padlen, index); +	} +	__sha512_sparc64_update(sctx, (const u8 *)&bits, sizeof(bits), 112); + +	/* Store state in digest */ +	for (i = 0; i < 8; i++) +		dst[i] = cpu_to_be64(sctx->state[i]); + +	/* Wipe context */ +	memset(sctx, 0, sizeof(*sctx)); + +	return 0; +} + +static int sha384_sparc64_final(struct shash_desc *desc, u8 *hash) +{ +	u8 D[64]; + +	sha512_sparc64_final(desc, D); + +	memcpy(hash, D, 48); +	memset(D, 0, 64); + +	return 0; +} + +static struct shash_alg sha512 = { +	.digestsize	=	SHA512_DIGEST_SIZE, +	.init		=	sha512_sparc64_init, +	.update		=	sha512_sparc64_update, +	.final		=	sha512_sparc64_final, +	.descsize	=	sizeof(struct sha512_state), +	.base		=	{ +		.cra_name	=	"sha512", +		.cra_driver_name=	"sha512-sparc64", +		.cra_priority	=	SPARC_CR_OPCODE_PRIORITY, +		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH, +		.cra_blocksize	=	SHA512_BLOCK_SIZE, +		.cra_module	=	THIS_MODULE, +	} +}; + +static struct shash_alg sha384 = { +	.digestsize	=	SHA384_DIGEST_SIZE, +	.init		=	sha384_sparc64_init, +	.update		=	sha512_sparc64_update, +	.final		=	sha384_sparc64_final, +	.descsize	=	sizeof(struct sha512_state), +	.base		=	{ +		.cra_name	=	"sha384", +		.cra_driver_name=	"sha384-sparc64", +		.cra_priority	=	SPARC_CR_OPCODE_PRIORITY, +		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH, +		.cra_blocksize	=	SHA384_BLOCK_SIZE, +		.cra_module	=	THIS_MODULE, +	} +}; + +static bool __init sparc64_has_sha512_opcode(void) +{ +	unsigned long cfr; + +	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) +		return false; + +	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); +	if (!(cfr & CFR_SHA512)) +		return false; + +	return true; +} + +static int __init sha512_sparc64_mod_init(void) +{ +	if (sparc64_has_sha512_opcode()) { +		int ret = crypto_register_shash(&sha384); +		if (ret < 0) +			return ret; + +		ret = crypto_register_shash(&sha512); +		if (ret < 0) { +			crypto_unregister_shash(&sha384); +			return ret; +		} + +		pr_info("Using sparc64 sha512 opcode optimized SHA-512/SHA-384 implementation\n"); +		return 0; +	} +	pr_info("sparc64 sha512 opcode not available.\n"); +	return -ENODEV; +} + +static void __exit sha512_sparc64_mod_fini(void) +{ +	crypto_unregister_shash(&sha384); +	crypto_unregister_shash(&sha512); +} + +module_init(sha512_sparc64_mod_init); +module_exit(sha512_sparc64_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 opcode accelerated"); + +MODULE_ALIAS("sha384"); +MODULE_ALIAS("sha512"); + +#include "crop_devid.c"  | 
