pcompress/crypto/sha2/sha256.c

274 lines
6.9 KiB
C
Raw Permalink Normal View History

/*-
* Copyright (c) 2001-2003 Allan Saddi <allan@saddi.com>
* Copyright (c) 2012 Moinak Ghosh moinakg <at1> gm0il <dot> com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Define WORDS_BIGENDIAN if compiling on a big-endian architecture.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#if HAVE_INTTYPES_H
# include <inttypes.h>
#else
# if HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#include <pthread.h>
#include <string.h>
#include <utils.h>
#include <sha256.h>
#ifdef WORDS_BIGENDIAN
#define BYTESWAP(x) (x)
#define BYTESWAP64(x) (x)
#else /* WORDS_BIGENDIAN */
#define BYTESWAP(x) htonl(x)
#define BYTESWAP64(x) htonll(x)
#endif /* WORDS_BIGENDIAN */
typedef void (*update_func_ptr)(void *input_data, uint32_t digest[8], uint64_t num_blks);
static uint8_t padding[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const uint32_t iv256[SHA256_HASH_WORDS] = {
0x6a09e667L,
0xbb67ae85L,
0x3c6ef372L,
0xa54ff53aL,
0x510e527fL,
0x9b05688cL,
0x1f83d9abL,
0x5be0cd19L
};
static update_func_ptr sha_update_func;
int
APS_NAMESPACE(Init_SHA) (processor_info_t *pc)
{
if (pc->proc_type == PROC_X64_INTEL || pc->proc_type == PROC_X64_AMD) {
if (pc->avx_level > 0) {
sha_update_func = sha256_avx;
} else if (pc->sse_level >= 4) {
sha_update_func = sha256_sse4;
} else {
return (1);
}
return (0);
}
return (1);
}
static void
_init (SHA256_Context *sc, const uint32_t iv[SHA256_HASH_WORDS])
{
int i;
/*
* SHA256_HASH_WORDS is 8, must be 8, cannot be anything but 8!
* So we unroll a loop here.
*/
sc->hash[0] = iv[0];
sc->hash[1] = iv[1];
sc->hash[2] = iv[2];
sc->hash[3] = iv[3];
sc->hash[4] = iv[4];
sc->hash[5] = iv[5];
sc->hash[6] = iv[6];
sc->hash[7] = iv[7];
sc->totalLength = 0LL;
sc->bufferLength = 0L;
}
void
APS_NAMESPACE(SHA256_Init) (SHA256_Context *sc)
{
_init (sc, iv256);
}
void
APS_NAMESPACE(SHA256_Update) (SHA256_Context *sc, const void *vdata, size_t len)
{
const uint8_t *data = vdata;
uint32_t bufferBytesLeft;
size_t bytesToCopy;
int rem;
if (sc->bufferLength) {
do {
bufferBytesLeft = 64L - sc->bufferLength;
bytesToCopy = bufferBytesLeft;
if (bytesToCopy > len)
bytesToCopy = len;
memcpy (&sc->buffer.bytes[sc->bufferLength], data, bytesToCopy);
sc->totalLength += bytesToCopy * 8L;
sc->bufferLength += bytesToCopy;
data += bytesToCopy;
len -= bytesToCopy;
if (sc->bufferLength == 64L) {
sc->blocks = 1;
sha_update_func(sc->buffer.words, sc->hash, sc->blocks);
sc->bufferLength = 0L;
} else {
return;
}
} while (len > 0 && len <= 64L);
if (!len) return;
}
sc->blocks = len >> 6;
rem = len - (sc->blocks << 6);
len = sc->blocks << 6;
sc->totalLength += rem * 8L;
if (len) {
sc->totalLength += len * 8L;
sha_update_func((uint32_t *)data, sc->hash, sc->blocks);
}
if (rem) {
memcpy (&sc->buffer.bytes[0], data + len, rem);
sc->bufferLength = rem;
}
}
static void
_final (SHA256_Context *sc, uint8_t *hash, int hashWords)
{
uint32_t bytesToPad;
uint64_t lengthPad;
int i;
bytesToPad = 120L - sc->bufferLength;
if (bytesToPad > 64L)
bytesToPad -= 64L;
lengthPad = BYTESWAP64(sc->totalLength);
APS_NAMESPACE(SHA256_Update) (sc, padding, bytesToPad);
APS_NAMESPACE(SHA256_Update) (sc, &lengthPad, 8L);
if (hash) {
for (i = 0; i < hashWords; i++) {
hash[0] = (uint8_t) (sc->hash[i] >> 24);
hash[1] = (uint8_t) (sc->hash[i] >> 16);
hash[2] = (uint8_t) (sc->hash[i] >> 8);
hash[3] = (uint8_t) sc->hash[i];
hash += 4;
}
}
}
void
APS_NAMESPACE(SHA256_Final) (SHA256_Context *sc, uint8_t hash[SHA256_HASH_SIZE])
{
_final (sc, hash, SHA256_HASH_WORDS);
}
/* Initialize an HMAC-SHA256 operation with the given key. */
void
APS_NAMESPACE(HMAC_SHA256_Init) (HMAC_SHA256_Context * ctx, const void * _K, size_t Klen)
{
unsigned char pad[64];
unsigned char khash[32];
const unsigned char * K = _K;
size_t i;
/* If Klen > 64, the key is really SHA256(K). */
if (Klen > 64) {
APS_NAMESPACE(SHA256_Init)(&ctx->ictx);
APS_NAMESPACE(SHA256_Update)(&ctx->ictx, K, Klen);
APS_NAMESPACE(SHA256_Final)(&ctx->ictx, khash);
K = khash;
Klen = 32;
}
/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
APS_NAMESPACE(SHA256_Init)(&ctx->ictx);
memset(pad, 0x36, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
APS_NAMESPACE(SHA256_Update)(&ctx->ictx, pad, 64);
/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
APS_NAMESPACE(SHA256_Init)(&ctx->octx);
memset(pad, 0x5c, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
APS_NAMESPACE(SHA256_Update)(&ctx->octx, pad, 64);
/* Clean the stack. */
memset(khash, 0, 32);
}
/* Add bytes to the HMAC-SHA256 operation. */
void
APS_NAMESPACE(HMAC_SHA256_Update) (HMAC_SHA256_Context * ctx, const void *in, size_t len)
{
/* Feed data to the inner SHA256 operation. */
APS_NAMESPACE(SHA256_Update)(&ctx->ictx, in, len);
}
/* Finish an HMAC-SHA256 operation. */
void
APS_NAMESPACE(HMAC_SHA256_Final) (HMAC_SHA256_Context * ctx, unsigned char digest[32])
{
unsigned char ihash[32];
/* Finish the inner SHA256 operation. */
APS_NAMESPACE(SHA256_Final)(&ctx->ictx, ihash);
/* Feed the inner hash to the outer SHA256 operation. */
APS_NAMESPACE(SHA256_Update)(&ctx->octx, ihash, 32);
/* Finish the outer SHA256 operation. */
APS_NAMESPACE(SHA256_Final)(&ctx->octx, digest);
/* Clean the stack. */
memset(ihash, 0, 32);
}