diff options
Diffstat (limited to 'sha512.c')
-rw-r--r-- | sha512.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/sha512.c b/sha512.c new file mode 100644 index 00000000..aba7317e --- /dev/null +++ b/sha512.c @@ -0,0 +1,413 @@ +/* sha512.c + * + * The sha512 hash function FIXME: Add the SHA384 variant. + * + * See http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2001, 2010 Niels Möller + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/* Modelled after the sha1.c code by Peter Gutmann. */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "sha.h" + +#include "macros.h" + +/* A block, treated as a sequence of 64-bit words. */ +#define SHA512_DATA_LENGTH 16 + +#define ROTR(n,x) ((x)>>(n) | ((x)<<(64-(n)))) +#define SHR(n,x) ((x)>>(n)) + +/* The SHA512 functions. The Choice function is the same as the SHA1 + function f1, and the majority function is the same as the SHA1 f3 + function, and the same as for SHA256. */ + +#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) ) +#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) ) + +#define S0(x) (ROTR(28,(x)) ^ ROTR(34,(x)) ^ ROTR(39,(x))) +#define S1(x) (ROTR(14,(x)) ^ ROTR(18,(x)) ^ ROTR(41,(x))) + +#define s0(x) (ROTR(1,(x)) ^ ROTR(8,(x)) ^ SHR(7,(x))) +#define s1(x) (ROTR(19,(x)) ^ ROTR(61,(x)) ^ SHR(6,(x))) + +/* Generated by the gp script + + { + print("obase=16"); + for (i = 1,80, + root = prime(i)^(1/3); + fraction = root - floor(root); + print(floor(2^64 * fraction)); + ); + quit(); + } + + piped through + + |grep -v '^[' | bc \ + |awk '{printf("0x%sULL,%s", $1, NR%3 == 0 ? "\n" : "");}' + + to convert it to hex. +*/ + +static const uint64_t +K[80] = +{ + 0x428A2F98D728AE22ULL,0x7137449123EF65CDULL, + 0xB5C0FBCFEC4D3B2FULL,0xE9B5DBA58189DBBCULL, + 0x3956C25BF348B538ULL,0x59F111F1B605D019ULL, + 0x923F82A4AF194F9BULL,0xAB1C5ED5DA6D8118ULL, + 0xD807AA98A3030242ULL,0x12835B0145706FBEULL, + 0x243185BE4EE4B28CULL,0x550C7DC3D5FFB4E2ULL, + 0x72BE5D74F27B896FULL,0x80DEB1FE3B1696B1ULL, + 0x9BDC06A725C71235ULL,0xC19BF174CF692694ULL, + 0xE49B69C19EF14AD2ULL,0xEFBE4786384F25E3ULL, + 0xFC19DC68B8CD5B5ULL,0x240CA1CC77AC9C65ULL, + 0x2DE92C6F592B0275ULL,0x4A7484AA6EA6E483ULL, + 0x5CB0A9DCBD41FBD4ULL,0x76F988DA831153B5ULL, + 0x983E5152EE66DFABULL,0xA831C66D2DB43210ULL, + 0xB00327C898FB213FULL,0xBF597FC7BEEF0EE4ULL, + 0xC6E00BF33DA88FC2ULL,0xD5A79147930AA725ULL, + 0x6CA6351E003826FULL,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, + 0x6F067AA72176FBAULL,0xA637DC5A2C898A6ULL, + 0x113F9804BEF90DAEULL,0x1B710B35131C471BULL, + 0x28DB77F523047D84ULL,0x32CAAB7B40C72493ULL, + 0x3C9EBE0A15C9BEBCULL,0x431D67C49C100D4CULL, + 0x4CC5D4BECB3E42B6ULL,0x597F299CFC657E2AULL, + 0x5FCB6FAB3AD6FAECULL,0x6C44198C4A475817ULL, +}; + +/* The initial expanding function. The hash function is defined over + an 64-word expanded input array W, where the first 16 are copies of + the input data, and the remaining 64 are defined by + + W[ t ] = s1(W[t-2]) + W[t-7] + s0(W[i-15]) + W[i-16] + + This implementation generates these values on the fly in a circular + buffer. +*/ + +#define EXPAND(W,i) \ +( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) ) + +/* The prototype SHA sub-round. The fundamental sub-round is: + + T1 = h + S1(e) + Choice(e,f,g) + K[t] + W[t] + T2 = S0(a) + Majority(a,b,c) + a' = T1+T2 + b' = a + c' = b + d' = c + e' = d + T1 + f' = e + g' = f + h' = g + + but this is implemented by unrolling the loop 8 times and renaming + the variables + ( h, a, b, c, d, e, f, g ) = ( a, b, c, d, e, f, g, h ) each + iteration. This code is then replicated 8, using the next 8 values + from the W[] array each time */ + +/* It's crucial that DATA is only used once, as that argument will + * have side effects. */ +#define ROUND(a,b,c,d,e,f,g,h,k,data) do { \ + uint64_t T = h + S1(e) + Choice(e,f,g) + k + data; \ + d += T; \ + h = T + S0(a) + Majority(a,b,c); \ +} while (0) + +void +sha512_init(struct sha512_ctx *ctx) +{ + /* Initial values, generated by the gp script + { + for (i = 1,8, + root = prime(i)^(1/2); + fraction = root - floor(root); + print(floor(2^64 * fraction)); + ); + } +. */ + static const uint64_t H0[_SHA512_DIGEST_LENGTH] = + { + 0x6A09E667F3BCC908ULL,0xBB67AE8584CAA73BULL, + 0x3C6EF372FE94F82BULL,0xA54FF53A5F1D36F1ULL, + 0x510E527FADE682D1ULL,0x9B05688C2B3E6C1FULL, + 0x1F83D9ABFB41BD6BULL,0x5BE0CD19137E2179ULL, + }; + + memcpy(ctx->state, H0, sizeof(H0)); + + /* Initialize bit count */ + ctx->count_low = ctx->count_high = 0; + + /* Initialize buffer */ + ctx->index = 0; +} + +/* Perform the SHA transformation. Note that this function destroys + the data area */ + +static void +sha512_transform(uint64_t *state, uint64_t *data) +{ + /* FIXME: XXX Just copied from sha256. */ + uint64_t A, B, C, D, E, F, G, H; /* Local vars */ + unsigned i; + const uint64_t *k; + uint64_t *d; + + /* Set up first buffer and local data buffer */ + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + F = state[5]; + G = state[6]; + H = state[7]; + + /* Heavy mangling */ + /* First 16 subrounds that act on the original data */ + + for (i = 0, k = K, d = data; i<16; i+=8, k += 8, d+= 8) + { + ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); + ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); + ROUND(G, H, A, B, C, D, E, F, k[2], d[2]); + ROUND(F, G, H, A, B, C, D, E, k[3], d[3]); + ROUND(E, F, G, H, A, B, C, D, k[4], d[4]); + ROUND(D, E, F, G, H, A, B, C, k[5], d[5]); + ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); + ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); + } + + for (; i<80; i += 16, k+= 16) + { + ROUND(A, B, C, D, E, F, G, H, k[ 0], EXPAND(data, 0)); + ROUND(H, A, B, C, D, E, F, G, k[ 1], EXPAND(data, 1)); + ROUND(G, H, A, B, C, D, E, F, k[ 2], EXPAND(data, 2)); + ROUND(F, G, H, A, B, C, D, E, k[ 3], EXPAND(data, 3)); + ROUND(E, F, G, H, A, B, C, D, k[ 4], EXPAND(data, 4)); + ROUND(D, E, F, G, H, A, B, C, k[ 5], EXPAND(data, 5)); + ROUND(C, D, E, F, G, H, A, B, k[ 6], EXPAND(data, 6)); + ROUND(B, C, D, E, F, G, H, A, k[ 7], EXPAND(data, 7)); + ROUND(A, B, C, D, E, F, G, H, k[ 8], EXPAND(data, 8)); + ROUND(H, A, B, C, D, E, F, G, k[ 9], EXPAND(data, 9)); + ROUND(G, H, A, B, C, D, E, F, k[10], EXPAND(data, 10)); + ROUND(F, G, H, A, B, C, D, E, k[11], EXPAND(data, 11)); + ROUND(E, F, G, H, A, B, C, D, k[12], EXPAND(data, 12)); + ROUND(D, E, F, G, H, A, B, C, k[13], EXPAND(data, 13)); + ROUND(C, D, E, F, G, H, A, B, k[14], EXPAND(data, 14)); + ROUND(B, C, D, E, F, G, H, A, k[15], EXPAND(data, 15)); + } + + /* Update state */ + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + state[4] += E; + state[5] += F; + state[6] += G; + state[7] += H; +} + +static void +sha512_block(struct sha512_ctx *ctx, const uint8_t *block) +{ + uint64_t data[SHA512_DATA_LENGTH]; + int i; + + /* Update block count */ + if (!++ctx->count_low) + ++ctx->count_high; + + /* Endian independent conversion */ + for (i = 0; i<SHA512_DATA_LENGTH; i++, block += 8) + data[i] = READ_UINT64(block); + + sha512_transform(ctx->state, data); +} + +void +sha512_update(struct sha512_ctx *ctx, + unsigned length, const uint8_t *buffer) +{ + if (ctx->index) + { /* Try to fill partial block */ + unsigned left = SHA512_DATA_SIZE - ctx->index; + if (length < left) + { + memcpy(ctx->block + ctx->index, buffer, length); + ctx->index += length; + return; /* Finished */ + } + else + { + memcpy(ctx->block + ctx->index, buffer, left); + sha512_block(ctx, ctx->block); + buffer += left; + length -= left; + } + } + while (length >= SHA512_DATA_SIZE) + { + sha512_block(ctx, buffer); + buffer += SHA512_DATA_SIZE; + length -= SHA512_DATA_SIZE; + } + + /* Buffer leftovers */ + memcpy(ctx->block, buffer, length); + ctx->index = length; +} + +/* Final wrapup - pad to SHA1_DATA_SIZE-byte boundary with the bit pattern + 1 0* (64-bit count of bits processed, MSB-first) */ + +static void +sha512_final(struct sha512_ctx *ctx) +{ + uint64_t data[SHA512_DATA_LENGTH]; + int i; + int words; + + i = ctx->index; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + + assert(i < SHA512_DATA_SIZE); + ctx->block[i++] = 0x80; + + /* Fill rest of word */ + for( ; i & 7; i++) + ctx->block[i] = 0; + + /* i is now a multiple of the word size 8 */ + words = i >> 3; + for (i = 0; i < words; i++) + data[i] = READ_UINT64(ctx->block + 8*i); + + if (words > (SHA512_DATA_LENGTH-2)) + { /* No room for length in this block. Process it and + * pad with another one */ + for (i = words ; i < SHA512_DATA_LENGTH; i++) + data[i] = 0; + sha512_transform(ctx->state, data); + for (i = 0; i < (SHA512_DATA_LENGTH-2); i++) + data[i] = 0; + } + else + for (i = words ; i < SHA512_DATA_LENGTH - 2; i++) + data[i] = 0; + + /* There are 1024 = 2^10 bits in one block */ + data[SHA512_DATA_LENGTH-2] = (ctx->count_high << 10) | (ctx->count_low >> 54); + data[SHA512_DATA_LENGTH-1] = (ctx->count_low << 10) | (ctx->index << 3); + sha512_transform(ctx->state, data); +} + +void +sha512_digest(struct sha512_ctx *ctx, + unsigned length, + uint8_t *digest) +{ + unsigned i; + unsigned words; + unsigned leftover; + + assert(length <= SHA512_DIGEST_SIZE); + + sha512_final(ctx); + + words = length / 8; + leftover = length % 8; + + for (i = 0; i < words; i++, digest += 8) + WRITE_UINT64(digest, ctx->state[i]); + + if (leftover) + { + uint64_t word; + unsigned j = leftover; + + assert(i < _SHA512_DIGEST_LENGTH); + + word = ctx->state[i]; + + switch (leftover) + { + default: + abort(); + case 7: + digest[--j] = (word >> 8) & 0xff; + /* Fall through */ + case 6: + digest[--j] = (word >> 16) & 0xff; + /* Fall through */ + case 5: + digest[--j] = (word >> 24) & 0xff; + /* Fall through */ + case 4: + digest[--j] = (word >> 32) & 0xff; + case 3: + digest[--j] = (word >> 40) & 0xff; + /* Fall through */ + case 2: + digest[--j] = (word >> 48) & 0xff; + /* Fall through */ + case 1: + digest[--j] = (word >> 56) & 0xff; + } + } + sha512_init(ctx); +} |