cryb-to/lib/digest/sha256.c
Dag-Erling Smørgrav b0ff5af2ba Clean up headers and typedefs.
Fix context length in the algorithm descriptors.
Expose the block length and include it in the algorithm descriptors.
Complete the list of available digest algorithms.
2014-07-10 18:09:47 +00:00

477 lines
12 KiB
C

/*-
* Copyright (c) 2005-2013 Colin Percival
* 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.
*
* $Cryb$
*/
#include "cryb/impl.h"
#ifdef HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#endif
#ifdef HAVE_ENDIAN_H
#define _BSD_SOURCE
#include <endian.h>
#endif
#include <stdint.h>
#include <string.h>
#include <cryb/sha256.h>
/*
* Encode a length len/4 vector of (uint32_t) into a length len vector of
* (uint8_t) in big-endian form. Assumes len is a multiple of 4.
*/
static void
be32enc_vect(uint8_t *dst, const uint32_t *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
be32enc(dst + i * 4, src[i]);
}
/*
* Decode a big-endian length len vector of (uint8_t) into a length
* len/4 vector of (uint32_t). Assumes len is a multiple of 4.
*/
static void
be32dec_vect(uint32_t *dst, const uint8_t *src, size_t len)
{
size_t i;
for (i = 0; i < len / 4; i++)
dst[i] = be32dec(src + i * 4);
}
/* Elementary functions used by SHA256 */
#define Ch(x, y, z) ((x & (y ^ z)) ^ z)
#define Maj(x, y, z) ((x & (y | z)) | (y & z))
#define SHR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))
/* SHA256 round function */
#define RND(a, b, c, d, e, f, g, h, k) \
t0 = h + S1(e) + Ch(e, f, g) + k; \
t1 = S0(a) + Maj(a, b, c); \
d += t0; \
h = t0 + t1;
/* Adjusted round function for rotating state */
#define RNDr(S, W, i, k) \
RND(S[(64 - i) % 8], S[(65 - i) % 8], \
S[(66 - i) % 8], S[(67 - i) % 8], \
S[(68 - i) % 8], S[(69 - i) % 8], \
S[(70 - i) % 8], S[(71 - i) % 8], \
W[i] + k)
/*
* SHA256 block compression function. The 256-bit state is transformed via
* the 512-bit input block to produce a new state.
*/
static void
sha256_Transform(uint32_t * state, const uint8_t block[64])
{
uint32_t W[64];
uint32_t S[8];
uint32_t t0, t1;
int i;
/* 1. Prepare message schedule W. */
be32dec_vect(W, block, 64);
for (i = 16; i < 64; i++)
W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16];
/* 2. Initialize working variables. */
memcpy(S, state, 32);
/* 3. Mix. */
RNDr(S, W, 0, 0x428a2f98);
RNDr(S, W, 1, 0x71374491);
RNDr(S, W, 2, 0xb5c0fbcf);
RNDr(S, W, 3, 0xe9b5dba5);
RNDr(S, W, 4, 0x3956c25b);
RNDr(S, W, 5, 0x59f111f1);
RNDr(S, W, 6, 0x923f82a4);
RNDr(S, W, 7, 0xab1c5ed5);
RNDr(S, W, 8, 0xd807aa98);
RNDr(S, W, 9, 0x12835b01);
RNDr(S, W, 10, 0x243185be);
RNDr(S, W, 11, 0x550c7dc3);
RNDr(S, W, 12, 0x72be5d74);
RNDr(S, W, 13, 0x80deb1fe);
RNDr(S, W, 14, 0x9bdc06a7);
RNDr(S, W, 15, 0xc19bf174);
RNDr(S, W, 16, 0xe49b69c1);
RNDr(S, W, 17, 0xefbe4786);
RNDr(S, W, 18, 0x0fc19dc6);
RNDr(S, W, 19, 0x240ca1cc);
RNDr(S, W, 20, 0x2de92c6f);
RNDr(S, W, 21, 0x4a7484aa);
RNDr(S, W, 22, 0x5cb0a9dc);
RNDr(S, W, 23, 0x76f988da);
RNDr(S, W, 24, 0x983e5152);
RNDr(S, W, 25, 0xa831c66d);
RNDr(S, W, 26, 0xb00327c8);
RNDr(S, W, 27, 0xbf597fc7);
RNDr(S, W, 28, 0xc6e00bf3);
RNDr(S, W, 29, 0xd5a79147);
RNDr(S, W, 30, 0x06ca6351);
RNDr(S, W, 31, 0x14292967);
RNDr(S, W, 32, 0x27b70a85);
RNDr(S, W, 33, 0x2e1b2138);
RNDr(S, W, 34, 0x4d2c6dfc);
RNDr(S, W, 35, 0x53380d13);
RNDr(S, W, 36, 0x650a7354);
RNDr(S, W, 37, 0x766a0abb);
RNDr(S, W, 38, 0x81c2c92e);
RNDr(S, W, 39, 0x92722c85);
RNDr(S, W, 40, 0xa2bfe8a1);
RNDr(S, W, 41, 0xa81a664b);
RNDr(S, W, 42, 0xc24b8b70);
RNDr(S, W, 43, 0xc76c51a3);
RNDr(S, W, 44, 0xd192e819);
RNDr(S, W, 45, 0xd6990624);
RNDr(S, W, 46, 0xf40e3585);
RNDr(S, W, 47, 0x106aa070);
RNDr(S, W, 48, 0x19a4c116);
RNDr(S, W, 49, 0x1e376c08);
RNDr(S, W, 50, 0x2748774c);
RNDr(S, W, 51, 0x34b0bcb5);
RNDr(S, W, 52, 0x391c0cb3);
RNDr(S, W, 53, 0x4ed8aa4a);
RNDr(S, W, 54, 0x5b9cca4f);
RNDr(S, W, 55, 0x682e6ff3);
RNDr(S, W, 56, 0x748f82ee);
RNDr(S, W, 57, 0x78a5636f);
RNDr(S, W, 58, 0x84c87814);
RNDr(S, W, 59, 0x8cc70208);
RNDr(S, W, 60, 0x90befffa);
RNDr(S, W, 61, 0xa4506ceb);
RNDr(S, W, 62, 0xbef9a3f7);
RNDr(S, W, 63, 0xc67178f2);
/* 4. Mix local working variables into global state. */
for (i = 0; i < 8; i++)
state[i] += S[i];
/* Clean the stack. */
memset(W, 0, 256);
memset(S, 0, 32);
t0 = t1 = 0;
}
static uint8_t PAD[64] = {
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
};
/* Add padding and terminating bit-count. */
static void
sha256_pad(sha256_ctx * ctx)
{
uint8_t len[8];
uint32_t r, plen;
/*
* Convert length to a vector of bytes -- we do this now rather
* than later because the length will change after we pad.
*/
be64enc(len, ctx->count);
/* Add 1--64 bytes so that the resulting length is 56 mod 64. */
r = (ctx->count >> 3) & 0x3f;
plen = (r < 56) ? (56 - r) : (120 - r);
sha256_update(ctx, PAD, (size_t)plen);
/* Add the terminating bit-count. */
sha256_update(ctx, len, 8);
}
/**
* sha256_init(ctx):
* Initialize the SHA256 context ${ctx}.
*/
void
sha256_init(sha256_ctx * ctx)
{
/* Zero bits processed so far. */
ctx->count = 0;
/* Magic initialization constants. */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
/**
* sha256_update(ctx, in, len):
* Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
*/
void
sha256_update(sha256_ctx * ctx, const void *in, size_t len)
{
uint32_t r;
const uint8_t *src = in;
/* Return immediately if we have nothing to do. */
if (len == 0)
return;
/* Number of bytes left in the buffer from previous updates. */
r = (ctx->count >> 3) & 0x3f;
/* Update number of bits. */
ctx->count += (uint64_t)(len) << 3;
/* Handle the case where we don't need to perform any transforms. */
if (len < 64 - r) {
memcpy(&ctx->buf[r], src, len);
return;
}
/* Finish the current block. */
memcpy(&ctx->buf[r], src, 64 - r);
sha256_Transform(ctx->state, ctx->buf);
src += 64 - r;
len -= 64 - r;
/* Perform complete blocks. */
while (len >= 64) {
sha256_Transform(ctx->state, src);
src += 64;
len -= 64;
}
/* Copy left over data into buffer. */
memcpy(ctx->buf, src, len);
}
/**
* sha256_final(ctx, digest):
* Output the SHA256 hash of the data input to the context ${ctx} into the
* buffer ${digest}.
*/
void
sha256_final(sha256_ctx * ctx, uint8_t digest[SHA256_DIGEST_LEN])
{
/* Add padding. */
sha256_pad(ctx);
/* Write the hash. */
be32enc_vect(digest, ctx->state, SHA256_DIGEST_LEN);
/* Clear the context state. */
memset((void *)ctx, 0, sizeof(*ctx));
}
/**
* sha256_complete(in, len, digest):
* Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}.
*/
void
sha256_complete(const void * in, size_t len, uint8_t digest[SHA256_DIGEST_LEN])
{
sha256_ctx ctx;
sha256_init(&ctx);
sha256_update(&ctx, in, len);
sha256_final(&ctx, digest);
}
/**
* hmac_sha256_init(ctx, K, Klen):
* Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
* ${K}.
*/
void
hmac_sha256_init(hmac_sha256_ctx * ctx, const void * _K, size_t Klen)
{
uint8_t pad[64];
uint8_t khash[SHA256_DIGEST_LEN];
const uint8_t * K = _K;
size_t i;
/* If Klen > 64, the key is really SHA256(K). */
if (Klen > 64) {
sha256_init(&ctx->ictx);
sha256_update(&ctx->ictx, K, Klen);
sha256_final(&ctx->ictx, khash);
K = khash;
Klen = sizeof khash;
}
/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
sha256_init(&ctx->ictx);
memset(pad, 0x36, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
sha256_update(&ctx->ictx, pad, 64);
/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
sha256_init(&ctx->octx);
memset(pad, 0x5c, 64);
for (i = 0; i < Klen; i++)
pad[i] ^= K[i];
sha256_update(&ctx->octx, pad, 64);
/* Clean the stack. */
memset(khash, 0, sizeof khash);
memset(pad, 0, 64);
}
/**
* hmac_sha256_update(ctx, in, len):
* Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
*/
void
hmac_sha256_update(hmac_sha256_ctx * ctx, const void *in, size_t len)
{
/* Feed data to the inner SHA256 operation. */
sha256_update(&ctx->ictx, in, len);
}
/**
* hmac_sha256_final(ctx, digest):
* Output the HMAC-SHA256 of the data input to the context ${ctx} into the
* buffer ${digest}.
*/
void
hmac_sha256_final(hmac_sha256_ctx * ctx, uint8_t digest[SHA256_DIGEST_LEN])
{
uint8_t ihash[SHA256_DIGEST_LEN];
/* Finish the inner SHA256 operation. */
sha256_final(&ctx->ictx, ihash);
/* Feed the inner hash to the outer SHA256 operation. */
sha256_update(&ctx->octx, ihash, sizeof ihash);
/* Finish the outer SHA256 operation. */
sha256_final(&ctx->octx, digest);
/* Clean the stack. */
memset(ihash, 0, sizeof ihash);
}
/**
* hmac_sha256_complete(K, Klen, in, len, digest):
* Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
* length ${Klen}, and write the result to ${digest}.
*/
void
hmac_sha256_complete(const void * K, size_t Klen, const void * in, size_t len,
uint8_t digest[SHA256_DIGEST_LEN])
{
hmac_sha256_ctx ctx;
hmac_sha256_init(&ctx, K, Klen);
hmac_sha256_update(&ctx, in, len);
hmac_sha256_final(&ctx, digest);
}
/**
* PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
* Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
* write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
*/
void
pbkdf2_sha256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
{
hmac_sha256_ctx PShctx, hctx;
size_t i;
uint8_t ivec[4];
uint8_t U[SHA256_DIGEST_LEN];
uint8_t T[SHA256_DIGEST_LEN];
uint64_t j;
unsigned int k;
size_t clen;
/* Compute HMAC state after processing P and S. */
hmac_sha256_init(&PShctx, passwd, passwdlen);
hmac_sha256_update(&PShctx, salt, saltlen);
/* Iterate through the blocks. */
for (i = 0; i * 32 < dkLen; i++) {
/* Generate INT(i + 1). */
be32enc(ivec, (uint32_t)(i + 1));
/* Compute U_1 = PRF(P, S || INT(i)). */
memcpy(&hctx, &PShctx, sizeof(hmac_sha256_ctx));
hmac_sha256_update(&hctx, ivec, 4);
hmac_sha256_final(&hctx, U);
/* T_i = U_1 ... */
memcpy(T, U, sizeof T);
for (j = 2; j <= c; j++) {
/* Compute U_j. */
hmac_sha256_init(&hctx, passwd, passwdlen);
hmac_sha256_update(&hctx, U, 32);
hmac_sha256_final(&hctx, U);
/* ... xor U_j ... */
for (k = 0; k < sizeof T; k++)
T[k] ^= U[k];
}
/* Copy as many bytes as necessary into buf. */
clen = dkLen - i * 32;
if (clen > 32)
clen = 32;
memcpy(&buf[i * 32], T, clen);
}
/* Clean PShctx, since we never called _final on it. */
memset(&PShctx, 0, sizeof(hmac_sha256_ctx));
}
digest_algorithm sha256_digest = {
.name = "sha256",
.contextlen = sizeof sha256_digest,
.blocklen = SHA256_BLOCK_LEN,
.digestlen = SHA256_DIGEST_LEN,
.init = (digest_init_func)sha256_init,
.update = (digest_update_func)sha256_update,
.final = (digest_final_func)sha256_final,
.complete = (digest_complete_func)sha256_complete,
};