blob: e92dbac833f2d6e7e8316fe59f56971c1aed8a3e [file] [log] [blame]
/*
* SHA1 Secure Hash Algorithm.
*
* Derived from cryptoapi implementation.
*
* Copyright (c) Alan Smithee.
* Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
* Copyright (c) Jean-Francois Dive <jef@linuxbe.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 of the License, or (at your option)
* any later version.
*
*/
#include "sha1.h"
/* SHA1 transforms */
#define F1(x, y, z) (z ^ (x & (y ^ z))) /* x ? y : z */
#define F2(x, y, z) (x ^ y ^ z) /* XOR */
#define F3(x, y, z) ((x & y) + (z & (x ^ y))) /* majority */
/* SHA1 per-round constants */
#define K1 0x5A827999UL /* Rounds 0-19: sqrt(2) * 2^30 */
#define K2 0x6ED9EBA1UL /* Rounds 20-39: sqrt(3) * 2^30 */
#define K3 0x8F1BBCDCUL /* Rounds 40-59: sqrt(5) * 2^30 */
#define K4 0xCA62C1D6UL /* Rounds 60-79: sqrt(10) * 2^30 */
static inline u32 rol32(u32 word, unsigned int shift)
{
return (word << shift) | (word >> (32 - shift));
}
static void __sha1_transform(u32 hash[SHA1_DIGEST_WORDS],
const u32 in[SHA1_BLOCK_WORDS],
u32 W[SHA1_WORKSPACE_WORDS])
{
register u32 a, b, c, d, e, t;
int i;
for (i = 0; i < SHA1_BLOCK_WORDS; i++)
W[i] = cpu_to_be32(in[i]);
for (i = 0; i < 64; i++)
W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1);
a = hash[0];
b = hash[1];
c = hash[2];
d = hash[3];
e = hash[4];
for (i = 0; i < 20; i++) {
t = F1(b, c, d) + K1 + rol32(a, 5) + e + W[i];
e = d; d = c; c = rol32(b, 30); b = a; a = t;
}
for (; i < 40; i++) {
t = F2(b, c, d) + K2 + rol32(a, 5) + e + W[i];
e = d; d = c; c = rol32(b, 30); b = a; a = t;
}
for (; i < 60; i++) {
t = F3(b, c, d) + K3 + rol32(a, 5) + e + W[i];
e = d; d = c; c = rol32(b, 30); b = a; a = t;
}
for (; i < 80; i++) {
t = F2(b, c, d) + K4 + rol32(a, 5) + e + W[i];
e = d; d = c; c = rol32(b, 30); b = a; a = t;
}
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
hash[4] += e;
}
static inline void sha1_transform(u32 digest[SHA1_DIGEST_WORDS],
const u32 block[SHA1_BLOCK_WORDS])
{
u32 workspace[SHA1_WORKSPACE_WORDS];
__sha1_transform(digest, block, workspace);
}
void sha1_init(struct sha1_ctx *ctx)
{
ctx->digest[0] = 0x67452301UL;
ctx->digest[1] = 0xEFCDAB89UL;
ctx->digest[2] = 0x98BADCFEUL;
ctx->digest[3] = 0x10325476UL;
ctx->digest[4] = 0xC3D2E1F0UL;
ctx->count = 0;
}
void sha1_update(struct sha1_ctx *ctx, const void *data_in, size_t len)
{
const size_t offset = ctx->count & 0x3f;
const size_t avail = SHA1_BLOCK_BYTES - offset;
const u8 *data = data_in;
ctx->count += len;
if (avail > len) {
memcpy((u8 *)ctx->block + offset, data, len);
return;
}
memcpy((u8 *)ctx->block + offset, data, avail);
sha1_transform(ctx->digest, ctx->block);
data += avail;
len -= avail;
while (len >= SHA1_BLOCK_BYTES) {
memcpy(ctx->block, data, SHA1_BLOCK_BYTES);
sha1_transform(ctx->digest, ctx->block);
data += SHA1_BLOCK_BYTES;
len -= SHA1_BLOCK_BYTES;
}
if (len)
memcpy(ctx->block, data, len);
}
void sha1_final(struct sha1_ctx *ctx, u8 *out)
{
const size_t offset = ctx->count & 0x3f;
char *p = (char *)ctx->block + offset;
int padding = (SHA1_BLOCK_BYTES - SHA1_COUNTER_BYTES) - (offset + 1);
int i;
*p++ = 0x80;
if (padding < 0) {
memset(p, 0, (padding + SHA1_COUNTER_BYTES));
sha1_transform(ctx->digest, ctx->block);
p = (char *)ctx->block;
padding = (SHA1_BLOCK_BYTES - SHA1_COUNTER_BYTES);
}
memset(p, 0, padding);
/* 64-bit bit counter stored in MSW/MSB format */
ctx->block[14] = cpu_to_be32(ctx->count >> 29);
ctx->block[15] = cpu_to_be32(ctx->count << 3);
sha1_transform(ctx->digest, ctx->block);
for (i = 0; i < SHA1_DIGEST_WORDS; i++)
ctx->digest[i] = be32_to_cpu(ctx->digest[i]);
memcpy(out, ctx->digest, SHA1_DIGEST_BYTES);
memset(ctx, 0, sizeof(*ctx));
}