diff --git a/lib/sha256.c b/lib/sha256.c index e262227b..bfd6a29c 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -32,6 +32,7 @@ sha256_init(sha256_context *ctx) ctx->nblocks = 0; ctx->nblocks_high = 0; ctx->count = 0; + ctx->blocksize = 64; } void @@ -49,6 +50,7 @@ sha224_init(sha224_context *ctx) ctx->nblocks = 0; ctx->nblocks_high = 0; ctx->count = 0; + ctx->blocksize = 64; } /* (4.2) same as SHA-1's F1. */ @@ -110,7 +112,7 @@ sum1(u32 x) 32-bit-words. See FIPS 180-2 for details. */ 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] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, @@ -217,7 +219,7 @@ sha256_transform(void *ctx, const unsigned char *data, size_t nblks) do { - burn = transform(hd, data); + burn = sha256_transform_block(hd, data); data += 64; } while (--nblks); @@ -234,8 +236,7 @@ sha256_transform(void *ctx, const unsigned char *data, size_t nblks) void sha256_update(sha256_context *ctx, const byte *in_buf, size_t in_len) { - unsigned int stack_burn = 0; - const unsigned int blocksize = 64; + const unsigned int blocksize = ctx->blocksize; size_t inblocks; 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. */ { - stack_burn = sha256_transform(ctx, ctx->buf, 1); - stack_burn = 0; + sha256_transform(ctx, ctx->buf, 1); ctx->count = 0; if (!++ctx->nblocks) ctx->nblocks_high++; @@ -264,7 +264,7 @@ sha256_update(sha256_context *ctx, const byte *in_buf, size_t in_len) if (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->nblocks_high += (ctx->nblocks + inblocks < inblocks); ctx->nblocks += inblocks; @@ -285,7 +285,6 @@ sha256_final(sha256_context *ctx) { u32 t, th, msb, lsb; byte *p; - unsigned int burn; sha256_update(ctx, NULL, 0); /* flush */; @@ -325,7 +324,7 @@ sha256_final(sha256_context *ctx) /* append the 64 bit count */ put_u32(ctx->buf + 56, msb); put_u32(ctx->buf + 60, lsb); - burn = sha256_transform(ctx, ctx->buf, 1); + sha256_transform(ctx, ctx->buf, 1); 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 returned value is valid as long as the context exists. On error NULL is returned. */ -const byte * +byte * sha256_hmac_final(sha256_hmac_context *ctx) { sha256_final(&ctx->ctx); diff --git a/lib/sha256.h b/lib/sha256.h index a054ff90..1cc49a79 100644 --- a/lib/sha256.h +++ b/lib/sha256.h @@ -20,10 +20,11 @@ typedef struct { u32 h0,h1,h2,h3,h4,h5,h6,h7; - byte buf[64]; + byte buf[128]; u32 nblocks; u32 nblocks_high; int count; + u32 blocksize; } sha256_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); } -const byte *sha256_hmac_final(sha256_hmac_context *ctx); -const byte *sha224_hmac_final(sha224_hmac_context *ctx) +byte *sha256_hmac_final(sha256_hmac_context *ctx); +byte *sha224_hmac_final(sha224_hmac_context *ctx) { return sha256_hmac_final(ctx); } diff --git a/lib/sha256_test.c b/lib/sha256_test.c index f7b93f0a..3aeab677 100644 --- a/lib/sha256_test.c +++ b/lib/sha256_test.c @@ -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_update(&ctx, in.data, in.data_len); byte *hash_byte = sha256_hmac_final(&ctx); - - int i; - for (i = 0; i < SHA256_SIZE; i++) - sprintf(*out_hash + i*2, "%02x", hash_byte[i]); + byte_to_hex((char*)out_hash, hash_byte, SHA256_SIZE); } 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_update(&ctx, in.data, in.data_len); byte *hash_byte = sha224_hmac_final(&ctx); - - int i; - for (i = 0; i < SHA224_SIZE; i++) - sprintf(*out_hash + i*2, "%02x", hash_byte[i]); + byte_to_hex((char*)out_hash, hash_byte, SHA224_HEX_SIZE); } diff --git a/lib/sha512.c b/lib/sha512.c new file mode 100644 index 00000000..f610bba9 --- /dev/null +++ b/lib/sha512.c @@ -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 +#include +#include +#include + +#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; +} diff --git a/lib/sha512.h b/lib/sha512.h new file mode 100644 index 00000000..b5da77b6 --- /dev/null +++ b/lib/sha512.h @@ -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_ */ diff --git a/lib/sha512_test.c b/lib/sha512_test.c new file mode 100644 index 00000000..73fdd5e8 --- /dev/null +++ b/lib/sha512_test.c @@ -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 + +#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(); +} diff --git a/lib/unaligned.h b/lib/unaligned.h index 73fe2d8a..f686b9c8 100644 --- a/lib/unaligned.h +++ b/lib/unaligned.h @@ -36,6 +36,15 @@ get_u32(const void *p) 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 put_u16(void *p, u16 x) { @@ -50,4 +59,14 @@ put_u32(void *p, u32 x) 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