sha512_generic.c 7.15 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9 10 11 12
/* SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
 *
 * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
 * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 */
13
#include <crypto/internal/hash.h>
Linus Torvalds's avatar
Linus Torvalds committed
14 15 16 17 18
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/crypto.h>
19
#include <linux/types.h>
20
#include <crypto/sha.h>
21
#include <crypto/sha512_base.h>
22
#include <linux/percpu.h>
Linus Torvalds's avatar
Linus Torvalds committed
23
#include <asm/byteorder.h>
24
#include <asm/unaligned.h>
Linus Torvalds's avatar
Linus Torvalds committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

static inline u64 Ch(u64 x, u64 y, u64 z)
{
        return z ^ (x & (y ^ z));
}

static inline u64 Maj(u64 x, u64 y, u64 z)
{
        return (x & y) | (z & (x | y));
}

static const u64 sha512_K[80] = {
        0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
        0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
        0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
        0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
        0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
        0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
        0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
        0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
        0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
        0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
        0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
        0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
        0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
        0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
        0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
        0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
        0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
        0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
        0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
        0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
        0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
        0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
        0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
        0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
        0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
        0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
        0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
};

66 67 68 69
#define e0(x)       (ror64(x,28) ^ ror64(x,34) ^ ror64(x,39))
#define e1(x)       (ror64(x,14) ^ ror64(x,18) ^ ror64(x,41))
#define s0(x)       (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7))
#define s1(x)       (ror64(x,19) ^ ror64(x,61) ^ (x >> 6))
Linus Torvalds's avatar
Linus Torvalds committed
70 71 72

static inline void LOAD_OP(int I, u64 *W, const u8 *input)
{
73
	W[I] = get_unaligned_be64((__u64 *)input + I);
Linus Torvalds's avatar
Linus Torvalds committed
74 75 76 77
}

static inline void BLEND_OP(int I, u64 *W)
{
78
	W[I & 15] += s1(W[(I-2) & 15]) + W[(I-7) & 15] + s0(W[(I-15) & 15]);
Linus Torvalds's avatar
Linus Torvalds committed
79 80 81
}

static void
82
sha512_transform(u64 *state, const u8 *input)
Linus Torvalds's avatar
Linus Torvalds committed
83 84 85 86
{
	u64 a, b, c, d, e, f, g, h, t1, t2;

	int i;
87
	u64 W[16];
Linus Torvalds's avatar
Linus Torvalds committed
88 89

	/* load the state into our registers */
90 91 92
	a=state[0];   b=state[1];   c=state[2];   d=state[3];
	e=state[4];   f=state[5];   g=state[6];   h=state[7];

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
	/* now iterate */
	for (i=0; i<80; i+=8) {
		if (!(i & 8)) {
			int j;

			if (i < 16) {
				/* load the input */
				for (j = 0; j < 16; j++)
					LOAD_OP(i + j, W, input);
			} else {
				for (j = 0; j < 16; j++) {
					BLEND_OP(i + j, W);
				}
			}
		}

		t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i  ] + W[(i & 15)];
		t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
		t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[(i & 15) + 1];
		t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
		t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[(i & 15) + 2];
		t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
		t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[(i & 15) + 3];
		t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
		t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[(i & 15) + 4];
		t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
		t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[(i & 15) + 5];
		t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
		t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[(i & 15) + 6];
		t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
		t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[(i & 15) + 7];
		t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
Linus Torvalds's avatar
Linus Torvalds committed
125
	}
126 127 128

	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
Linus Torvalds's avatar
Linus Torvalds committed
129 130 131 132 133

	/* erase our data */
	a = b = c = d = e = f = g = h = t1 = t2 = 0;
}

134 135
static void sha512_generic_block_fn(struct sha512_state *sst, u8 const *src,
				    int blocks)
Linus Torvalds's avatar
Linus Torvalds committed
136
{
137 138 139 140
	while (blocks--) {
		sha512_transform(sst->state, src);
		src += SHA512_BLOCK_SIZE;
	}
Linus Torvalds's avatar
Linus Torvalds committed
141 142
}

143 144
int crypto_sha512_update(struct shash_desc *desc, const u8 *data,
			unsigned int len)
Linus Torvalds's avatar
Linus Torvalds committed
145
{
146
	return sha512_base_do_update(desc, data, len, sha512_generic_block_fn);
Linus Torvalds's avatar
Linus Torvalds committed
147
}
148
EXPORT_SYMBOL(crypto_sha512_update);
Linus Torvalds's avatar
Linus Torvalds committed
149

150
static int sha512_final(struct shash_desc *desc, u8 *hash)
Linus Torvalds's avatar
Linus Torvalds committed
151
{
152 153
	sha512_base_do_finalize(desc, sha512_generic_block_fn);
	return sha512_base_finish(desc, hash);
Linus Torvalds's avatar
Linus Torvalds committed
154 155
}

156 157
int crypto_sha512_finup(struct shash_desc *desc, const u8 *data,
			unsigned int len, u8 *hash)
Linus Torvalds's avatar
Linus Torvalds committed
158
{
159 160
	sha512_base_do_update(desc, data, len, sha512_generic_block_fn);
	return sha512_final(desc, hash);
Linus Torvalds's avatar
Linus Torvalds committed
161
}
162
EXPORT_SYMBOL(crypto_sha512_finup);
Linus Torvalds's avatar
Linus Torvalds committed
163

164
static struct shash_alg sha512_algs[2] = { {
165
	.digestsize	=	SHA512_DIGEST_SIZE,
166
	.init		=	sha512_base_init,
167
	.update		=	crypto_sha512_update,
168
	.final		=	sha512_final,
169
	.finup		=	crypto_sha512_finup,
170
	.descsize	=	sizeof(struct sha512_state),
171 172
	.base		=	{
		.cra_name	=	"sha512",
173
		.cra_driver_name =	"sha512-generic",
174 175 176 177
		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
		.cra_blocksize	=	SHA512_BLOCK_SIZE,
		.cra_module	=	THIS_MODULE,
	}
178
}, {
179
	.digestsize	=	SHA384_DIGEST_SIZE,
180
	.init		=	sha384_base_init,
181
	.update		=	crypto_sha512_update,
182 183
	.final		=	sha512_final,
	.finup		=	crypto_sha512_finup,
184
	.descsize	=	sizeof(struct sha512_state),
185 186
	.base		=	{
		.cra_name	=	"sha384",
187
		.cra_driver_name =	"sha384-generic",
188 189 190 191
		.cra_flags	=	CRYPTO_ALG_TYPE_SHASH,
		.cra_blocksize	=	SHA384_BLOCK_SIZE,
		.cra_module	=	THIS_MODULE,
	}
192
} };
Linus Torvalds's avatar
Linus Torvalds committed
193

194
static int __init sha512_generic_mod_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
195
{
196
	return crypto_register_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
Linus Torvalds's avatar
Linus Torvalds committed
197 198
}

199
static void __exit sha512_generic_mod_fini(void)
Linus Torvalds's avatar
Linus Torvalds committed
200
{
201
	crypto_unregister_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
Linus Torvalds's avatar
Linus Torvalds committed
202 203
}

204 205
module_init(sha512_generic_mod_init);
module_exit(sha512_generic_mod_fini);
Linus Torvalds's avatar
Linus Torvalds committed
206 207 208

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms");
209

210
MODULE_ALIAS_CRYPTO("sha384");
211
MODULE_ALIAS_CRYPTO("sha384-generic");
212
MODULE_ALIAS_CRYPTO("sha512");
213
MODULE_ALIAS_CRYPTO("sha512-generic");