0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-05 08:31:53 +00:00

Add SHA512 and SHA384 hash library and unit tests

This commit is contained in:
Pavel Tvrdík 2015-04-28 15:02:37 +02:00
parent 5a5e825213
commit 5355407915
7 changed files with 703 additions and 21 deletions

View File

@ -32,6 +32,7 @@ sha256_init(sha256_context *ctx)
ctx->nblocks = 0; ctx->nblocks = 0;
ctx->nblocks_high = 0; ctx->nblocks_high = 0;
ctx->count = 0; ctx->count = 0;
ctx->blocksize = 64;
} }
void void
@ -49,6 +50,7 @@ sha224_init(sha224_context *ctx)
ctx->nblocks = 0; ctx->nblocks = 0;
ctx->nblocks_high = 0; ctx->nblocks_high = 0;
ctx->count = 0; ctx->count = 0;
ctx->blocksize = 64;
} }
/* (4.2) same as SHA-1's F1. */ /* (4.2) same as SHA-1's F1. */
@ -110,7 +112,7 @@ sum1(u32 x)
32-bit-words. See FIPS 180-2 for details. 32-bit-words. See FIPS 180-2 for details.
*/ */
static unsigned int static unsigned int
transform(sha256_context *ctx, const unsigned char *data) sha256_transform_block(sha256_context *ctx, const unsigned char *data)
{ {
static const u32 K[64] = { static const u32 K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
@ -217,7 +219,7 @@ sha256_transform(void *ctx, const unsigned char *data, size_t nblks)
do do
{ {
burn = transform(hd, data); burn = sha256_transform_block(hd, data);
data += 64; data += 64;
} }
while (--nblks); while (--nblks);
@ -234,8 +236,7 @@ sha256_transform(void *ctx, const unsigned char *data, size_t nblks)
void void
sha256_update(sha256_context *ctx, const byte *in_buf, size_t in_len) sha256_update(sha256_context *ctx, const byte *in_buf, size_t in_len)
{ {
unsigned int stack_burn = 0; const unsigned int blocksize = ctx->blocksize;
const unsigned int blocksize = 64;
size_t inblocks; size_t inblocks;
if (sizeof(ctx->buf) < blocksize) if (sizeof(ctx->buf) < blocksize)
@ -243,8 +244,7 @@ sha256_update(sha256_context *ctx, const byte *in_buf, size_t in_len)
if (ctx->count == blocksize) /* Flush the buffer. */ if (ctx->count == blocksize) /* Flush the buffer. */
{ {
stack_burn = sha256_transform(ctx, ctx->buf, 1); sha256_transform(ctx, ctx->buf, 1);
stack_burn = 0;
ctx->count = 0; ctx->count = 0;
if (!++ctx->nblocks) if (!++ctx->nblocks)
ctx->nblocks_high++; ctx->nblocks_high++;
@ -264,7 +264,7 @@ sha256_update(sha256_context *ctx, const byte *in_buf, size_t in_len)
if (in_len >= blocksize) if (in_len >= blocksize)
{ {
inblocks = in_len / blocksize; inblocks = in_len / blocksize;
stack_burn = sha256_transform(ctx, in_buf, inblocks); sha256_transform(ctx, in_buf, inblocks);
ctx->count = 0; ctx->count = 0;
ctx->nblocks_high += (ctx->nblocks + inblocks < inblocks); ctx->nblocks_high += (ctx->nblocks + inblocks < inblocks);
ctx->nblocks += inblocks; ctx->nblocks += inblocks;
@ -285,7 +285,6 @@ sha256_final(sha256_context *ctx)
{ {
u32 t, th, msb, lsb; u32 t, th, msb, lsb;
byte *p; byte *p;
unsigned int burn;
sha256_update(ctx, NULL, 0); /* flush */; sha256_update(ctx, NULL, 0); /* flush */;
@ -325,7 +324,7 @@ sha256_final(sha256_context *ctx)
/* append the 64 bit count */ /* append the 64 bit count */
put_u32(ctx->buf + 56, msb); put_u32(ctx->buf + 56, msb);
put_u32(ctx->buf + 60, lsb); put_u32(ctx->buf + 60, lsb);
burn = sha256_transform(ctx, ctx->buf, 1); sha256_transform(ctx, ctx->buf, 1);
p = ctx->buf; p = ctx->buf;
@ -443,7 +442,7 @@ sha256_hmac_update(sha256_hmac_context *ctx, const void *buffer, size_t length)
the length of the digest will be stored at that address. The the length of the digest will be stored at that address. The
returned value is valid as long as the context exists. On error returned value is valid as long as the context exists. On error
NULL is returned. */ NULL is returned. */
const byte * byte *
sha256_hmac_final(sha256_hmac_context *ctx) sha256_hmac_final(sha256_hmac_context *ctx)
{ {
sha256_final(&ctx->ctx); sha256_final(&ctx->ctx);

View File

@ -20,10 +20,11 @@
typedef struct { typedef struct {
u32 h0,h1,h2,h3,h4,h5,h6,h7; u32 h0,h1,h2,h3,h4,h5,h6,h7;
byte buf[64]; byte buf[128];
u32 nblocks; u32 nblocks;
u32 nblocks_high; u32 nblocks_high;
int count; int count;
u32 blocksize;
} sha256_context; } sha256_context;
typedef sha256_context sha224_context; typedef sha256_context sha224_context;
@ -63,8 +64,8 @@ void sha224_hmac_update(sha224_hmac_context *ctx, const void *buf, size_t buflen
sha256_hmac_update(ctx, buf, buflen); sha256_hmac_update(ctx, buf, buflen);
} }
const byte *sha256_hmac_final(sha256_hmac_context *ctx); byte *sha256_hmac_final(sha256_hmac_context *ctx);
const byte *sha224_hmac_final(sha224_hmac_context *ctx) byte *sha224_hmac_final(sha224_hmac_context *ctx)
{ {
return sha256_hmac_final(ctx); return sha256_hmac_final(ctx);
} }

View File

@ -165,10 +165,7 @@ get_sha256_hmac(const struct hmac_data_in in, char (*out_hash)[SHA256_HEX_SIZE])
sha256_hmac_init(&ctx, in.key, in.key_len); sha256_hmac_init(&ctx, in.key, in.key_len);
sha256_hmac_update(&ctx, in.data, in.data_len); sha256_hmac_update(&ctx, in.data, in.data_len);
byte *hash_byte = sha256_hmac_final(&ctx); byte *hash_byte = sha256_hmac_final(&ctx);
byte_to_hex((char*)out_hash, hash_byte, SHA256_SIZE);
int i;
for (i = 0; i < SHA256_SIZE; i++)
sprintf(*out_hash + i*2, "%02x", hash_byte[i]);
} }
static void static void
@ -178,10 +175,7 @@ get_sha224_hmac(const struct hmac_data_in in, char (*out_hash)[SHA256_HEX_SIZE])
sha224_hmac_init(&ctx, in.key, in.key_len); sha224_hmac_init(&ctx, in.key, in.key_len);
sha224_hmac_update(&ctx, in.data, in.data_len); sha224_hmac_update(&ctx, in.data, in.data_len);
byte *hash_byte = sha224_hmac_final(&ctx); byte *hash_byte = sha224_hmac_final(&ctx);
byte_to_hex((char*)out_hash, hash_byte, SHA224_HEX_SIZE);
int i;
for (i = 0; i < SHA224_SIZE; i++)
sprintf(*out_hash + i*2, "%02x", hash_byte[i]);
} }

493
lib/sha512.c Normal file
View File

@ -0,0 +1,493 @@
/*
* BIRD -- SHA512 and SHA384 Hash Functions
*
* (c) 2015 CZ.NIC z.s.p.o.
*
* Based on the code from libgcrypt-1.6.0, which is
* (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "lib/sha256.h"
#include "lib/sha256.c" /* REMOVE ME */
#include "lib/sha512.h"
#include "lib/unaligned.h"
#define U64_C(c) (c ## UL) /* Maybe is system dependent */
void
sha512_init(sha512_context *ctx)
{
sha512_state *hd = &ctx->state;
hd->h0 = U64_C(0x6a09e667f3bcc908);
hd->h1 = U64_C(0xbb67ae8584caa73b);
hd->h2 = U64_C(0x3c6ef372fe94f82b);
hd->h3 = U64_C(0xa54ff53a5f1d36f1);
hd->h4 = U64_C(0x510e527fade682d1);
hd->h5 = U64_C(0x9b05688c2b3e6c1f);
hd->h6 = U64_C(0x1f83d9abfb41bd6b);
hd->h7 = U64_C(0x5be0cd19137e2179);
ctx->bctx.nblocks = 0;
ctx->bctx.nblocks_high = 0;
ctx->bctx.count = 0;
ctx->bctx.blocksize = 128;
}
void
sha384_init(sha384_context *ctx)
{
sha512_state *hd = &ctx->state;
hd->h0 = U64_C(0xcbbb9d5dc1059ed8);
hd->h1 = U64_C(0x629a292a367cd507);
hd->h2 = U64_C(0x9159015a3070dd17);
hd->h3 = U64_C(0x152fecd8f70e5939);
hd->h4 = U64_C(0x67332667ffc00b31);
hd->h5 = U64_C(0x8eb44a8768581511);
hd->h6 = U64_C(0xdb0c2e0d64f98fa7);
hd->h7 = U64_C(0x47b5481dbefa4fa4);
ctx->bctx.nblocks = 0;
ctx->bctx.nblocks_high = 0;
ctx->bctx.count = 0;
ctx->bctx.blocksize = 128;
}
void sha512_update(sha512_context *ctx, const byte *in_buf, size_t in_len)
{
sha256_update(&ctx->bctx, in_buf, in_len);
}
static inline u64
ROTR (u64 x, u64 n)
{
return((x >> n) | (x << (64 - n)));
}
static inline u64
Ch(u64 x, u64 y, u64 z)
{
return((x & y) ^ ( ~x & z));
}
static inline u64
Maj(u64 x, u64 y, u64 z)
{
return((x & y) ^ (x & z) ^ (y & z));
}
static inline u64
Sum0 (u64 x)
{
return(ROTR (x, 28) ^ ROTR (x, 34) ^ ROTR (x, 39));
}
static inline u64
Sum1 (u64 x)
{
return(ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41));
}
static const u64 k[] =
{
U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd),
U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc),
U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019),
U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118),
U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe),
U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2),
U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1),
U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694),
U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3),
U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65),
U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483),
U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5),
U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210),
U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4),
U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725),
U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70),
U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926),
U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df),
U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8),
U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b),
U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001),
U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30),
U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910),
U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8),
U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53),
U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8),
U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb),
U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3),
U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60),
U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec),
U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9),
U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b),
U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207),
U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178),
U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6),
U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b),
U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493),
U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c),
U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a),
U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817)
};
/*
* Transform the message W which consists of 16 64-bit-words
*/
static unsigned int
sha512_transform_block(sha512_state *hd, const unsigned char *data)
{
u64 a, b, c, d, e, f, g, h;
u64 w[16];
int t;
/* get values from the chaining vars */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
f = hd->h5;
g = hd->h6;
h = hd->h7;
for ( t = 0; t < 16; t++ )
w[t] = get_u64(data + t * 8);
#define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
#define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
for (t = 0; t < 80 - 16; )
{
u64 t1, t2;
/* Performance on a AMD Athlon(tm) Dual Core Processor 4050e
with gcc 4.3.3 using gcry_md_hash_buffer of each 10000 bytes
initialized to 0,1,2,3...255,0,... and 1000 iterations:
Not unrolled with macros: 440ms
Unrolled with macros: 350ms
Unrolled with inline: 330ms
*/
#if 0 /* Not unrolled. */
t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[t%16];
w[t%16] += S1 (w[(t - 2)%16]) + w[(t - 7)%16] + S0 (w[(t - 15)%16]);
t2 = Sum0 (a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
t++;
#else /* Unrolled to interweave the chain variables. */
t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[0];
w[0] += S1 (w[14]) + w[9] + S0 (w[1]);
t2 = Sum0 (a) + Maj(a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+1] + w[1];
w[1] += S1 (w[15]) + w[10] + S0 (w[2]);
t2 = Sum0 (h) + Maj(h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+2] + w[2];
w[2] += S1 (w[0]) + w[11] + S0 (w[3]);
t2 = Sum0 (g) + Maj(g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+3] + w[3];
w[3] += S1 (w[1]) + w[12] + S0 (w[4]);
t2 = Sum0 (f) + Maj(f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+4] + w[4];
w[4] += S1 (w[2]) + w[13] + S0 (w[5]);
t2 = Sum0 (e) + Maj(e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+5] + w[5];
w[5] += S1 (w[3]) + w[14] + S0 (w[6]);
t2 = Sum0 (d) + Maj(d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+6] + w[6];
w[6] += S1 (w[4]) + w[15] + S0 (w[7]);
t2 = Sum0 (c) + Maj(c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+7] + w[7];
w[7] += S1 (w[5]) + w[0] + S0 (w[8]);
t2 = Sum0 (b) + Maj(b, c, d);
e += t1;
a = t1 + t2;
t1 = h + Sum1 (e) + Ch(e, f, g) + k[t+8] + w[8];
w[8] += S1 (w[6]) + w[1] + S0 (w[9]);
t2 = Sum0 (a) + Maj(a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+9] + w[9];
w[9] += S1 (w[7]) + w[2] + S0 (w[10]);
t2 = Sum0 (h) + Maj(h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+10] + w[10];
w[10] += S1 (w[8]) + w[3] + S0 (w[11]);
t2 = Sum0 (g) + Maj(g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+11] + w[11];
w[11] += S1 (w[9]) + w[4] + S0 (w[12]);
t2 = Sum0 (f) + Maj(f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+12] + w[12];
w[12] += S1 (w[10]) + w[5] + S0 (w[13]);
t2 = Sum0 (e) + Maj(e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+13] + w[13];
w[13] += S1 (w[11]) + w[6] + S0 (w[14]);
t2 = Sum0 (d) + Maj(d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+14] + w[14];
w[14] += S1 (w[12]) + w[7] + S0 (w[15]);
t2 = Sum0 (c) + Maj(c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+15] + w[15];
w[15] += S1 (w[13]) + w[8] + S0 (w[0]);
t2 = Sum0 (b) + Maj(b, c, d);
e += t1;
a = t1 + t2;
t += 16;
#endif
}
for (; t < 80; )
{
u64 t1, t2;
#if 0 /* Not unrolled. */
t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[t%16];
t2 = Sum0 (a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
t++;
#else /* Unrolled to interweave the chain variables. */
t1 = h + Sum1 (e) + Ch(e, f, g) + k[t] + w[0];
t2 = Sum0 (a) + Maj(a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+1] + w[1];
t2 = Sum0 (h) + Maj(h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+2] + w[2];
t2 = Sum0 (g) + Maj(g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+3] + w[3];
t2 = Sum0 (f) + Maj(f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+4] + w[4];
t2 = Sum0 (e) + Maj(e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+5] + w[5];
t2 = Sum0 (d) + Maj(d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+6] + w[6];
t2 = Sum0 (c) + Maj(c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+7] + w[7];
t2 = Sum0 (b) + Maj(b, c, d);
e += t1;
a = t1 + t2;
t1 = h + Sum1 (e) + Ch(e, f, g) + k[t+8] + w[8];
t2 = Sum0 (a) + Maj(a, b, c);
d += t1;
h = t1 + t2;
t1 = g + Sum1 (d) + Ch(d, e, f) + k[t+9] + w[9];
t2 = Sum0 (h) + Maj(h, a, b);
c += t1;
g = t1 + t2;
t1 = f + Sum1 (c) + Ch(c, d, e) + k[t+10] + w[10];
t2 = Sum0 (g) + Maj(g, h, a);
b += t1;
f = t1 + t2;
t1 = e + Sum1 (b) + Ch(b, c, d) + k[t+11] + w[11];
t2 = Sum0 (f) + Maj(f, g, h);
a += t1;
e = t1 + t2;
t1 = d + Sum1 (a) + Ch(a, b, c) + k[t+12] + w[12];
t2 = Sum0 (e) + Maj(e, f, g);
h += t1;
d = t1 + t2;
t1 = c + Sum1 (h) + Ch(h, a, b) + k[t+13] + w[13];
t2 = Sum0 (d) + Maj(d, e, f);
g += t1;
c = t1 + t2;
t1 = b + Sum1 (g) + Ch(g, h, a) + k[t+14] + w[14];
t2 = Sum0 (c) + Maj(c, d, e);
f += t1;
b = t1 + t2;
t1 = a + Sum1 (f) + Ch(f, g, h) + k[t+15] + w[15];
t2 = Sum0 (b) + Maj(b, c, d);
e += t1;
a = t1 + t2;
t += 16;
#endif
}
/* Update chaining vars. */
hd->h0 += a;
hd->h1 += b;
hd->h2 += c;
hd->h3 += d;
hd->h4 += e;
hd->h5 += f;
hd->h6 += g;
hd->h7 += h;
return /* burn_stack */ (8 + 16) * sizeof(u64) + sizeof(u32) + 3 * sizeof(void*);
}
static unsigned int
sha512_transform(void *context, const unsigned char *data, size_t nblks)
{
sha512_context *ctx = context;
unsigned int burn;
do
{
burn = sha512_transform_block(&ctx->state, data) + 3 * sizeof(void*);
data += 128;
}
while(--nblks);
return burn;
}
/* The routine final terminates the computation and
* returns the digest.
* The handle is prepared for a new cycle, but adding bytes to the
* handle will the destroy the returned buffer.
* Returns: 64 bytes representing the digest. When used for sha384,
* we take the leftmost 48 of those bytes.
*/
byte *
sha512_final(sha512_context *ctx)
{
u64 t, th, msb, lsb;
byte *p;
sha256_update(&ctx->bctx, NULL, 0); /* flush */ ;
t = ctx->bctx.nblocks;
/* if (sizeof t == sizeof ctx->bctx.nblocks) */
th = ctx->bctx.nblocks_high;
/* else */
/* th = ctx->bctx.nblocks >> 64; In case we ever use u128 */
/* multiply by 128 to make a byte count */
lsb = t << 7;
msb = (th << 7) | (t >> 57);
/* add the count */
t = lsb;
if ((lsb += ctx->bctx.count) < t)
msb++;
/* multiply by 8 to make a bit count */
t = lsb;
lsb <<= 3;
msb <<= 3;
msb |= t >> 61;
if (ctx->bctx.count < 112)
{ /* enough room */
ctx->bctx.buf[ctx->bctx.count++] = 0x80; /* pad */
while(ctx->bctx.count < 112)
ctx->bctx.buf[ctx->bctx.count++] = 0; /* pad */
}
else
{ /* need one extra block */
ctx->bctx.buf[ctx->bctx.count++] = 0x80; /* pad character */
while(ctx->bctx.count < 128)
ctx->bctx.buf[ctx->bctx.count++] = 0;
sha256_update(&ctx->bctx, NULL, 0); /* flush */ ;
memset(ctx->bctx.buf, 0, 112); /* fill next block with zeroes */
}
/* append the 128 bit count */
put_u64(ctx->bctx.buf + 112, msb);
put_u64(ctx->bctx.buf + 120, lsb);
sha512_transform(ctx, ctx->bctx.buf, 1);
p = ctx->bctx.buf;
#define X(a) do { put_u64(p, ctx->state.h##a); p += 8; } while(0)
X (0);
X (1);
X (2);
X (3);
X (4);
X (5);
/* Note that these last two chunks are included even for SHA384.
We just ignore them. */
X (6);
X (7);
#undef X
return ctx->bctx.buf;
}

53
lib/sha512.h Normal file
View File

@ -0,0 +1,53 @@
/*
* BIRD -- SHA512 and SHA384 Hash Functions
*
* (c) 2015 CZ.NIC z.s.p.o.
*
* Based on the code from libgcrypt-1.6.0, which is
* (c) 2003, 2006, 2008, 2009 Free Software Foundation, Inc.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _BIRD_SHA512_H_
#define _BIRD_SHA512_H_
#include "lib/sha256.h"
#define SHA512_SIZE 64
#define SHA512_HEX_SIZE 129
#define SHA384_SIZE 48
#define SHA384_HEX_SIZE 97
typedef struct
{
u64 h0, h1, h2, h3, h4, h5, h6, h7;
} sha512_state;
typedef struct
{
sha256_context bctx;
sha512_state state;
} sha512_context;
typedef sha512_context sha384_context;
void sha512_init(sha512_context *ctx);
void sha384_init(sha384_context *ctx);
void sha512_update(sha512_context *ctx, const byte *in_buf, size_t in_len);
void sha384_update(sha384_context *ctx, const byte *in_buf, size_t in_len)
{
sha512_update(ctx, in_buf, in_len);
}
byte* sha512_final(sha512_context *ctx);
byte* sha384_final(sha384_context *ctx)
{
return sha512_final(ctx);
}
static unsigned int sha512_transform(void *context, const unsigned char *data, size_t nblks);
#endif /* _BIRD_SHA512_H_ */

123
lib/sha512_test.c Normal file
View File

@ -0,0 +1,123 @@
/*
* BIRD Library -- SHA512 and SHA384 Hash Functions Tests
*
* (c) 2015 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include <stdlib.h>
#include "test/birdtest.h"
#include "test/birdtest_support.h"
#include "sysdep/config.h"
#include "lib/sha512.h"
#include "lib/sha512.c" /* REMOVE ME */
static void
byte_to_hex(char *out, const byte *in, uint len)
{
int i;
for (i = 0; i < len; i++)
sprintf(out + i*2, "%02x", in[i]);
}
static void
get_sha512(const char *str, char (*out_hash)[SHA512_HEX_SIZE])
{
sha512_context ctx;
sha512_init(&ctx);
sha512_update(&ctx, str, strlen(str));
byte *hash = sha512_final(&ctx);
byte_to_hex((char*)out_hash, hash, SHA512_SIZE);
}
static void
get_sha384(const char *str, char (*out_hash)[SHA384_HEX_SIZE])
{
sha384_context ctx;
sha384_init(&ctx);
sha384_update(&ctx, str, strlen(str));
byte *hash = sha384_final(&ctx);
byte_to_hex((char*)out_hash, hash, SHA384_SIZE);
}
static int
t_sha512(void)
{
struct in_out {
char *in;
char out[SHA512_HEX_SIZE];
} in_out[] = {
{
.in = "",
.out = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
},
{
.in = "a",
.out = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
},
{
.in = "abc",
.out = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
},
{
.in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
.out = "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445",
},
{
.in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
.out = "86497b815f64702e2ac6aca1f1d16f7159b4f0b34f6e92a41e632982a7291465957e0ef171042b9630bb66c6e35051613f99bdc95c371eeb46bff8c897eba6e9",
},
};
bt_assert_fn_in_out(get_sha512, in_out, "'%s'", "'%s'");
return BT_SUCCESS;
}
static int
t_sha384(void)
{
struct in_out {
char *in;
char out[SHA384_HEX_SIZE];
} in_out[] = {
{
.in = "",
.out = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
},
{
.in = "a",
.out = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
},
{
.in = "abc",
.out = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
},
{
.in = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
.out = "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b",
},
{
.in = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
.out = "7b2cc66b0f621c1cb45c8dec93becf425d08f48d0e652154f8fffdde3ac7b1d2c6b19e9e507867301a3b604a8dafd3ba",
},
};
bt_assert_fn_in_out(get_sha384, in_out, "'%s'", "'%s'");
return BT_SUCCESS;
}
int
main(int argc, char *argv[])
{
bt_init(argc, argv);
bt_test_suite(t_sha512, "Testing SHA512");
bt_test_suite(t_sha384, "Testing SHA384");
return bt_end();
}

View File

@ -36,6 +36,15 @@ get_u32(const void *p)
return ntohl(x); return ntohl(x);
} }
static inline u64
get_u64(const void *p)
{
u32 xh, xl;
memcpy(&xh, p, 4);
memcpy(&xl, p+4, 4);
return (((u64) ntohl(xh)) << 32) | ntohl(xl);
}
static inline void static inline void
put_u16(void *p, u16 x) put_u16(void *p, u16 x)
{ {
@ -50,4 +59,14 @@ put_u32(void *p, u32 x)
memcpy(p, &x, 4); memcpy(p, &x, 4);
} }
static inline void
put_u64(void *p, u64 x)
{
u32 xh, xl;
xh = htonl(x >> 32);
xl = htonl((u32) x);
memcpy(p, &xh, 4);
memcpy(p+4, &xl, 4);
}
#endif #endif