gecko/ipc/app/sha256.c

492 lines
11 KiB
C
Raw Normal View History

/* 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/. */
// Stripped down version of security/nss/lib/freebl/sha512.c
// and related headers.
#include "sha256.h"
#include "string.h"
#include "prcpucfg.h"
#if defined(NSS_X86) || defined(SHA_NO_LONG_LONG)
#define NOUNROLL512 1
#undef HAVE_LONG_LONG
#endif
#define SHA256_BLOCK_LENGTH 64 /* bytes */
typedef enum _SECStatus {
SECWouldBlock = -2,
SECFailure = -1,
SECSuccess = 0
} SECStatus;
/* ============= 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 (_MSC_VER >= 1300)
#include <stdlib.h>
#pragma intrinsic(_byteswap_ulong)
#define SHA_HTONL(x) _byteswap_ulong(x)
#define BYTESWAP4(x) x = SHA_HTONL(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)
#define BYTESWAP4(x) x = SHA_HTONL(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)
#define BYTESWAP4(x) x = SHA_HTONL(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)
#define BYTESWAP4(x) x = SHA_HTONL(x)
#else
#define SWAP4MASK 0x00FF00FF
#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \
((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK))
#define BYTESWAP4(x) x = SHA_HTONL(x)
#endif
#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) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3))
#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10))
void
SHA256_Begin(SHA256Context *ctx)
{
memset(ctx, 0, sizeof *ctx);
memcpy(H, H256, sizeof H256);
}
static void
SHA256_Compress(SHA256Context *ctx)
{
{
register PRUint32 t1, t2;
#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;
#ifdef SWAP4MASK
PRUint32 t1;
#endif
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;
#ifdef SWAP4MASK
PRUint32 t1;
#endif
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;
}