-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto: arm - add support for SHA1 using ARMv8 Crypto Instructions
This implements the SHA1 secure hash algorithm using the AArch32 versions of the ARMv8 Crypto Extensions for SHA1. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
- Loading branch information
Ard Biesheuvel
authored and
Herbert Xu
committed
Mar 12, 2015
1 parent
652ccae
commit 864cbee
Showing
4 changed files
with
296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* sha1-ce-core.S - SHA-1 secure hash using ARMv8 Crypto Extensions | ||
* | ||
* Copyright (C) 2015 Linaro Ltd. | ||
* Author: Ard Biesheuvel <ard.biesheuvel@linaro.org> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <linux/linkage.h> | ||
#include <asm/assembler.h> | ||
|
||
.text | ||
.fpu crypto-neon-fp-armv8 | ||
|
||
k0 .req q0 | ||
k1 .req q1 | ||
k2 .req q2 | ||
k3 .req q3 | ||
|
||
ta0 .req q4 | ||
ta1 .req q5 | ||
tb0 .req q5 | ||
tb1 .req q4 | ||
|
||
dga .req q6 | ||
dgb .req q7 | ||
dgbs .req s28 | ||
|
||
dg0 .req q12 | ||
dg1a0 .req q13 | ||
dg1a1 .req q14 | ||
dg1b0 .req q14 | ||
dg1b1 .req q13 | ||
|
||
.macro add_only, op, ev, rc, s0, dg1 | ||
.ifnb \s0 | ||
vadd.u32 tb\ev, q\s0, \rc | ||
.endif | ||
sha1h.32 dg1b\ev, dg0 | ||
.ifb \dg1 | ||
sha1\op\().32 dg0, dg1a\ev, ta\ev | ||
.else | ||
sha1\op\().32 dg0, \dg1, ta\ev | ||
.endif | ||
.endm | ||
|
||
.macro add_update, op, ev, rc, s0, s1, s2, s3, dg1 | ||
sha1su0.32 q\s0, q\s1, q\s2 | ||
add_only \op, \ev, \rc, \s1, \dg1 | ||
sha1su1.32 q\s0, q\s3 | ||
.endm | ||
|
||
.align 6 | ||
.Lsha1_rcon: | ||
.word 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999 | ||
.word 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1 | ||
.word 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc | ||
.word 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 | ||
|
||
/* | ||
* void sha1_ce_transform(int blocks, u8 const *src, u32 *state, | ||
* u8 *head); | ||
*/ | ||
ENTRY(sha1_ce_transform) | ||
/* load round constants */ | ||
adr ip, .Lsha1_rcon | ||
vld1.32 {k0-k1}, [ip, :128]! | ||
vld1.32 {k2-k3}, [ip, :128] | ||
|
||
/* load state */ | ||
vld1.32 {dga}, [r2] | ||
vldr dgbs, [r2, #16] | ||
|
||
/* load partial input (if supplied) */ | ||
teq r3, #0 | ||
beq 0f | ||
vld1.32 {q8-q9}, [r3]! | ||
vld1.32 {q10-q11}, [r3] | ||
teq r0, #0 | ||
b 1f | ||
|
||
/* load input */ | ||
0: vld1.32 {q8-q9}, [r1]! | ||
vld1.32 {q10-q11}, [r1]! | ||
subs r0, r0, #1 | ||
|
||
1: | ||
#ifndef CONFIG_CPU_BIG_ENDIAN | ||
vrev32.8 q8, q8 | ||
vrev32.8 q9, q9 | ||
vrev32.8 q10, q10 | ||
vrev32.8 q11, q11 | ||
#endif | ||
|
||
vadd.u32 ta0, q8, k0 | ||
vmov dg0, dga | ||
|
||
add_update c, 0, k0, 8, 9, 10, 11, dgb | ||
add_update c, 1, k0, 9, 10, 11, 8 | ||
add_update c, 0, k0, 10, 11, 8, 9 | ||
add_update c, 1, k0, 11, 8, 9, 10 | ||
add_update c, 0, k1, 8, 9, 10, 11 | ||
|
||
add_update p, 1, k1, 9, 10, 11, 8 | ||
add_update p, 0, k1, 10, 11, 8, 9 | ||
add_update p, 1, k1, 11, 8, 9, 10 | ||
add_update p, 0, k1, 8, 9, 10, 11 | ||
add_update p, 1, k2, 9, 10, 11, 8 | ||
|
||
add_update m, 0, k2, 10, 11, 8, 9 | ||
add_update m, 1, k2, 11, 8, 9, 10 | ||
add_update m, 0, k2, 8, 9, 10, 11 | ||
add_update m, 1, k2, 9, 10, 11, 8 | ||
add_update m, 0, k3, 10, 11, 8, 9 | ||
|
||
add_update p, 1, k3, 11, 8, 9, 10 | ||
add_only p, 0, k3, 9 | ||
add_only p, 1, k3, 10 | ||
add_only p, 0, k3, 11 | ||
add_only p, 1 | ||
|
||
/* update state */ | ||
vadd.u32 dga, dga, dg0 | ||
vadd.u32 dgb, dgb, dg1a0 | ||
bne 0b | ||
|
||
/* store new state */ | ||
vst1.32 {dga}, [r2] | ||
vstr dgbs, [r2, #16] | ||
bx lr | ||
ENDPROC(sha1_ce_transform) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
/* | ||
* sha1-ce-glue.c - SHA-1 secure hash using ARMv8 Crypto Extensions | ||
* | ||
* Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
|
||
#include <crypto/internal/hash.h> | ||
#include <crypto/sha.h> | ||
#include <linux/crypto.h> | ||
#include <linux/module.h> | ||
|
||
#include <asm/crypto/sha1.h> | ||
#include <asm/hwcap.h> | ||
#include <asm/neon.h> | ||
#include <asm/simd.h> | ||
#include <asm/unaligned.h> | ||
|
||
MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions"); | ||
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); | ||
MODULE_LICENSE("GPL v2"); | ||
|
||
asmlinkage void sha1_ce_transform(int blocks, u8 const *src, u32 *state, | ||
u8 *head); | ||
|
||
static int sha1_init(struct shash_desc *desc) | ||
{ | ||
struct sha1_state *sctx = shash_desc_ctx(desc); | ||
|
||
*sctx = (struct sha1_state){ | ||
.state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, | ||
}; | ||
return 0; | ||
} | ||
|
||
static int sha1_update(struct shash_desc *desc, const u8 *data, | ||
unsigned int len) | ||
{ | ||
struct sha1_state *sctx = shash_desc_ctx(desc); | ||
unsigned int partial; | ||
|
||
if (!may_use_simd()) | ||
return sha1_update_arm(desc, data, len); | ||
|
||
partial = sctx->count % SHA1_BLOCK_SIZE; | ||
sctx->count += len; | ||
|
||
if ((partial + len) >= SHA1_BLOCK_SIZE) { | ||
int blocks; | ||
|
||
if (partial) { | ||
int p = SHA1_BLOCK_SIZE - partial; | ||
|
||
memcpy(sctx->buffer + partial, data, p); | ||
data += p; | ||
len -= p; | ||
} | ||
|
||
blocks = len / SHA1_BLOCK_SIZE; | ||
len %= SHA1_BLOCK_SIZE; | ||
|
||
kernel_neon_begin(); | ||
sha1_ce_transform(blocks, data, sctx->state, | ||
partial ? sctx->buffer : NULL); | ||
kernel_neon_end(); | ||
|
||
data += blocks * SHA1_BLOCK_SIZE; | ||
partial = 0; | ||
} | ||
if (len) | ||
memcpy(sctx->buffer + partial, data, len); | ||
return 0; | ||
} | ||
|
||
static int sha1_final(struct shash_desc *desc, u8 *out) | ||
{ | ||
static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; | ||
|
||
struct sha1_state *sctx = shash_desc_ctx(desc); | ||
__be64 bits = cpu_to_be64(sctx->count << 3); | ||
__be32 *dst = (__be32 *)out; | ||
int i; | ||
|
||
u32 padlen = SHA1_BLOCK_SIZE | ||
- ((sctx->count + sizeof(bits)) % SHA1_BLOCK_SIZE); | ||
|
||
sha1_update(desc, padding, padlen); | ||
sha1_update(desc, (const u8 *)&bits, sizeof(bits)); | ||
|
||
for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++) | ||
put_unaligned_be32(sctx->state[i], dst++); | ||
|
||
*sctx = (struct sha1_state){}; | ||
return 0; | ||
} | ||
|
||
static int sha1_export(struct shash_desc *desc, void *out) | ||
{ | ||
struct sha1_state *sctx = shash_desc_ctx(desc); | ||
struct sha1_state *dst = out; | ||
|
||
*dst = *sctx; | ||
return 0; | ||
} | ||
|
||
static int sha1_import(struct shash_desc *desc, const void *in) | ||
{ | ||
struct sha1_state *sctx = shash_desc_ctx(desc); | ||
struct sha1_state const *src = in; | ||
|
||
*sctx = *src; | ||
return 0; | ||
} | ||
|
||
static struct shash_alg alg = { | ||
.init = sha1_init, | ||
.update = sha1_update, | ||
.final = sha1_final, | ||
.export = sha1_export, | ||
.import = sha1_import, | ||
.descsize = sizeof(struct sha1_state), | ||
.digestsize = SHA1_DIGEST_SIZE, | ||
.statesize = sizeof(struct sha1_state), | ||
.base = { | ||
.cra_name = "sha1", | ||
.cra_driver_name = "sha1-ce", | ||
.cra_priority = 200, | ||
.cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
.cra_blocksize = SHA1_BLOCK_SIZE, | ||
.cra_module = THIS_MODULE, | ||
} | ||
}; | ||
|
||
static int __init sha1_ce_mod_init(void) | ||
{ | ||
if (!(elf_hwcap2 & HWCAP2_SHA1)) | ||
return -ENODEV; | ||
return crypto_register_shash(&alg); | ||
} | ||
|
||
static void __exit sha1_ce_mod_fini(void) | ||
{ | ||
crypto_unregister_shash(&alg); | ||
} | ||
|
||
module_init(sha1_ce_mod_init); | ||
module_exit(sha1_ce_mod_fini); |