summaryrefslogtreecommitdiff
path: root/sha512.c
diff options
context:
space:
mode:
authorNiels Möller <nisse@lysator.liu.se>2010-03-22 22:13:04 +0100
committerNiels Möller <nisse@lysator.liu.se>2010-03-22 22:13:04 +0100
commitd8eb745be4282fc9792b63556cec8f725be12de0 (patch)
treee7d69e0d82ed7ef3960afbd0b5943da2b23e8279 /sha512.c
parent03bdd346f59d460137c26f2f17dcecb37bd500d4 (diff)
downloadnettle-d8eb745be4282fc9792b63556cec8f725be12de0.tar.gz
* Makefile.in (nettle_SOURCES): Added sha512.c and sha512-meta.c.
* sha.h: Added SHA-512-related declarations. * nettle-meta.h: Likewise. * sha512-meta.c: New file. * sha512.c: New file. Rev: nettle/Makefile.in:1.14 Rev: nettle/nettle-meta.h:1.3 Rev: nettle/sha.h:1.2 Rev: nettle/sha512-meta.c:1.1 Rev: nettle/sha512.c:1.1
Diffstat (limited to 'sha512.c')
-rw-r--r--sha512.c413
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);
+}