diff options
Diffstat (limited to 'security/nss/lib/freebl/sha512.c')
-rw-r--r-- | security/nss/lib/freebl/sha512.c | 1655 |
1 files changed, 1655 insertions, 0 deletions
diff --git a/security/nss/lib/freebl/sha512.c b/security/nss/lib/freebl/sha512.c new file mode 100644 index 000000000..528f884b2 --- /dev/null +++ b/security/nss/lib/freebl/sha512.c @@ -0,0 +1,1655 @@ +/* + * sha512.c - implementation of SHA224, SHA256, SHA384 and SHA512 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef FREEBL_NO_DEPEND +#include "stubs.h" +#endif + +#include "prcpucfg.h" +#if defined(NSS_X86) || defined(SHA_NO_LONG_LONG) +#define NOUNROLL512 1 +#undef HAVE_LONG_LONG +#endif +#include "prtypes.h" /* for PRUintXX */ +#include "prlong.h" +#include "secport.h" /* for PORT_XXX */ +#include "blapi.h" +#include "sha256.h" /* for struct SHA256ContextStr */ + +/* ============= Common constants and defines ======================= */ + +#define W ctx->u.w +#define B ctx->u.b +#define H ctx->h + +#define SHR(x, n) (x >> n) +#define SHL(x, n) (x << n) +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define SHA_MIN(a, b) (a < b ? a : b) + +/* Padding used with all flavors of SHA */ +static const PRUint8 pad[240] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + /* compiler will fill the rest in with zeros */ +}; + +/* ============= SHA256 implementation ================================== */ + +/* SHA-256 constants, K256. */ +static const PRUint32 K256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/* SHA-256 initial hash values */ +static const PRUint32 H256[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +#if defined(IS_LITTLE_ENDIAN) +#if (_MSC_VER >= 1300) +#include <stdlib.h> +#pragma intrinsic(_byteswap_ulong) +#define SHA_HTONL(x) _byteswap_ulong(x) +#elif defined(_MSC_VER) && defined(NSS_X86_OR_X64) +#ifndef FORCEINLINE +#if (_MSC_VER >= 1200) +#define FORCEINLINE __forceinline +#else +#define FORCEINLINE __inline +#endif +#endif +#define FASTCALL __fastcall + +static FORCEINLINE PRUint32 FASTCALL +swap4b(PRUint32 dwd) +{ + __asm { + mov eax,dwd + bswap eax + } +} + +#define SHA_HTONL(x) swap4b(x) + +#elif defined(__GNUC__) && defined(NSS_X86_OR_X64) +static __inline__ PRUint32 +swap4b(PRUint32 value) +{ + __asm__("bswap %0" + : "+r"(value)); + return (value); +} +#define SHA_HTONL(x) swap4b(x) + +#elif defined(__GNUC__) && (defined(__thumb2__) || \ + (!defined(__thumb__) && \ + (defined(__ARM_ARCH_6__) || \ + defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__) || \ + defined(__ARM_ARCH_6Z__) || \ + defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) || \ + defined(__ARM_ARCH_7__) || \ + defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)))) +static __inline__ PRUint32 +swap4b(PRUint32 value) +{ + PRUint32 ret; + __asm__("rev %0, %1" + : "=r"(ret) + : "r"(value)); + return ret; +} +#define SHA_HTONL(x) swap4b(x) + +#else +#define SWAP4MASK 0x00FF00FF +static PRUint32 +swap4b(PRUint32 value) +{ + PRUint32 t1 = (value << 16) | (value >> 16); + return ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK); +} +#define SHA_HTONL(x) swap4b(x) +#endif +#define BYTESWAP4(x) x = SHA_HTONL(x) +#endif /* defined(IS_LITTLE_ENDIAN) */ + +#if defined(_MSC_VER) +#pragma intrinsic(_lrotr, _lrotl) +#define ROTR32(x, n) _lrotr(x, n) +#define ROTL32(x, n) _lrotl(x, n) +#else +#define ROTR32(x, n) ((x >> n) | (x << ((8 * sizeof x) - n))) +#define ROTL32(x, n) ((x << n) | (x >> ((8 * sizeof x) - n))) +#endif + +/* Capitol Sigma and lower case sigma functions */ +#define S0(x) (ROTR32(x, 2) ^ ROTR32(x, 13) ^ ROTR32(x, 22)) +#define S1(x) (ROTR32(x, 6) ^ ROTR32(x, 11) ^ ROTR32(x, 25)) +#define s0(x) (ROTR32(x, 7) ^ ROTR32(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR32(x, 17) ^ ROTR32(x, 19) ^ SHR(x, 10)) + +SHA256Context * +SHA256_NewContext(void) +{ + SHA256Context *ctx = PORT_New(SHA256Context); + return ctx; +} + +void +SHA256_DestroyContext(SHA256Context *ctx, PRBool freeit) +{ + memset(ctx, 0, sizeof *ctx); + if (freeit) { + PORT_Free(ctx); + } +} + +void +SHA256_Begin(SHA256Context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + memcpy(H, H256, sizeof H256); +} + +static void +SHA256_Compress(SHA256Context *ctx) +{ + { +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP4(W[0]); + BYTESWAP4(W[1]); + BYTESWAP4(W[2]); + BYTESWAP4(W[3]); + BYTESWAP4(W[4]); + BYTESWAP4(W[5]); + BYTESWAP4(W[6]); + BYTESWAP4(W[7]); + BYTESWAP4(W[8]); + BYTESWAP4(W[9]); + BYTESWAP4(W[10]); + BYTESWAP4(W[11]); + BYTESWAP4(W[12]); + BYTESWAP4(W[13]); + BYTESWAP4(W[14]); + BYTESWAP4(W[15]); +#endif + +#define INITW(t) W[t] = (s1(W[t - 2]) + W[t - 7] + s0(W[t - 15]) + W[t - 16]) + +/* prepare the "message schedule" */ +#ifdef NOUNROLL256 + { + int t; + for (t = 16; t < 64; ++t) { + INITW(t); + } + } +#else + INITW(16); + INITW(17); + INITW(18); + INITW(19); + + INITW(20); + INITW(21); + INITW(22); + INITW(23); + INITW(24); + INITW(25); + INITW(26); + INITW(27); + INITW(28); + INITW(29); + + INITW(30); + INITW(31); + INITW(32); + INITW(33); + INITW(34); + INITW(35); + INITW(36); + INITW(37); + INITW(38); + INITW(39); + + INITW(40); + INITW(41); + INITW(42); + INITW(43); + INITW(44); + INITW(45); + INITW(46); + INITW(47); + INITW(48); + INITW(49); + + INITW(50); + INITW(51); + INITW(52); + INITW(53); + INITW(54); + INITW(55); + INITW(56); + INITW(57); + INITW(58); + INITW(59); + + INITW(60); + INITW(61); + INITW(62); + INITW(63); + +#endif +#undef INITW + } + { + PRUint32 a, b, c, d, e, f, g, h; + + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + +#define ROUND(n, a, b, c, d, e, f, g, h) \ + h += S1(e) + Ch(e, f, g) + K256[n] + W[n]; \ + d += h; \ + h += S0(a) + Maj(a, b, c); + +#ifdef NOUNROLL256 + { + int t; + for (t = 0; t < 64; t += 8) { + ROUND(t + 0, a, b, c, d, e, f, g, h) + ROUND(t + 1, h, a, b, c, d, e, f, g) + ROUND(t + 2, g, h, a, b, c, d, e, f) + ROUND(t + 3, f, g, h, a, b, c, d, e) + ROUND(t + 4, e, f, g, h, a, b, c, d) + ROUND(t + 5, d, e, f, g, h, a, b, c) + ROUND(t + 6, c, d, e, f, g, h, a, b) + ROUND(t + 7, b, c, d, e, f, g, h, a) + } + } +#else + ROUND(0, a, b, c, d, e, f, g, h) + ROUND(1, h, a, b, c, d, e, f, g) + ROUND(2, g, h, a, b, c, d, e, f) + ROUND(3, f, g, h, a, b, c, d, e) + ROUND(4, e, f, g, h, a, b, c, d) + ROUND(5, d, e, f, g, h, a, b, c) + ROUND(6, c, d, e, f, g, h, a, b) + ROUND(7, b, c, d, e, f, g, h, a) + + ROUND(8, a, b, c, d, e, f, g, h) + ROUND(9, h, a, b, c, d, e, f, g) + ROUND(10, g, h, a, b, c, d, e, f) + ROUND(11, f, g, h, a, b, c, d, e) + ROUND(12, e, f, g, h, a, b, c, d) + ROUND(13, d, e, f, g, h, a, b, c) + ROUND(14, c, d, e, f, g, h, a, b) + ROUND(15, b, c, d, e, f, g, h, a) + + ROUND(16, a, b, c, d, e, f, g, h) + ROUND(17, h, a, b, c, d, e, f, g) + ROUND(18, g, h, a, b, c, d, e, f) + ROUND(19, f, g, h, a, b, c, d, e) + ROUND(20, e, f, g, h, a, b, c, d) + ROUND(21, d, e, f, g, h, a, b, c) + ROUND(22, c, d, e, f, g, h, a, b) + ROUND(23, b, c, d, e, f, g, h, a) + + ROUND(24, a, b, c, d, e, f, g, h) + ROUND(25, h, a, b, c, d, e, f, g) + ROUND(26, g, h, a, b, c, d, e, f) + ROUND(27, f, g, h, a, b, c, d, e) + ROUND(28, e, f, g, h, a, b, c, d) + ROUND(29, d, e, f, g, h, a, b, c) + ROUND(30, c, d, e, f, g, h, a, b) + ROUND(31, b, c, d, e, f, g, h, a) + + ROUND(32, a, b, c, d, e, f, g, h) + ROUND(33, h, a, b, c, d, e, f, g) + ROUND(34, g, h, a, b, c, d, e, f) + ROUND(35, f, g, h, a, b, c, d, e) + ROUND(36, e, f, g, h, a, b, c, d) + ROUND(37, d, e, f, g, h, a, b, c) + ROUND(38, c, d, e, f, g, h, a, b) + ROUND(39, b, c, d, e, f, g, h, a) + + ROUND(40, a, b, c, d, e, f, g, h) + ROUND(41, h, a, b, c, d, e, f, g) + ROUND(42, g, h, a, b, c, d, e, f) + ROUND(43, f, g, h, a, b, c, d, e) + ROUND(44, e, f, g, h, a, b, c, d) + ROUND(45, d, e, f, g, h, a, b, c) + ROUND(46, c, d, e, f, g, h, a, b) + ROUND(47, b, c, d, e, f, g, h, a) + + ROUND(48, a, b, c, d, e, f, g, h) + ROUND(49, h, a, b, c, d, e, f, g) + ROUND(50, g, h, a, b, c, d, e, f) + ROUND(51, f, g, h, a, b, c, d, e) + ROUND(52, e, f, g, h, a, b, c, d) + ROUND(53, d, e, f, g, h, a, b, c) + ROUND(54, c, d, e, f, g, h, a, b) + ROUND(55, b, c, d, e, f, g, h, a) + + ROUND(56, a, b, c, d, e, f, g, h) + ROUND(57, h, a, b, c, d, e, f, g) + ROUND(58, g, h, a, b, c, d, e, f) + ROUND(59, f, g, h, a, b, c, d, e) + ROUND(60, e, f, g, h, a, b, c, d) + ROUND(61, d, e, f, g, h, a, b, c) + ROUND(62, c, d, e, f, g, h, a, b) + ROUND(63, b, c, d, e, f, g, h, a) +#endif + + H[0] += a; + H[1] += b; + H[2] += c; + H[3] += d; + H[4] += e; + H[5] += f; + H[6] += g; + H[7] += h; + } +#undef ROUND +} + +#undef s0 +#undef s1 +#undef S0 +#undef S1 + +void +SHA256_Update(SHA256Context *ctx, const unsigned char *input, + unsigned int inputLen) +{ + unsigned int inBuf = ctx->sizeLo & 0x3f; + if (!inputLen) + return; + + /* Add inputLen into the count of bytes processed, before processing */ + if ((ctx->sizeLo += inputLen) < inputLen) + ctx->sizeHi++; + + /* if data already in buffer, attemp to fill rest of buffer */ + if (inBuf) { + unsigned int todo = SHA256_BLOCK_LENGTH - inBuf; + if (inputLen < todo) + todo = inputLen; + memcpy(B + inBuf, input, todo); + input += todo; + inputLen -= todo; + if (inBuf + todo == SHA256_BLOCK_LENGTH) + SHA256_Compress(ctx); + } + + /* if enough data to fill one or more whole buffers, process them. */ + while (inputLen >= SHA256_BLOCK_LENGTH) { + memcpy(B, input, SHA256_BLOCK_LENGTH); + input += SHA256_BLOCK_LENGTH; + inputLen -= SHA256_BLOCK_LENGTH; + SHA256_Compress(ctx); + } + /* if data left over, fill it into buffer */ + if (inputLen) + memcpy(B, input, inputLen); +} + +void +SHA256_End(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + unsigned int inBuf = ctx->sizeLo & 0x3f; + unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf); + PRUint32 hi, lo; + + hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29); + lo = (ctx->sizeLo << 3); + + SHA256_Update(ctx, pad, padLen); + +#if defined(IS_LITTLE_ENDIAN) + W[14] = SHA_HTONL(hi); + W[15] = SHA_HTONL(lo); +#else + W[14] = hi; + W[15] = lo; +#endif + SHA256_Compress(ctx); + +/* now output the answer */ +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP4(H[0]); + BYTESWAP4(H[1]); + BYTESWAP4(H[2]); + BYTESWAP4(H[3]); + BYTESWAP4(H[4]); + BYTESWAP4(H[5]); + BYTESWAP4(H[6]); + BYTESWAP4(H[7]); +#endif + padLen = PR_MIN(SHA256_LENGTH, maxDigestLen); + memcpy(digest, H, padLen); + if (digestLen) + *digestLen = padLen; +} + +void +SHA256_EndRaw(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + PRUint32 h[8]; + unsigned int len; + + memcpy(h, ctx->h, sizeof(h)); + +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP4(h[0]); + BYTESWAP4(h[1]); + BYTESWAP4(h[2]); + BYTESWAP4(h[3]); + BYTESWAP4(h[4]); + BYTESWAP4(h[5]); + BYTESWAP4(h[6]); + BYTESWAP4(h[7]); +#endif + + len = PR_MIN(SHA256_LENGTH, maxDigestLen); + memcpy(digest, h, len); + if (digestLen) + *digestLen = len; +} + +SECStatus +SHA256_HashBuf(unsigned char *dest, const unsigned char *src, + PRUint32 src_length) +{ + SHA256Context ctx; + unsigned int outLen; + + SHA256_Begin(&ctx); + SHA256_Update(&ctx, src, src_length); + SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH); + memset(&ctx, 0, sizeof ctx); + + return SECSuccess; +} + +SECStatus +SHA256_Hash(unsigned char *dest, const char *src) +{ + return SHA256_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); +} + +void +SHA256_TraceState(SHA256Context *ctx) +{ +} + +unsigned int +SHA256_FlattenSize(SHA256Context *ctx) +{ + return sizeof *ctx; +} + +SECStatus +SHA256_Flatten(SHA256Context *ctx, unsigned char *space) +{ + PORT_Memcpy(space, ctx, sizeof *ctx); + return SECSuccess; +} + +SHA256Context * +SHA256_Resurrect(unsigned char *space, void *arg) +{ + SHA256Context *ctx = SHA256_NewContext(); + if (ctx) + PORT_Memcpy(ctx, space, sizeof *ctx); + return ctx; +} + +void +SHA256_Clone(SHA256Context *dest, SHA256Context *src) +{ + memcpy(dest, src, sizeof *dest); +} + +/* ============= SHA224 implementation ================================== */ + +/* SHA-224 initial hash values */ +static const PRUint32 H224[8] = { + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 +}; + +SHA224Context * +SHA224_NewContext(void) +{ + return SHA256_NewContext(); +} + +void +SHA224_DestroyContext(SHA224Context *ctx, PRBool freeit) +{ + SHA256_DestroyContext(ctx, freeit); +} + +void +SHA224_Begin(SHA224Context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + memcpy(H, H224, sizeof H224); +} + +void +SHA224_Update(SHA224Context *ctx, const unsigned char *input, + unsigned int inputLen) +{ + SHA256_Update(ctx, input, inputLen); +} + +void +SHA224_End(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + unsigned int maxLen = SHA_MIN(maxDigestLen, SHA224_LENGTH); + SHA256_End(ctx, digest, digestLen, maxLen); +} + +void +SHA224_EndRaw(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + unsigned int maxLen = SHA_MIN(maxDigestLen, SHA224_LENGTH); + SHA256_EndRaw(ctx, digest, digestLen, maxLen); +} + +SECStatus +SHA224_HashBuf(unsigned char *dest, const unsigned char *src, + PRUint32 src_length) +{ + SHA256Context ctx; + unsigned int outLen; + + SHA224_Begin(&ctx); + SHA256_Update(&ctx, src, src_length); + SHA256_End(&ctx, dest, &outLen, SHA224_LENGTH); + memset(&ctx, 0, sizeof ctx); + + return SECSuccess; +} + +SECStatus +SHA224_Hash(unsigned char *dest, const char *src) +{ + return SHA224_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); +} + +void +SHA224_TraceState(SHA224Context *ctx) +{ +} + +unsigned int +SHA224_FlattenSize(SHA224Context *ctx) +{ + return SHA256_FlattenSize(ctx); +} + +SECStatus +SHA224_Flatten(SHA224Context *ctx, unsigned char *space) +{ + return SHA256_Flatten(ctx, space); +} + +SHA224Context * +SHA224_Resurrect(unsigned char *space, void *arg) +{ + return SHA256_Resurrect(space, arg); +} + +void +SHA224_Clone(SHA224Context *dest, SHA224Context *src) +{ + SHA256_Clone(dest, src); +} + +/* ======= SHA512 and SHA384 common constants and defines ================= */ + +/* common #defines for SHA512 and SHA384 */ +#if defined(HAVE_LONG_LONG) +#if defined(_MSC_VER) +#pragma intrinsic(_rotr64, _rotl64) +#define ROTR64(x, n) _rotr64(x, n) +#define ROTL64(x, n) _rotl64(x, n) +#else +#define ROTR64(x, n) ((x >> n) | (x << (64 - n))) +#define ROTL64(x, n) ((x << n) | (x >> (64 - n))) +#endif + +#define S0(x) (ROTR64(x, 28) ^ ROTR64(x, 34) ^ ROTR64(x, 39)) +#define S1(x) (ROTR64(x, 14) ^ ROTR64(x, 18) ^ ROTR64(x, 41)) +#define s0(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ SHR(x, 7)) +#define s1(x) (ROTR64(x, 19) ^ ROTR64(x, 61) ^ SHR(x, 6)) + +#if PR_BYTES_PER_LONG == 8 +#define ULLC(hi, lo) 0x##hi##lo##UL +#elif defined(_MSC_VER) +#define ULLC(hi, lo) 0x##hi##lo##ui64 +#else +#define ULLC(hi, lo) 0x##hi##lo##ULL +#endif + +#if defined(IS_LITTLE_ENDIAN) +#if defined(_MSC_VER) +#pragma intrinsic(_byteswap_uint64) +#define SHA_HTONLL(x) _byteswap_uint64(x) + +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__x86_64)) +static __inline__ PRUint64 +swap8b(PRUint64 value) +{ + __asm__("bswapq %0" + : "+r"(value)); + return (value); +} +#define SHA_HTONLL(x) swap8b(x) + +#else +#define SHA_MASK16 ULLC(0000FFFF, 0000FFFF) +#define SHA_MASK8 ULLC(00FF00FF, 00FF00FF) +static PRUint64 +swap8b(PRUint64 x) +{ + PRUint64 t1 = x; + t1 = ((t1 & SHA_MASK8) << 8) | ((t1 >> 8) & SHA_MASK8); + t1 = ((t1 & SHA_MASK16) << 16) | ((t1 >> 16) & SHA_MASK16); + return (t1 >> 32) | (t1 << 32); +} +#define SHA_HTONLL(x) swap8b(x) +#endif +#define BYTESWAP8(x) x = SHA_HTONLL(x) +#endif /* defined(IS_LITTLE_ENDIAN) */ + +#else /* no long long */ + +#if defined(IS_LITTLE_ENDIAN) +#define ULLC(hi, lo) \ + { \ + 0x##lo##U, 0x##hi##U \ + } +#define SHA_HTONLL(x) (BYTESWAP4(x.lo), BYTESWAP4(x.hi), \ + x.hi ^= x.lo ^= x.hi ^= x.lo, x) +#define BYTESWAP8(x) \ + do { \ + PRUint32 tmp; \ + BYTESWAP4(x.lo); \ + BYTESWAP4(x.hi); \ + tmp = x.lo; \ + x.lo = x.hi; \ + x.hi = tmp; \ + } while (0) +#else +#define ULLC(hi, lo) \ + { \ + 0x##hi##U, 0x##lo##U \ + } +#endif + +#endif + +/* SHA-384 and SHA-512 constants, K512. */ +static const PRUint64 K512[80] = { +#if PR_BYTES_PER_LONG == 8 + 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, + 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, + 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, + 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL, + 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, + 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL, + 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, + 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL, + 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, + 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL, + 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, + 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL, + 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, + 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL, + 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, + 0x06ca6351e003826fUL, 0x142929670a0e6e70UL, + 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, + 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL, + 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, + 0x81c2c92e47edaee6UL, 0x92722c851482353bUL, + 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, + 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL, + 0xd192e819d6ef5218UL, 0xd69906245565a910UL, + 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL, + 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, + 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL, + 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, + 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL, + 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, + 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL, + 0x90befffa23631e28UL, 0xa4506cebde82bde9UL, + 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL, + 0xca273eceea26619cUL, 0xd186b8c721c0c207UL, + 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL, + 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, + 0x113f9804bef90daeUL, 0x1b710b35131c471bUL, + 0x28db77f523047d84UL, 0x32caab7b40c72493UL, + 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL, + 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, + 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL +#else + ULLC(428a2f98, d728ae22), ULLC(71374491, 23ef65cd), + ULLC(b5c0fbcf, ec4d3b2f), ULLC(e9b5dba5, 8189dbbc), + ULLC(3956c25b, f348b538), ULLC(59f111f1, b605d019), + ULLC(923f82a4, af194f9b), ULLC(ab1c5ed5, da6d8118), + ULLC(d807aa98, a3030242), ULLC(12835b01, 45706fbe), + ULLC(243185be, 4ee4b28c), ULLC(550c7dc3, d5ffb4e2), + ULLC(72be5d74, f27b896f), ULLC(80deb1fe, 3b1696b1), + ULLC(9bdc06a7, 25c71235), ULLC(c19bf174, cf692694), + ULLC(e49b69c1, 9ef14ad2), ULLC(efbe4786, 384f25e3), + ULLC(0fc19dc6, 8b8cd5b5), ULLC(240ca1cc, 77ac9c65), + ULLC(2de92c6f, 592b0275), ULLC(4a7484aa, 6ea6e483), + ULLC(5cb0a9dc, bd41fbd4), ULLC(76f988da, 831153b5), + ULLC(983e5152, ee66dfab), ULLC(a831c66d, 2db43210), + ULLC(b00327c8, 98fb213f), ULLC(bf597fc7, beef0ee4), + ULLC(c6e00bf3, 3da88fc2), ULLC(d5a79147, 930aa725), + ULLC(06ca6351, e003826f), ULLC(14292967, 0a0e6e70), + ULLC(27b70a85, 46d22ffc), ULLC(2e1b2138, 5c26c926), + ULLC(4d2c6dfc, 5ac42aed), ULLC(53380d13, 9d95b3df), + ULLC(650a7354, 8baf63de), ULLC(766a0abb, 3c77b2a8), + ULLC(81c2c92e, 47edaee6), ULLC(92722c85, 1482353b), + ULLC(a2bfe8a1, 4cf10364), ULLC(a81a664b, bc423001), + ULLC(c24b8b70, d0f89791), ULLC(c76c51a3, 0654be30), + ULLC(d192e819, d6ef5218), ULLC(d6990624, 5565a910), + ULLC(f40e3585, 5771202a), ULLC(106aa070, 32bbd1b8), + ULLC(19a4c116, b8d2d0c8), ULLC(1e376c08, 5141ab53), + ULLC(2748774c, df8eeb99), ULLC(34b0bcb5, e19b48a8), + ULLC(391c0cb3, c5c95a63), ULLC(4ed8aa4a, e3418acb), + ULLC(5b9cca4f, 7763e373), ULLC(682e6ff3, d6b2b8a3), + ULLC(748f82ee, 5defb2fc), ULLC(78a5636f, 43172f60), + ULLC(84c87814, a1f0ab72), ULLC(8cc70208, 1a6439ec), + ULLC(90befffa, 23631e28), ULLC(a4506ceb, de82bde9), + ULLC(bef9a3f7, b2c67915), ULLC(c67178f2, e372532b), + ULLC(ca273ece, ea26619c), ULLC(d186b8c7, 21c0c207), + ULLC(eada7dd6, cde0eb1e), ULLC(f57d4f7f, ee6ed178), + ULLC(06f067aa, 72176fba), ULLC(0a637dc5, a2c898a6), + ULLC(113f9804, bef90dae), ULLC(1b710b35, 131c471b), + ULLC(28db77f5, 23047d84), ULLC(32caab7b, 40c72493), + ULLC(3c9ebe0a, 15c9bebc), ULLC(431d67c4, 9c100d4c), + ULLC(4cc5d4be, cb3e42b6), ULLC(597f299c, fc657e2a), + ULLC(5fcb6fab, 3ad6faec), ULLC(6c44198c, 4a475817) +#endif +}; + +struct SHA512ContextStr { + union { + PRUint64 w[80]; /* message schedule, input buffer, plus 64 words */ + PRUint32 l[160]; + PRUint8 b[640]; + } u; + PRUint64 h[8]; /* 8 state variables */ + PRUint64 sizeLo; /* 64-bit count of hashed bytes. */ +}; + +/* =========== SHA512 implementation ===================================== */ + +/* SHA-512 initial hash values */ +static const PRUint64 H512[8] = { +#if PR_BYTES_PER_LONG == 8 + 0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL, + 0x3c6ef372fe94f82bUL, 0xa54ff53a5f1d36f1UL, + 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL, + 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL +#else + ULLC(6a09e667, f3bcc908), ULLC(bb67ae85, 84caa73b), + ULLC(3c6ef372, fe94f82b), ULLC(a54ff53a, 5f1d36f1), + ULLC(510e527f, ade682d1), ULLC(9b05688c, 2b3e6c1f), + ULLC(1f83d9ab, fb41bd6b), ULLC(5be0cd19, 137e2179) +#endif +}; + +SHA512Context * +SHA512_NewContext(void) +{ + SHA512Context *ctx = PORT_New(SHA512Context); + return ctx; +} + +void +SHA512_DestroyContext(SHA512Context *ctx, PRBool freeit) +{ + memset(ctx, 0, sizeof *ctx); + if (freeit) { + PORT_Free(ctx); + } +} + +void +SHA512_Begin(SHA512Context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + memcpy(H, H512, sizeof H512); +} + +#if defined(SHA512_TRACE) +#if defined(HAVE_LONG_LONG) +#define DUMP(n, a, d, e, h) printf(" t = %2d, %s = %016lx, %s = %016lx\n", \ + n, #e, d, #a, h); +#else +#define DUMP(n, a, d, e, h) printf(" t = %2d, %s = %08x%08x, %s = %08x%08x\n", \ + n, #e, d.hi, d.lo, #a, h.hi, h.lo); +#endif +#else +#define DUMP(n, a, d, e, h) +#endif + +#if defined(HAVE_LONG_LONG) + +#define ADDTO(x, y) y += x + +#define INITW(t) W[t] = (s1(W[t - 2]) + W[t - 7] + s0(W[t - 15]) + W[t - 16]) + +#define ROUND(n, a, b, c, d, e, f, g, h) \ + h += S1(e) + Ch(e, f, g) + K512[n] + W[n]; \ + d += h; \ + h += S0(a) + Maj(a, b, c); \ + DUMP(n, a, d, e, h) + +#else /* use only 32-bit variables, and don't unroll loops */ + +#undef NOUNROLL512 +#define NOUNROLL512 1 + +#define ADDTO(x, y) \ + y.lo += x.lo; \ + y.hi += x.hi + (x.lo > y.lo) + +#define ROTR64a(x, n, lo, hi) (x.lo >> n | x.hi << (32 - n)) +#define ROTR64A(x, n, lo, hi) (x.lo << (64 - n) | x.hi >> (n - 32)) +#define SHR64a(x, n, lo, hi) (x.lo >> n | x.hi << (32 - n)) + +/* Capitol Sigma and lower case sigma functions */ +#define s0lo(x) (ROTR64a(x, 1, lo, hi) ^ ROTR64a(x, 8, lo, hi) ^ SHR64a(x, 7, lo, hi)) +#define s0hi(x) (ROTR64a(x, 1, hi, lo) ^ ROTR64a(x, 8, hi, lo) ^ (x.hi >> 7)) + +#define s1lo(x) (ROTR64a(x, 19, lo, hi) ^ ROTR64A(x, 61, lo, hi) ^ SHR64a(x, 6, lo, hi)) +#define s1hi(x) (ROTR64a(x, 19, hi, lo) ^ ROTR64A(x, 61, hi, lo) ^ (x.hi >> 6)) + +#define S0lo(x) (ROTR64a(x, 28, lo, hi) ^ ROTR64A(x, 34, lo, hi) ^ ROTR64A(x, 39, lo, hi)) +#define S0hi(x) (ROTR64a(x, 28, hi, lo) ^ ROTR64A(x, 34, hi, lo) ^ ROTR64A(x, 39, hi, lo)) + +#define S1lo(x) (ROTR64a(x, 14, lo, hi) ^ ROTR64a(x, 18, lo, hi) ^ ROTR64A(x, 41, lo, hi)) +#define S1hi(x) (ROTR64a(x, 14, hi, lo) ^ ROTR64a(x, 18, hi, lo) ^ ROTR64A(x, 41, hi, lo)) + +/* 32-bit versions of Ch and Maj */ +#define Chxx(x, y, z, lo) ((x.lo & y.lo) ^ (~x.lo & z.lo)) +#define Majx(x, y, z, lo) ((x.lo & y.lo) ^ (x.lo & z.lo) ^ (y.lo & z.lo)) + +#define INITW(t) \ + do { \ + PRUint32 lo, tm; \ + PRUint32 cy = 0; \ + lo = s1lo(W[t - 2]); \ + lo += (tm = W[t - 7].lo); \ + if (lo < tm) \ + cy++; \ + lo += (tm = s0lo(W[t - 15])); \ + if (lo < tm) \ + cy++; \ + lo += (tm = W[t - 16].lo); \ + if (lo < tm) \ + cy++; \ + W[t].lo = lo; \ + W[t].hi = cy + s1hi(W[t - 2]) + W[t - 7].hi + s0hi(W[t - 15]) + W[t - 16].hi; \ + } while (0) + +#define ROUND(n, a, b, c, d, e, f, g, h) \ + { \ + PRUint32 lo, tm, cy; \ + lo = S1lo(e); \ + lo += (tm = Chxx(e, f, g, lo)); \ + cy = (lo < tm); \ + lo += (tm = K512[n].lo); \ + if (lo < tm) \ + cy++; \ + lo += (tm = W[n].lo); \ + if (lo < tm) \ + cy++; \ + h.lo += lo; \ + if (h.lo < lo) \ + cy++; \ + h.hi += cy + S1hi(e) + Chxx(e, f, g, hi) + K512[n].hi + W[n].hi; \ + d.lo += h.lo; \ + d.hi += h.hi + (d.lo < h.lo); \ + lo = S0lo(a); \ + lo += (tm = Majx(a, b, c, lo)); \ + cy = (lo < tm); \ + h.lo += lo; \ + if (h.lo < lo) \ + cy++; \ + h.hi += cy + S0hi(a) + Majx(a, b, c, hi); \ + DUMP(n, a, d, e, h) \ + } +#endif + +static void +SHA512_Compress(SHA512Context *ctx) +{ +#if defined(IS_LITTLE_ENDIAN) + { + BYTESWAP8(W[0]); + BYTESWAP8(W[1]); + BYTESWAP8(W[2]); + BYTESWAP8(W[3]); + BYTESWAP8(W[4]); + BYTESWAP8(W[5]); + BYTESWAP8(W[6]); + BYTESWAP8(W[7]); + BYTESWAP8(W[8]); + BYTESWAP8(W[9]); + BYTESWAP8(W[10]); + BYTESWAP8(W[11]); + BYTESWAP8(W[12]); + BYTESWAP8(W[13]); + BYTESWAP8(W[14]); + BYTESWAP8(W[15]); + } +#endif + + { +#ifdef NOUNROLL512 + { + /* prepare the "message schedule" */ + int t; + for (t = 16; t < 80; ++t) { + INITW(t); + } + } +#else + INITW(16); + INITW(17); + INITW(18); + INITW(19); + + INITW(20); + INITW(21); + INITW(22); + INITW(23); + INITW(24); + INITW(25); + INITW(26); + INITW(27); + INITW(28); + INITW(29); + + INITW(30); + INITW(31); + INITW(32); + INITW(33); + INITW(34); + INITW(35); + INITW(36); + INITW(37); + INITW(38); + INITW(39); + + INITW(40); + INITW(41); + INITW(42); + INITW(43); + INITW(44); + INITW(45); + INITW(46); + INITW(47); + INITW(48); + INITW(49); + + INITW(50); + INITW(51); + INITW(52); + INITW(53); + INITW(54); + INITW(55); + INITW(56); + INITW(57); + INITW(58); + INITW(59); + + INITW(60); + INITW(61); + INITW(62); + INITW(63); + INITW(64); + INITW(65); + INITW(66); + INITW(67); + INITW(68); + INITW(69); + + INITW(70); + INITW(71); + INITW(72); + INITW(73); + INITW(74); + INITW(75); + INITW(76); + INITW(77); + INITW(78); + INITW(79); +#endif + } +#ifdef SHA512_TRACE + { + int i; + for (i = 0; i < 80; ++i) { +#ifdef HAVE_LONG_LONG + printf("W[%2d] = %016lx\n", i, W[i]); +#else + printf("W[%2d] = %08x%08x\n", i, W[i].hi, W[i].lo); +#endif + } + } +#endif + { + PRUint64 a, b, c, d, e, f, g, h; + + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + +#ifdef NOUNROLL512 + { + int t; + for (t = 0; t < 80; t += 8) { + ROUND(t + 0, a, b, c, d, e, f, g, h) + ROUND(t + 1, h, a, b, c, d, e, f, g) + ROUND(t + 2, g, h, a, b, c, d, e, f) + ROUND(t + 3, f, g, h, a, b, c, d, e) + ROUND(t + 4, e, f, g, h, a, b, c, d) + ROUND(t + 5, d, e, f, g, h, a, b, c) + ROUND(t + 6, c, d, e, f, g, h, a, b) + ROUND(t + 7, b, c, d, e, f, g, h, a) + } + } +#else + ROUND(0, a, b, c, d, e, f, g, h) + ROUND(1, h, a, b, c, d, e, f, g) + ROUND(2, g, h, a, b, c, d, e, f) + ROUND(3, f, g, h, a, b, c, d, e) + ROUND(4, e, f, g, h, a, b, c, d) + ROUND(5, d, e, f, g, h, a, b, c) + ROUND(6, c, d, e, f, g, h, a, b) + ROUND(7, b, c, d, e, f, g, h, a) + + ROUND(8, a, b, c, d, e, f, g, h) + ROUND(9, h, a, b, c, d, e, f, g) + ROUND(10, g, h, a, b, c, d, e, f) + ROUND(11, f, g, h, a, b, c, d, e) + ROUND(12, e, f, g, h, a, b, c, d) + ROUND(13, d, e, f, g, h, a, b, c) + ROUND(14, c, d, e, f, g, h, a, b) + ROUND(15, b, c, d, e, f, g, h, a) + + ROUND(16, a, b, c, d, e, f, g, h) + ROUND(17, h, a, b, c, d, e, f, g) + ROUND(18, g, h, a, b, c, d, e, f) + ROUND(19, f, g, h, a, b, c, d, e) + ROUND(20, e, f, g, h, a, b, c, d) + ROUND(21, d, e, f, g, h, a, b, c) + ROUND(22, c, d, e, f, g, h, a, b) + ROUND(23, b, c, d, e, f, g, h, a) + + ROUND(24, a, b, c, d, e, f, g, h) + ROUND(25, h, a, b, c, d, e, f, g) + ROUND(26, g, h, a, b, c, d, e, f) + ROUND(27, f, g, h, a, b, c, d, e) + ROUND(28, e, f, g, h, a, b, c, d) + ROUND(29, d, e, f, g, h, a, b, c) + ROUND(30, c, d, e, f, g, h, a, b) + ROUND(31, b, c, d, e, f, g, h, a) + + ROUND(32, a, b, c, d, e, f, g, h) + ROUND(33, h, a, b, c, d, e, f, g) + ROUND(34, g, h, a, b, c, d, e, f) + ROUND(35, f, g, h, a, b, c, d, e) + ROUND(36, e, f, g, h, a, b, c, d) + ROUND(37, d, e, f, g, h, a, b, c) + ROUND(38, c, d, e, f, g, h, a, b) + ROUND(39, b, c, d, e, f, g, h, a) + + ROUND(40, a, b, c, d, e, f, g, h) + ROUND(41, h, a, b, c, d, e, f, g) + ROUND(42, g, h, a, b, c, d, e, f) + ROUND(43, f, g, h, a, b, c, d, e) + ROUND(44, e, f, g, h, a, b, c, d) + ROUND(45, d, e, f, g, h, a, b, c) + ROUND(46, c, d, e, f, g, h, a, b) + ROUND(47, b, c, d, e, f, g, h, a) + + ROUND(48, a, b, c, d, e, f, g, h) + ROUND(49, h, a, b, c, d, e, f, g) + ROUND(50, g, h, a, b, c, d, e, f) + ROUND(51, f, g, h, a, b, c, d, e) + ROUND(52, e, f, g, h, a, b, c, d) + ROUND(53, d, e, f, g, h, a, b, c) + ROUND(54, c, d, e, f, g, h, a, b) + ROUND(55, b, c, d, e, f, g, h, a) + + ROUND(56, a, b, c, d, e, f, g, h) + ROUND(57, h, a, b, c, d, e, f, g) + ROUND(58, g, h, a, b, c, d, e, f) + ROUND(59, f, g, h, a, b, c, d, e) + ROUND(60, e, f, g, h, a, b, c, d) + ROUND(61, d, e, f, g, h, a, b, c) + ROUND(62, c, d, e, f, g, h, a, b) + ROUND(63, b, c, d, e, f, g, h, a) + + ROUND(64, a, b, c, d, e, f, g, h) + ROUND(65, h, a, b, c, d, e, f, g) + ROUND(66, g, h, a, b, c, d, e, f) + ROUND(67, f, g, h, a, b, c, d, e) + ROUND(68, e, f, g, h, a, b, c, d) + ROUND(69, d, e, f, g, h, a, b, c) + ROUND(70, c, d, e, f, g, h, a, b) + ROUND(71, b, c, d, e, f, g, h, a) + + ROUND(72, a, b, c, d, e, f, g, h) + ROUND(73, h, a, b, c, d, e, f, g) + ROUND(74, g, h, a, b, c, d, e, f) + ROUND(75, f, g, h, a, b, c, d, e) + ROUND(76, e, f, g, h, a, b, c, d) + ROUND(77, d, e, f, g, h, a, b, c) + ROUND(78, c, d, e, f, g, h, a, b) + ROUND(79, b, c, d, e, f, g, h, a) +#endif + + ADDTO(a, H[0]); + ADDTO(b, H[1]); + ADDTO(c, H[2]); + ADDTO(d, H[3]); + ADDTO(e, H[4]); + ADDTO(f, H[5]); + ADDTO(g, H[6]); + ADDTO(h, H[7]); + } +} + +void +SHA512_Update(SHA512Context *ctx, const unsigned char *input, + unsigned int inputLen) +{ + unsigned int inBuf; + if (!inputLen) + return; + +#if defined(HAVE_LONG_LONG) + inBuf = (unsigned int)ctx->sizeLo & 0x7f; + /* Add inputLen into the count of bytes processed, before processing */ + ctx->sizeLo += inputLen; +#else + inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f; + ctx->sizeLo.lo += inputLen; + if (ctx->sizeLo.lo < inputLen) + ctx->sizeLo.hi++; +#endif + + /* if data already in buffer, attemp to fill rest of buffer */ + if (inBuf) { + unsigned int todo = SHA512_BLOCK_LENGTH - inBuf; + if (inputLen < todo) + todo = inputLen; + memcpy(B + inBuf, input, todo); + input += todo; + inputLen -= todo; + if (inBuf + todo == SHA512_BLOCK_LENGTH) + SHA512_Compress(ctx); + } + + /* if enough data to fill one or more whole buffers, process them. */ + while (inputLen >= SHA512_BLOCK_LENGTH) { + memcpy(B, input, SHA512_BLOCK_LENGTH); + input += SHA512_BLOCK_LENGTH; + inputLen -= SHA512_BLOCK_LENGTH; + SHA512_Compress(ctx); + } + /* if data left over, fill it into buffer */ + if (inputLen) + memcpy(B, input, inputLen); +} + +void +SHA512_End(SHA512Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ +#if defined(HAVE_LONG_LONG) + unsigned int inBuf = (unsigned int)ctx->sizeLo & 0x7f; +#else + unsigned int inBuf = (unsigned int)ctx->sizeLo.lo & 0x7f; +#endif + unsigned int padLen = (inBuf < 112) ? (112 - inBuf) : (112 + 128 - inBuf); + PRUint64 lo; + LL_SHL(lo, ctx->sizeLo, 3); + + SHA512_Update(ctx, pad, padLen); + +#if defined(HAVE_LONG_LONG) + W[14] = 0; +#else + W[14].lo = 0; + W[14].hi = 0; +#endif + + W[15] = lo; +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP8(W[15]); +#endif + SHA512_Compress(ctx); + +/* now output the answer */ +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP8(H[0]); + BYTESWAP8(H[1]); + BYTESWAP8(H[2]); + BYTESWAP8(H[3]); + BYTESWAP8(H[4]); + BYTESWAP8(H[5]); + BYTESWAP8(H[6]); + BYTESWAP8(H[7]); +#endif + padLen = PR_MIN(SHA512_LENGTH, maxDigestLen); + memcpy(digest, H, padLen); + if (digestLen) + *digestLen = padLen; +} + +void +SHA512_EndRaw(SHA512Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + PRUint64 h[8]; + unsigned int len; + + memcpy(h, ctx->h, sizeof(h)); + +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP8(h[0]); + BYTESWAP8(h[1]); + BYTESWAP8(h[2]); + BYTESWAP8(h[3]); + BYTESWAP8(h[4]); + BYTESWAP8(h[5]); + BYTESWAP8(h[6]); + BYTESWAP8(h[7]); +#endif + len = PR_MIN(SHA512_LENGTH, maxDigestLen); + memcpy(digest, h, len); + if (digestLen) + *digestLen = len; +} + +SECStatus +SHA512_HashBuf(unsigned char *dest, const unsigned char *src, + PRUint32 src_length) +{ + SHA512Context ctx; + unsigned int outLen; + + SHA512_Begin(&ctx); + SHA512_Update(&ctx, src, src_length); + SHA512_End(&ctx, dest, &outLen, SHA512_LENGTH); + memset(&ctx, 0, sizeof ctx); + + return SECSuccess; +} + +SECStatus +SHA512_Hash(unsigned char *dest, const char *src) +{ + return SHA512_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); +} + +void +SHA512_TraceState(SHA512Context *ctx) +{ +} + +unsigned int +SHA512_FlattenSize(SHA512Context *ctx) +{ + return sizeof *ctx; +} + +SECStatus +SHA512_Flatten(SHA512Context *ctx, unsigned char *space) +{ + PORT_Memcpy(space, ctx, sizeof *ctx); + return SECSuccess; +} + +SHA512Context * +SHA512_Resurrect(unsigned char *space, void *arg) +{ + SHA512Context *ctx = SHA512_NewContext(); + if (ctx) + PORT_Memcpy(ctx, space, sizeof *ctx); + return ctx; +} + +void +SHA512_Clone(SHA512Context *dest, SHA512Context *src) +{ + memcpy(dest, src, sizeof *dest); +} + +/* ======================================================================= */ +/* SHA384 uses a SHA512Context as the real context. +** The only differences between SHA384 an SHA512 are: +** a) the intialization values for the context, and +** b) the number of bytes of data produced as output. +*/ + +/* SHA-384 initial hash values */ +static const PRUint64 H384[8] = { +#if PR_BYTES_PER_LONG == 8 + 0xcbbb9d5dc1059ed8UL, 0x629a292a367cd507UL, + 0x9159015a3070dd17UL, 0x152fecd8f70e5939UL, + 0x67332667ffc00b31UL, 0x8eb44a8768581511UL, + 0xdb0c2e0d64f98fa7UL, 0x47b5481dbefa4fa4UL +#else + ULLC(cbbb9d5d, c1059ed8), ULLC(629a292a, 367cd507), + ULLC(9159015a, 3070dd17), ULLC(152fecd8, f70e5939), + ULLC(67332667, ffc00b31), ULLC(8eb44a87, 68581511), + ULLC(db0c2e0d, 64f98fa7), ULLC(47b5481d, befa4fa4) +#endif +}; + +SHA384Context * +SHA384_NewContext(void) +{ + return SHA512_NewContext(); +} + +void +SHA384_DestroyContext(SHA384Context *ctx, PRBool freeit) +{ + SHA512_DestroyContext(ctx, freeit); +} + +void +SHA384_Begin(SHA384Context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + memcpy(H, H384, sizeof H384); +} + +void +SHA384_Update(SHA384Context *ctx, const unsigned char *input, + unsigned int inputLen) +{ + SHA512_Update(ctx, input, inputLen); +} + +void +SHA384_End(SHA384Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH); + SHA512_End(ctx, digest, digestLen, maxLen); +} + +void +SHA384_EndRaw(SHA384Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + unsigned int maxLen = SHA_MIN(maxDigestLen, SHA384_LENGTH); + SHA512_EndRaw(ctx, digest, digestLen, maxLen); +} + +SECStatus +SHA384_HashBuf(unsigned char *dest, const unsigned char *src, + PRUint32 src_length) +{ + SHA512Context ctx; + unsigned int outLen; + + SHA384_Begin(&ctx); + SHA512_Update(&ctx, src, src_length); + SHA512_End(&ctx, dest, &outLen, SHA384_LENGTH); + memset(&ctx, 0, sizeof ctx); + + return SECSuccess; +} + +SECStatus +SHA384_Hash(unsigned char *dest, const char *src) +{ + return SHA384_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); +} + +void +SHA384_TraceState(SHA384Context *ctx) +{ +} + +unsigned int +SHA384_FlattenSize(SHA384Context *ctx) +{ + return sizeof(SHA384Context); +} + +SECStatus +SHA384_Flatten(SHA384Context *ctx, unsigned char *space) +{ + return SHA512_Flatten(ctx, space); +} + +SHA384Context * +SHA384_Resurrect(unsigned char *space, void *arg) +{ + return SHA512_Resurrect(space, arg); +} + +void +SHA384_Clone(SHA384Context *dest, SHA384Context *src) +{ + memcpy(dest, src, sizeof *dest); +} + +/* ======================================================================= */ +#ifdef SELFTEST +#include <stdio.h> + +static const char abc[] = { "abc" }; +static const char abcdbc[] = { + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +}; +static const char abcdef[] = { + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +}; + +void +dumpHash32(const unsigned char *buf, unsigned int bufLen) +{ + unsigned int i; + for (i = 0; i < bufLen; i += 4) { + printf(" %02x%02x%02x%02x", buf[i], buf[i + 1], buf[i + 2], buf[i + 3]); + } + printf("\n"); +} + +void +test256(void) +{ + unsigned char outBuf[SHA256_LENGTH]; + + printf("SHA256, input = %s\n", abc); + SHA256_Hash(outBuf, abc); + dumpHash32(outBuf, sizeof outBuf); + + printf("SHA256, input = %s\n", abcdbc); + SHA256_Hash(outBuf, abcdbc); + dumpHash32(outBuf, sizeof outBuf); +} + +void +test224(void) +{ + SHA224Context ctx; + unsigned char a1000times[1000]; + unsigned int outLen; + unsigned char outBuf[SHA224_LENGTH]; + int i; + + /* Test Vector 1 */ + printf("SHA224, input = %s\n", abc); + SHA224_Hash(outBuf, abc); + dumpHash32(outBuf, sizeof outBuf); + + /* Test Vector 2 */ + printf("SHA224, input = %s\n", abcdbc); + SHA224_Hash(outBuf, abcdbc); + dumpHash32(outBuf, sizeof outBuf); + + /* Test Vector 3 */ + + /* to hash one million 'a's perform 1000 + * sha224 updates on a buffer with 1000 'a's + */ + memset(a1000times, 'a', 1000); + printf("SHA224, input = %s\n", "a one million times"); + SHA224_Begin(&ctx); + for (i = 0; i < 1000; i++) + SHA224_Update(&ctx, a1000times, 1000); + SHA224_End(&ctx, outBuf, &outLen, SHA224_LENGTH); + dumpHash32(outBuf, sizeof outBuf); +} + +void +dumpHash64(const unsigned char *buf, unsigned int bufLen) +{ + unsigned int i; + for (i = 0; i < bufLen; i += 8) { + if (i % 32 == 0) + printf("\n"); + printf(" %02x%02x%02x%02x%02x%02x%02x%02x", + buf[i], buf[i + 1], buf[i + 2], buf[i + 3], + buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); + } + printf("\n"); +} + +void +test512(void) +{ + unsigned char outBuf[SHA512_LENGTH]; + + printf("SHA512, input = %s\n", abc); + SHA512_Hash(outBuf, abc); + dumpHash64(outBuf, sizeof outBuf); + + printf("SHA512, input = %s\n", abcdef); + SHA512_Hash(outBuf, abcdef); + dumpHash64(outBuf, sizeof outBuf); +} + +void +time512(void) +{ + unsigned char outBuf[SHA512_LENGTH]; + + SHA512_Hash(outBuf, abc); + SHA512_Hash(outBuf, abcdef); +} + +void +test384(void) +{ + unsigned char outBuf[SHA384_LENGTH]; + + printf("SHA384, input = %s\n", abc); + SHA384_Hash(outBuf, abc); + dumpHash64(outBuf, sizeof outBuf); + + printf("SHA384, input = %s\n", abcdef); + SHA384_Hash(outBuf, abcdef); + dumpHash64(outBuf, sizeof outBuf); +} + +int +main(int argc, char *argv[], char *envp[]) +{ + int i = 1; + if (argc > 1) { + i = atoi(argv[1]); + } + if (i < 2) { + test224(); + test256(); + test384(); + test512(); + } else { + while (i-- > 0) { + time512(); + } + printf("done\n"); + } + return 0; +} + +void * +PORT_Alloc(size_t len) +{ + return malloc(len); +} +void +PORT_Free(void *ptr) +{ + free(ptr); +} +void +PORT_ZFree(void *ptr, size_t len) +{ + memset(ptr, 0, len); + free(ptr); +} +#endif |