--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+uint64_t sha256_h_init[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+};
+
+uint64_t sha224_h_init[8] = {
+ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+ 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
+};
+
+uint64_t sha384_h_init[8] = {
+ 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17,
+ 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511,
+ 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4
+};
+
+uint64_t sha512_h_init[8] = {
+ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b,
+ 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
+ 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
+};
+
+uint64_t sha512_224_h_init[8] = {
+ 0x8c3d37c819544da2, 0x73e1996689dcd4d6, 0x1dfab7ae32ff9c82,
+ 0x679dd514582f9fcf, 0x0f6d2b697bd44da8, 0x77e36f7304C48942,
+ 0x3f9d85a86a1d36C8, 0x1112e6ad91d692a1
+};
+
+uint64_t sha512_256_h_init[8] = {
+ 0x22312194fc2bf72c, 0x9f555fa3c84c64c2,
+ 0x2393b86b6f53b151, 0x963877195940eabd,
+ 0x96283ee2a88effe3, 0xbe5e1e2553863992,
+ 0x2b0199fc2c85b8aa, 0x0eb72ddC81c52ca2
+};
+
+uint64_t sha256_k[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
+};
+
+uint64_t sha512_k[80] = {
+ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
+ 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
+ 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
+ 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
+ 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
+ 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+ 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
+ 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
+ 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
+ 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+ 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
+ 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
+ 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
+ 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
+ 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+ 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
+ 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
+ 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+ 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
+ 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+};
+
+#define SHA2_MAX_BLOCK_LENGTH 128
+
+static inline int min(int a,int b) { return a<b?a:b; }
+
+static inline uint32_t rot32(uint32_t v, int amt) {
+ return (v>>amt) | (v<<(32-amt));
+}
+
+static inline uint64_t rot64(uint64_t v, int amt) {
+ return (v>>amt) | (v<<(64-amt));
+}
+
+static inline uint64_t bepack(uint8_t **src,int num) {
+ int i;
+ uint64_t out=0;
+
+ for(i=0;i<num;i++) {
+ out <<= 8;
+ out |= *((*src)++);
+ }
+ return out;
+}
+
+static inline int be_unpack(uint64_t in, uint8_t **out, int n_in, int n_out,
+ int *maxlen) {
+ int i;
+
+ if(maxlen) {
+ n_out = min(n_out,*maxlen);
+ *maxlen -= n_out;
+ }
+ if(n_out < n_in) {
+ in >>= (8*(n_in-n_out));
+ }
+ for(i=n_out-1;i>=0;i--) {
+ *((*out)+i) = (uint8_t)in;
+ in >>= 8;
+ }
+ *out += n_in;
+ return n_out;
+}
+
+#define FLAG_HALFWORD 1 /* Curse you, 512-224 */
+#define FLAG_HMAC 2
+
+struct sha2_variety_t {
+ uint64_t *iv;
+ int bits,words_out;
+ int v_flags;
+};
+
+struct sha2_ctx_t {
+ int variety_idx;
+ struct sha2_variety_t *variety;
+ uint64_t h64[8];
+ uint8_t pending[SHA2_MAX_BLOCK_LENGTH];
+ int pending_len;
+ uint64_t length;
+ int flags;
+ uint8_t k_prime[SHA2_MAX_BLOCK_LENGTH]; /* For HMAC */
+};
+
+#define SHA2_VARIETY_224 0
+#define SHA2_VARIETY_256 1
+#define SHA2_VARIETY_384 2
+#define SHA2_VARIETY_512 3
+#define SHA2_VARIETY_512_256 4
+#define SHA2_VARIETY_512_224 5
+#define SHA2_VARIETY_END 6
+
+struct sha2_variety_t sha2_variety_def[SHA2_VARIETY_END] = {
+ {sha224_h_init,32,7,0}, /* SHA224 */
+ {sha256_h_init,32,8,0}, /* SHA256 */
+ {sha384_h_init,64,6,0}, /* SHA384 */
+ {sha512_h_init,64,8,0}, /* SHA512 */
+ {sha512_256_h_init,64,4,0}, /* SHA512-256 */
+ {sha512_224_h_init,64,4,FLAG_HALFWORD} /* SHA512-224 */
+};
+
+static int block_length(struct sha2_variety_t *var) {
+ return var->bits*2;
+}
+
+void sha2_init(struct sha2_ctx_t *ctx, int sha2_variety) {
+ ctx->variety_idx = sha2_variety;
+ ctx->variety = &sha2_variety_def[sha2_variety];
+ memcpy(&(ctx->h64),ctx->variety->iv,64);
+ ctx->pending_len = 0;
+ ctx->length = 0;
+ ctx->flags = ctx->variety->v_flags;
+}
+
+static inline uint32_t sigma32(uint32_t src,int a,int b,int c) {
+ return rot32(src,a) ^ rot32(src,b) ^ rot32(src,c);
+}
+
+static inline uint64_t sigma64(uint64_t src,int a,int b,int c) {
+ return rot64(src,a) ^ rot64(src,b) ^ rot64(src,c);
+}
+
+static inline uint64_t maj(uint64_t a, uint64_t b, uint64_t c) {
+ return (a&b) ^ (a&c) ^ (b&c);
+}
+
+static inline uint64_t choose(uint64_t a, uint64_t b, uint64_t c) {
+ return (a&b)^((~a)&c);
+}
+
+static inline uint64_t shr32(uint64_t in, int amt) {
+ return (in&0xFFFFFFFF)>>amt;
+}
+
+static void hash32(struct sha2_ctx_t *ctx) {
+ uint64_t j[8],m[8],w[64],s0,s1,t1;
+ uint8_t *src;
+ int i;
+
+ src = ctx->pending;
+ for(i=0;i<16;i++) {
+ w[i] = bepack(&src,4);
+ }
+ memcpy(j,ctx->h64,64);
+ for(i=16;i<64;i++) {
+ s0 = rot32(w[i-15],7) ^ rot32(w[i-15],18) ^ shr32(w[i-15],3);
+ s1 = rot32(w[i-2],17) ^ rot32(w[i-2],19) ^ shr32(w[i-2],10);
+ w[i] = w[i-16] + s0 + w[i-7] + s1;
+ }
+ for(i=0;i<64;i++) {
+ memcpy(m+1,j,56);
+ t1 = j[7] + sigma32(j[4],6,11,25) + choose(j[4],j[5],j[6]) +
+ sha256_k[i] + w[i];
+ m[4] += t1;
+ m[0] = t1 + sigma32(j[0],2,13,22) + maj(j[0],j[1],j[2]);
+ memcpy(j,m,64);
+ }
+ for(i=0;i<8;i++) {
+ ctx->h64[i] += j[i];
+ }
+}
+
+static void hash64(struct sha2_ctx_t *ctx) {
+ uint64_t w[80],j[8],m[8],t1,s0,s1;
+ uint8_t *src;
+ int i;
+
+ src = ctx->pending;
+ for(i=0;i<16;i++) {
+ w[i] = bepack(&src,8);
+ }
+ for(i=16;i<80;i++) {
+ s0 = rot64(w[i-15],1) ^ rot64(w[i-15],8) ^ (w[i-15]>>7);
+ s1 = rot64(w[i-2],19) ^ rot64(w[i-2],61) ^ (w[i-2]>>6);
+ w[i] = w[i-16] + s0 + w[i-7] + s1;
+ }
+ memcpy(j,ctx->h64,64);
+ for(i=0;i<80;i++) {
+ memcpy(m+1,j,56);
+ t1 = j[7] + sigma64(j[4],14,18,41) + choose(j[4],j[5],j[6]) +
+ sha512_k[i] + w[i];
+ m[4] += t1;
+ m[0] = t1 + sigma64(j[0],28,34,39) + maj(j[0],j[1],j[2]);
+ memcpy(j,m,64);
+ }
+ for(i=0;i<8;i++) {
+ ctx->h64[i] += j[i];
+ }
+}
+
+static void sha_hash(struct sha2_ctx_t *ctx) {
+ if(ctx->variety->bits>32)
+ hash64(ctx);
+ else
+ hash32(ctx);
+}
+
+void sha2_more(struct sha2_ctx_t *ctx, uint8_t *data, int len) {
+ int here,plen;
+
+ ctx->length += len;
+ plen = 2*ctx->variety->bits;
+ while(len>0) {
+ here = min(len, plen - ctx->pending_len);
+ memcpy(ctx->pending + ctx->pending_len, data, here);
+ data += here;
+ len -= here;
+ ctx->pending_len += here;
+ if(ctx->pending_len == plen) {
+ sha_hash(ctx);
+ ctx->pending_len = 0;
+ }
+ }
+}
+
+static int sha2_finish_main(struct sha2_ctx_t *ctx, uint8_t *out, int maxlen) {
+ int i,space_bytes,half_here,space_needed,len_bytes,len_offset,
+ block_size,bits,len;
+ signed int pad_length;
+ uint8_t terminal[128],*len_pos;
+
+ bits = ctx->variety->bits;
+ block_size = 2*bits;
+ len_bytes = bits/4; /* 32 => 8; 64 => 16 */
+ space_bytes = block_size - ctx->pending_len;
+ space_needed = 1 + len_bytes;
+ pad_length = space_bytes - space_needed;
+ if(pad_length<0) {
+ pad_length += block_size;
+ }
+ memset(terminal,0,128);
+ terminal[0] = 0x80;
+ len_offset = 1 + pad_length;
+ len_pos = terminal+len_offset;
+ be_unpack(ctx->length*8,&len_pos,len_bytes,len_bytes,NULL);
+ sha2_more(ctx,terminal,space_needed + pad_length);
+ len = 0;
+ for(i=0;i<ctx->variety->words_out;i++) {
+ half_here = (i==ctx->variety->words_out-1 && ctx->flags&FLAG_HALFWORD);
+ len +=
+ be_unpack(ctx->h64[i],&out,bits/8,half_here?bits/16:bits/8,&maxlen);
+ }
+ return len;
+}
+
+static void xor_blit(uint8_t *data, int v, int n) {
+ int i;
+
+ for(i=0;i<n;i++)
+ data[i] ^= v;
+}
+
+int sha2_finish(struct sha2_ctx_t *ctx, uint8_t *out, int max_len) {
+ uint8_t tmp[SHA2_MAX_BLOCK_LENGTH];
+ struct sha2_ctx_t outer;
+ int block_size,len;
+
+ block_size = block_length(ctx->variety);
+ if(ctx->flags&FLAG_HMAC) {
+ sha2_init(&outer,ctx->variety_idx);
+ memcpy(tmp,ctx->k_prime,block_size);
+ xor_blit(tmp,0x5C,block_size);
+ sha2_more(&outer,tmp,block_size);
+ len = sha2_finish_main(ctx,tmp,SHA2_MAX_BLOCK_LENGTH);
+ sha2_more(&outer,tmp,len);
+ return sha2_finish_main(&outer,out,max_len);
+ } else {
+ return sha2_finish_main(ctx,out,max_len);
+ }
+}
+
+static void derive_key(uint8_t *out, int sha2_variety, uint8_t *key, int key_len) {
+ struct sha2_ctx_t ctx;
+ int block_size;
+
+ block_size = block_length(&sha2_variety_def[sha2_variety]);
+ memset(out,0,block_size);
+ if(key_len > block_size) {
+ sha2_init(&ctx,sha2_variety);
+ sha2_more(&ctx,key,key_len);
+ sha2_finish(&ctx,out,SHA2_MAX_BLOCK_LENGTH);
+ } else {
+ memcpy(out,key,key_len);
+ memset(out+key_len,0,block_size-key_len);
+ }
+}
+
+void sha2_init_hmac(struct sha2_ctx_t *ctx, int sha2_variety,
+ uint8_t *key, int key_len) {
+ uint8_t i_pad[SHA2_MAX_BLOCK_LENGTH];
+ int block_size;
+
+ block_size = block_length(&sha2_variety_def[sha2_variety]);
+ sha2_init(ctx,sha2_variety);
+ derive_key(ctx->k_prime,sha2_variety,key,key_len);
+ memcpy(i_pad,ctx->k_prime,block_size);
+ xor_blit(i_pad,0x36,block_size);
+ sha2_more(ctx,i_pad,block_size);
+ ctx->flags |= FLAG_HMAC;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "sha2.h"
+
+static void to_hex(char *hex, uint8_t *data, int len) {
+ int i;
+ char *h;
+
+ h = hex;
+ for(i=0;i<len;i++) {
+ snprintf(h,3,"%2.2x",data[i]);
+ h += 2;
+ }
+ *h = '\0';
+}
+
+static void compare(char * test_name, int variety, char *input, char *value, char *key) {
+ struct sha2_ctx_t ctx;
+ int len;
+ uint8_t out[SHA2_MAX_DIGEST_SIZE];
+ char hex[SHA2_MAX_DIGEST_SIZE*2+1];
+
+ if(key) {
+ sha2_init_hmac(&ctx,variety,(uint8_t *)key,strlen(key));
+ } else {
+ sha2_init(&ctx,variety);
+ }
+ sha2_more(&ctx,(uint8_t *)input,strlen(input));
+ len = sha2_finish(&ctx,out,SHA2_MAX_DIGEST_SIZE);
+ to_hex(hex,out,len);
+ if(strcmp(hex,value)) {
+ printf("test '%s' failed: expected='%s' got='%s'\n",test_name,value,hex);
+ exit(1);
+ }
+ printf("ok %s\n",test_name);
+}
+
+static void test_trunc() {
+ struct sha2_ctx_t ctx;
+ uint8_t out[SHA2_MAX_DIGEST_SIZE+1];
+ char hex[SHA2_MAX_DIGEST_SIZE*2+1];
+ int len,got;
+ char *expect_all = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
+ char expect[SHA2_MAX_DIGEST_SIZE*2+1];
+
+ for(len=0;len<SHA2_MAX_DIGEST_SIZE;len++) {
+ sha2_init(&ctx,SHA2_VARIETY_512);
+ out[len] = len&0xFF;
+ got = sha2_finish(&ctx,out,len);
+ to_hex(hex,out,got);
+ memcpy(expect,expect_all,len*2);
+ expect[len*2] = '\0';
+ if(strcmp(hex,expect)) {
+ printf("test trunc failed at len=%d: expected='%s' got='%s'\n",
+ len,expect,hex);
+ exit(1);
+ }
+ if(out[len] != (len&0xFF)) {
+ printf("test trunc failed with overrun at len=%d\n",len);
+ exit(1);
+ }
+ }
+ printf("ok test-trunc\n");
+}
+
+int main() {
+ char *dog = "The quick brown fox jumps over the lazy dog";
+ char *k = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
+
+ compare("empty-512",SHA2_VARIETY_512,"","cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",NULL);
+ compare("empty-384",SHA2_VARIETY_384,"","38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",NULL);
+ compare("empty-256",SHA2_VARIETY_256,"","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",NULL);
+ compare("empty-256",SHA2_VARIETY_224,"","d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",NULL);
+ compare("empty-512/256",SHA2_VARIETY_512_256,"","c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",NULL);
+ compare("empty-512/224",SHA2_VARIETY_512_224,"","6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",NULL);
+ compare("dog-512",SHA2_VARIETY_512,dog,"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",NULL);
+ compare("dog-384",SHA2_VARIETY_384,dog,"ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1",NULL);
+ compare("dog-256",SHA2_VARIETY_256,dog,"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",NULL);
+ compare("dog-224",SHA2_VARIETY_224,dog,"730e109bd7a8a32b1cb9d9a09aa2325d2430587ddbc0c38bad911525",NULL);
+ compare("hmac-512",SHA2_VARIETY_512,dog,"2a31d580d74d604de3dce055477d0a5633411adeafa044e10a2c6cfee6e38df49ed336cb53e3e7fa6bbbf3f107a3067296560be3deb09afcaff9cb98d2169433",k);
+ compare("hmac-224",SHA2_VARIETY_224,dog,"610d38da56e06cf7d15bdf1ad83e250ae77ada28b5648036bba614ee",k);
+ test_trunc();
+ return 0;
+}