SHA512系列哈希算法原理及实现(附源码)
SHA512系列哈希算法原理及实现(附源码)相关文章:SHA224和SHA256哈希算法原理及实现(附源码)国密SM3哈希算法原理及实现(附源码)SHA1哈希算法原理及实现(附源码)MD5哈希算法原理及实现(附源码)MD4哈希算法原理及实现(附源码)MD2哈希算法原理及实现(附源码)MD2中用于随机置换的S盒是如何生成的?最近陆续造了一批哈希算法的轮子,包括MD家族(包括MD2/MD4/MD5),
相关文章:
最近陆续造了一批哈希算法的轮子,包括MD家族(包括MD2/MD4/MD5), SHA1, SHA2家族(SHA224, SHA256, SHA384, SHA512),SHA3家族以及国密SM3算法。
原来打算将每一个算法都详细分析并实现,现在看来,这个工作短时间可能无法完成,所以先将源码发上来。
这部分实现的源码完全参考官方文档的算法描述,连变量名也尽可能和官方文档中的变量保持一致,方便学习。
本篇主要是描述SHA512系列哈希算法的原理及实现,SHA512系列的哈希函数都是基于SHA512哈希函数扩展而来,这些列主要包括:
- SHA512
- SHA384 (初始化常量和SHA512不一样,结果哈希从512比特截断为384比特)
- SHA512/224 (初始化常量和SHA512不一样,哈希结果从512比特截断为224比特,兼容SHA224)
- SHA512/256 (初始化常量和SHA512不一样,哈希结果从512比特截断为256比特,兼容SHA256)
- SHA512/t (t值不同,计算得到的初始化常量不同,哈希结果从512比特截断为t比特)
变长版本的SHA512t中:
- 如果t=224,其结果和SHA512/224一样;
- 如果t=256,其结果和SHA512/256一样;
- FIPS 180-4中指出,没有t=384的变长版本
另外, SHA512系列函数的API封装调用接口参考了openssl官方的接口,完全兼容,无缝对接。会使用这里的接口,就会使用openssl的库函数接口,甚至连代码都不需要修改。
除了实现的源码外,还另外附带了一个测试例子,这个测试例子不仅仅是用于测试哈希算法的实现是否正确,还可以提供了"-f"/"-s"等选项用于对任意文件和字符串进行哈希,因此作为一个工具使用,类似系统内置的md5sum/sha1sum。
SHA512的实现源码
1. 头文件sha512.c
/*
* @ file: sha512.h
* @ description: header file for sha512.c
* @ author: Gu Yongqiang
* @ blog: https://blog.csdn.net/guyongqiangx
*/
#ifndef __ROCKY_SHA512__H
#define __ROCKY_SHA512__H
#define ERR_OK 0
#define ERR_ERR -1 /* generic error */
#define ERR_INV_PARAM -2 /* invalid parameter */
#define ERR_TOO_LONG -3 /* too long */
#define ERR_STATE_ERR -4 /* state error */
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef struct {
uint64_t high; /* high 64 bits */
uint64_t low; /* low 64 bits */
} uint128_t;
typedef struct sha512_context {
/* message total length in bytes */
uint128_t total;
/* intermedia hash value for each block */
struct {
uint64_t a;
uint64_t b;
uint64_t c;
uint64_t d;
uint64_t e;
uint64_t f;
uint64_t g;
uint64_t h;
}hash;
/* last block */
struct {
uint32_t used; /* used bytes */
uint8_t buf[128]; /* block data buffer */
}last;
uint32_t ext; /* t value of SHA512/t */
}SHA512_CTX;
/* https://www.openssl.org/docs/man1.1.1/man3/SHA256_Final.html */
int SHA384_Init(SHA512_CTX *c);
int SHA384_Update(SHA512_CTX *c, const void *data, size_t len);
int SHA384_Final(unsigned char *md, SHA512_CTX *c);
unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md);
int SHA512_Init(SHA512_CTX *c);
int SHA512_Update(SHA512_CTX *c, const void *data, size_t len);
int SHA512_Final(unsigned char *md, SHA512_CTX *c);
unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md);
/* SHA512/224 */
int SHA512_224_Init(SHA512_CTX *c);
int SHA512_224_Update(SHA512_CTX *c, const void *data, size_t len);
int SHA512_224_Final(unsigned char *md, SHA512_CTX *c);
unsigned char *SHA512_224(const unsigned char *d, size_t n, unsigned char *md);
/* SHA512/256 */
int SHA512_256_Init(SHA512_CTX *c);
int SHA512_256_Update(SHA512_CTX *c, const void *data, size_t len);
int SHA512_256_Final(unsigned char *md, SHA512_CTX *c);
unsigned char *SHA512_256(const unsigned char *d, size_t n, unsigned char *md);
int SHA512t_Init(SHA512_CTX *c, unsigned int t);
int SHA512t_Update(SHA512_CTX *c, const void *data, size_t len);
int SHA512t_Final(unsigned char *md, SHA512_CTX *c);
unsigned char *SHA512t(const unsigned char *d, size_t n, unsigned char *md, unsigned int t);
#endif
2. 代码文件sha512.c
/*
* @ file: sha512.c
* @ description: implementation for the SHA512, SHA384, SHA512/224, SHA512/256, SHA512/t Secure Hash Algorithm
* @ author: Gu Yongqiang
* @ blog: https://blog.csdn.net/guyongqiangx
*/
#include <stdio.h>
#include <string.h>
#include "utils.h"
#include "sha512.h"
// #define DEBUG
#ifdef DEBUG
#define DBG(...) printf(__VA_ARGS__)
#define DUMP_BLOCK_DATA 1
#define DUMP_BLOCK_HASH 1
#define DUMP_ROUND_DATA 0
#else
#define DBG(...)
#define DUMP_BLOCK_DATA 0
#define DUMP_BLOCK_HASH 0
#define DUMP_ROUND_DATA 0
#endif
#define SHA512_BLOCK_SIZE 128 /* 1024 bits = 128 bytes */
#define SHA512_LEN_SIZE 16 /* 128 bits = 16 bytes */
#define SHA512_LEN_OFFSET (SHA512_BLOCK_SIZE - SHA512_LEN_SIZE)
#define SHA512_DIGEST_SIZE 64 /* 512 bits = 64 bytes */
#define SHA512_PADDING_PATTERN 0x80
#define SHA512_ROUND_NUM 80
#define SHA384_DIGEST_SIZE 48 /* 384 bits = 48 bytes */
#define SHA512_224_DIGEST_SIZE 28 /* 224 bits = 28 bytes */
#define SHA512_256_DIGEST_SIZE 32 /* 256 bits = 32 bytes */
#define HASH_BLOCK_SIZE SHA512_BLOCK_SIZE
#define HASH_LEN_SIZE SHA512_LEN_SIZE
#define HASH_LEN_OFFSET SHA512_LEN_OFFSET
#define HASH_DIGEST_SIZE SHA512_DIGEST_SIZE
#define HASH_PADDING_PATTERN SHA512_PADDING_PATTERN
#define HASH_ROUND_NUM SHA512_ROUND_NUM
/* SHA512 Constants */
static const uint64_t K512[HASH_ROUND_NUM] =
{
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
};
/* ROTate Right (cirular right shift) */
static uint64_t ROTR(uint64_t x, uint8_t shift)
{
return (x >> shift) | (x << (64 - shift));
}
/* Right SHift */
static uint64_t SHR(uint64_t x, uint8_t shift)
{
return (x >> shift);
}
/* Ch ... choose */
static uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
{
return (x & y) ^ (~x & z) ;
}
/* Maj ... majority */
static uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
{
return (x & y) ^ (x & z) ^ (y & z);
}
/* SIGMA0 */
static uint64_t SIGMA0(uint64_t x)
{
return ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39);
}
/* SIGMA1 */
static uint64_t SIGMA1(uint64_t x)
{
return ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41);
}
/* sigma0, different from SIGMA0 */
static uint64_t sigma0(uint64_t x)
{
return ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7);
}
/* sigma1, different from SIGMA1 */
static uint64_t sigma1(uint64_t x)
{
return ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6);
}
int SHA512_Init(SHA512_CTX *c)
{
if (NULL == c)
{
return ERR_INV_PARAM;
}
memset(c, 0, sizeof(SHA512_CTX));
/* Initial Value for SHA512 */
c->hash.a = 0x6a09e667f3bcc908;
c->hash.b = 0xbb67ae8584caa73b;
c->hash.c = 0x3c6ef372fe94f82b;
c->hash.d = 0xa54ff53a5f1d36f1;
c->hash.e = 0x510e527fade682d1;
c->hash.f = 0x9b05688c2b3e6c1f;
c->hash.g = 0x1f83d9abfb41bd6b;
c->hash.h = 0x5be0cd19137e2179;
c->total.low = 0;
c->total.high = 0;
c->last.used = 0;
return ERR_OK;
}
static int SHA512_PrepareScheduleWord(const uint64_t *block, uint64_t *W)
{
uint32_t t;
if ((NULL == block) || (NULL == W))
{
return ERR_INV_PARAM;
}
for (t=0; t<HASH_ROUND_NUM; t++)
{
if (t<=15) /* 0 <= t <= 15 */
W[t] = be64toh(block[t]);
else /* 16 <= t <= 79 */
W[t] = sigma1(W[t-2]) + W[t-7] + sigma0(W[t-15]) + W[t-16];
}
return ERR_OK;
}
static int SHA512_UpdateTotal(uint128_t *x, uint64_t len)
{
uint64_t l;
l = (x->low + (((uint64_t)len)<<3)) & 0xffffffffffffffff;
if (l < x->low)
x->high++;
//if (sizeof(len) >= 8)
// x->high += ((uint64_t)len)>> 61)
x->low = l;
return ERR_OK;
}
#if 0
static int SHA512_SaveTotal(uint64_t *buffer, uint128_t *len)
{
buffer[0] = htobe64(len->high);
buffer[1] = htobe64(len->low);
return ERR_OK;
}
#endif
#if (DUMP_BLOCK_DATA == 1)
static int SHA512_GetBlockCount(SHA512_CTX *ctx, uint128_t * count)
{
if (ctx->total.high == 0)
{
count->low = ctx->total.low >> 10;
count->high = 0;
}
else
{
count->low = ctx->total.low >> 10;
count->low |= (ctx->total.high & 0x07FF << 54);
count->high = ctx->total.high >> 10;
}
return ERR_OK;
}
#endif
static int SHA512_ProcessBlock(SHA512_CTX *ctx, const void *block)
{
uint32_t t;
uint64_t W[HASH_ROUND_NUM];
uint64_t T1, T2;
uint64_t a, b, c, d, e, f, g, h;
if ((NULL == ctx) || (NULL == block))
{
return ERR_INV_PARAM;
}
#if (DUMP_BLOCK_DATA == 1)
DBG("---------------------------------------------------------\n");
{
uint128_t count;
SHA512_GetBlockCount(ctx, &count);
if (count.high == 0)
{
DBG(" BLOCK: %llu\n", count.low);
}
else{
DBG(" BLOCK: %llu%016llu\n", count.high, count.low);
}
}
DBG(" DATA:\n");
print_buffer(block, HASH_BLOCK_SIZE, " ");
#endif
/* prepare schedule word */
SHA512_PrepareScheduleWord(block, W);
a = ctx->hash.a;
b = ctx->hash.b;
c = ctx->hash.c;
d = ctx->hash.d;
e = ctx->hash.e;
f = ctx->hash.f;
g = ctx->hash.g;
h = ctx->hash.h;
#if (DUMP_BLOCK_HASH == 1)
DBG(" IV: %016llx %016llx %016llx %016llx\n"
" %016llx %016llx %016llx %016llx\n", \
ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h);
#endif
for (t=0; t<HASH_ROUND_NUM; t++)
{
T1 = h + SIGMA1(e) + Ch(e, f, g) + K512[t] + W[t];
T2 = SIGMA0(a) + Maj(a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
#if (DUMP_ROUND_DATA == 1)
DBG(" %02d: T1=0x%016llx, T2=0x%016llx, W=0x%016llx\n", t, T1, T2, W[t]);
DBG(" a=0x%016llx, b=0x%016llx, c=0x%016llx, d=0x%016llx,\n"
" e=0x%016llx, f=0x%016llx, g=0x%016llx, h=0x%016llx\n",
a, b, c, d, e, f, g, h);
#endif
}
ctx->hash.a += a;
ctx->hash.b += b;
ctx->hash.c += c;
ctx->hash.d += d;
ctx->hash.e += e;
ctx->hash.f += f;
ctx->hash.g += g;
ctx->hash.h += h;
#if (DUMP_BLOCK_HASH == 1)
DBG(" HASH: %016llx %016llx %016llx %016llx\n"
" %016llx %016llx %016llx %016llx\n",
ctx->hash.a, ctx->hash.b, ctx->hash.c, ctx->hash.d, ctx->hash.e, ctx->hash.f, ctx->hash.g, ctx->hash.h);
#endif
return ERR_OK;
}
int SHA512_Update(SHA512_CTX *c, const void *data, size_t len)
{
uint64_t copy_len = 0;
if ((NULL == c) || (NULL == data))
{
return ERR_INV_PARAM;
}
/* has used data */
if (c->last.used != 0)
{
/* less than 1 block in total, combine data */
if (c->last.used + len < HASH_BLOCK_SIZE)
{
memcpy(&c->last.buf[c->last.used], data, len);
c->last.used += len;
return ERR_OK;
}
else /* more than 1 block */
{
/* process the block in context buffer */
copy_len = HASH_BLOCK_SIZE - c->last.used;
memcpy(&c->last.buf[c->last.used], data, copy_len);
SHA512_ProcessBlock(c, &c->last.buf);
SHA512_UpdateTotal(&c->total, HASH_BLOCK_SIZE);
data = (uint8_t *)data + copy_len;
len -= copy_len;
/* reset context buffer */
memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE);
c->last.used = 0;
}
}
/* less than 1 block, copy to context buffer */
if (len < HASH_BLOCK_SIZE)
{
memcpy(&c->last.buf[c->last.used], data, len);
c->last.used += len;
return ERR_OK;
}
else
{
/* process data blocks */
while (len >= HASH_BLOCK_SIZE)
{
SHA512_ProcessBlock(c, data);
SHA512_UpdateTotal(&c->total, HASH_BLOCK_SIZE);
data = (uint8_t *)data + HASH_BLOCK_SIZE;
len -= HASH_BLOCK_SIZE;
}
/* copy rest data to context buffer */
memcpy(&c->last.buf[0], data, len);
c->last.used = len;
}
return ERR_OK;
}
int SHA512_Final(unsigned char *md, SHA512_CTX *c)
{
uint64_t *temp;
if ((NULL == c) || (NULL == md))
{
return ERR_INV_PARAM;
}
/* Last block should be less thant HASH_BLOCK_SIZE - HASH_LEN_SIZE */
if (c->last.used >= (HASH_BLOCK_SIZE - HASH_LEN_SIZE))
{
SHA512_UpdateTotal(&c->total, c->last.used);
/* one more block */
c->last.buf[c->last.used] = HASH_PADDING_PATTERN;
c->last.used++;
memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - c->last.used);
SHA512_ProcessBlock(c, &c->last.buf);
c->last.used = 0;
memset(&c->last.buf[0], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE);
// SHA512_SaveTotal(&c->last.buf[HASH_LEN_OFFSET], &c->total);
temp = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]);
temp[0] = htobe64(c->total.high);
temp[1] = htobe64(c->total.low);
SHA512_ProcessBlock(c, &c->last.buf);
}
else /* 0 <= last.used < HASH_BLOCK_SIZE - HASH_LEN_SIZE */
{
SHA512_UpdateTotal(&c->total, c->last.used);
/* one more block */
c->last.buf[c->last.used] = HASH_PADDING_PATTERN;
c->last.used++;
/* padding 0s */
memset(&c->last.buf[c->last.used], 0, HASH_BLOCK_SIZE - HASH_LEN_SIZE - c->last.used);
// SHA512_SaveTotal(&c->last.buf[HASH_LEN_OFFSET], &c->total);
temp = (uint64_t *)&(c->last.buf[HASH_LEN_OFFSET]);
temp[0] = htobe64(c->total.high);
temp[1] = htobe64(c->total.low);
SHA512_ProcessBlock(c, &c->last.buf);
}
temp = (uint64_t *)md;
temp[0] = htobe64(c->hash.a);
temp[1] = htobe64(c->hash.b);
temp[2] = htobe64(c->hash.c);
temp[3] = htobe64(c->hash.d);
temp[4] = htobe64(c->hash.e);
temp[5] = htobe64(c->hash.f);
temp[6] = htobe64(c->hash.g);
temp[7] = htobe64(c->hash.h);
return ERR_OK;
}
unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md)
{
SHA512_CTX c;
if ((NULL == d) || (NULL == md))
{
return NULL;
}
SHA512_Init(&c);
SHA512_Update(&c, d, n);
SHA512_Final(md, &c);
return md;
}
static int SHA512_xxx_Final(unsigned char *md, unsigned int md_size, SHA512_CTX *c)
{
int rc = ERR_OK;
unsigned char sha512_md[SHA512_DIGEST_SIZE];
memset(&sha512_md, 0, sizeof(sha512_md));
rc = SHA512_Final(sha512_md, c);
memcpy(md, sha512_md, md_size);
return rc;
}
int SHA384_Init(SHA512_CTX *c)
{
if (NULL == c)
{
return ERR_INV_PARAM;
}
memset(c, 0, sizeof(SHA512_CTX));
/* Initial Value for SHA384 */
c->hash.a = 0xcbbb9d5dc1059ed8;
c->hash.b = 0x629a292a367cd507;
c->hash.c = 0x9159015a3070dd17;
c->hash.d = 0x152fecd8f70e5939;
c->hash.e = 0x67332667ffc00b31;
c->hash.f = 0x8eb44a8768581511;
c->hash.g = 0xdb0c2e0d64f98fa7;
c->hash.h = 0x47b5481dbefa4fa4;
c->total.low = 0;
c->total.high = 0;
c->last.used = 0;
return ERR_OK;
}
int SHA384_Update(SHA512_CTX *c, const void *data, size_t len)
{
return SHA512_Update(c, data, len);
}
int SHA384_Final(unsigned char *md, SHA512_CTX *c)
{
return SHA512_xxx_Final(md, SHA384_DIGEST_SIZE, c);
}
unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md)
{
SHA512_CTX c;
if ((NULL == d) || (NULL == md))
{
return NULL;
}
SHA384_Init(&c);
SHA384_Update(&c, d, n);
SHA384_Final(md, &c);
return md;
}
int SHA512_224_Init(SHA512_CTX *c)
{
if (NULL == c)
{
return ERR_INV_PARAM;
}
memset(c, 0, sizeof(SHA512_CTX));
/* Initial Value for SHA512/224 */
c->hash.a = 0x8c3d37c819544da2;
c->hash.b = 0x73e1996689dcd4d6;
c->hash.c = 0x1dfab7ae32ff9c82;
c->hash.d = 0x679dd514582f9fcf;
c->hash.e = 0x0f6d2b697bd44da8;
c->hash.f = 0x77e36f7304c48942;
c->hash.g = 0x3f9d85a86a1d36c8;
c->hash.h = 0x1112e6ad91d692a1;
c->total.low = 0;
c->total.high = 0;
c->last.used = 0;
return ERR_OK;
}
int SHA512_224_Update(SHA512_CTX *c, const void *data, size_t len)
{
return SHA512_Update(c, data, len);
}
int SHA512_224_Final(unsigned char *md, SHA512_CTX *c)
{
return SHA512_xxx_Final(md, SHA512_224_DIGEST_SIZE, c);
}
unsigned char *SHA512_224(const unsigned char *d, size_t n, unsigned char *md)
{
SHA512_CTX c;
if ((NULL == d) || (NULL == md))
{
return NULL;
}
SHA512_224_Init(&c);
SHA512_224_Update(&c, d, n);
SHA512_224_Final(md, &c);
return md;
}
int SHA512_256_Init(SHA512_CTX *c)
{
if (NULL == c)
{
return ERR_INV_PARAM;
}
memset(c, 0, sizeof(SHA512_CTX));
/* Initial Value for SHA512/256 */
c->hash.a = 0x22312194fc2bf72c;
c->hash.b = 0x9f555fa3c84c64c2;
c->hash.c = 0x2393b86b6f53b151;
c->hash.d = 0x963877195940eabd;
c->hash.e = 0x96283ee2a88effe3;
c->hash.f = 0xbe5e1e2553863992;
c->hash.g = 0x2b0199fc2c85b8aa;
c->hash.h = 0x0eb72ddc81c52ca2;
c->total.low = 0;
c->total.high = 0;
c->last.used = 0;
return ERR_OK;
}
int SHA512_256_Update(SHA512_CTX *c, const void *data, size_t len)
{
return SHA512_Update(c, data, len);
}
int SHA512_256_Final(unsigned char *md, SHA512_CTX *c)
{
return SHA512_xxx_Final(md, SHA512_256_DIGEST_SIZE, c);
}
unsigned char *SHA512_256(const unsigned char *d, size_t n, unsigned char *md)
{
SHA512_CTX c;
if ((NULL == d) || (NULL == md))
{
return NULL;
}
SHA512_256_Init(&c);
SHA512_256_Update(&c, d, n);
SHA512_256_Final(md, &c);
return md;
}
static int SHA512t_GenerateIV(SHA512_CTX *c, unsigned int t)
{
char name[12]; /* 12 chars for "SHA-512/xxx", like "SHA512/224" */
unsigned char md[SHA512_DIGEST_SIZE];
SHA512_Init(c);
c->hash.a ^= 0xa5a5a5a5a5a5a5a5;
c->hash.b ^= 0xa5a5a5a5a5a5a5a5;
c->hash.c ^= 0xa5a5a5a5a5a5a5a5;
c->hash.d ^= 0xa5a5a5a5a5a5a5a5;
c->hash.e ^= 0xa5a5a5a5a5a5a5a5;
c->hash.f ^= 0xa5a5a5a5a5a5a5a5;
c->hash.g ^= 0xa5a5a5a5a5a5a5a5;
c->hash.h ^= 0xa5a5a5a5a5a5a5a5;
/* "SHA-512/xxx" */
memset(name, 0, sizeof(name));
sprintf(name, "SHA-512/%d", t);
SHA512_Update(c, name, strlen(name));
SHA512_Final(md, c);
#if (DUMP_BLOCK_HASH == 1)
DBG(" IV: (%s)\n", name);
DBG(" %016llx %016llx %016llx %016llx\n"
" %016llx %016llx %016llx %016llx\n", \
c->hash.a, c->hash.b, c->hash.c, c->hash.d, c->hash.e, c->hash.f, c->hash.g, c->hash.h);
#endif
c->ext = t;
return ERR_OK;
}
int SHA512t_Init(SHA512_CTX *c, unsigned int t)
{
if (NULL == c)
{
return ERR_INV_PARAM;
}
/* t=8x, t!=0, t!=384, t!=512 */
if (( t >= 512) || (0 != t%8) || (384 == t) || (0 == t))
{
return ERR_INV_PARAM;
}
memset(c, 0, sizeof(SHA512_CTX));
/* Generate Initial Value for SHA512/t */
SHA512t_GenerateIV(c, t);
c->total.low = 0;
c->total.high = 0;
c->last.used = 0;
return ERR_OK;
}
int SHA512t_Update(SHA512_CTX *c, const void *data, size_t len)
{
return SHA512_Update(c, data, len);
}
int SHA512t_Final(unsigned char *md, SHA512_CTX *c)
{
return SHA512_xxx_Final(md, c->ext/8, c);
}
unsigned char *SHA512t(const unsigned char *d, size_t n, unsigned char *md, unsigned int t)
{
SHA512_CTX c;
if ((NULL == d) || (NULL == md))
{
return NULL;
}
if ((t > 512) || (t%8 != 0) || (t == 0) || (t == 384))
{
return NULL;
}
SHA512t_Init(&c, t);
SHA512t_Update(&c, d, n);
SHA512t_Final(md, &c);
return md;
}
从上面的实现来看,SHA-384, SHA-512/224, SHA-512/256, SHA-512/t和SHA512的主要区别在于:
- SHA-384, SHA-512/224, SHA-512/256, SHA-512/t初始化函数中的初始化常量不一致;
- SHA-384, SHA-512/224, SHA-512/256, SHA-512/t哈希结果中,从基于SHA512得到的哈希中截取前面部分作为这几个函数的哈希值
- SHA-512/t的初始化常量是通过t值计算的,不同的t值,计算得到的初始化常量不一样
SHA512源码的编译和测试
我直接在Makefile中内置了一个test伪目标,编译时除了编译生成名为sha512的哈希工具外,还会直接调用内置的哈希测试。
编译和运行如下:
$ make
gcc -Wall -g -O2 -c utils.c -o utils.o
gcc -Wall -g -O2 -c sha512.c -o sha512.o
gcc -Wall -g -O2 -c sha512test.c -o sha512test.o
gcc -Wall -g -O2 utils.o sha512.o sha512test.o -o sha512
Run Test...
./sha512 -a sha384 -x
Internal hash tests for ./sha512(SHA384):
./sha512("")
Expect: 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
Result: 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
./sha512("a")
Expect: 54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31
Result: 54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31
./sha512("abc")
Expect: cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
Result: cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7
./sha512("message digest")
Expect: 473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5
Result: 473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5
./sha512("abcdefghijklmnopqrstuvwxyz")
Expect: feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4
Result: feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4
./sha512("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
Expect: 1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84
Result: 1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84
./sha512("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
Expect: b12932b0627d1c060942f5447764155655bd4da0c9afa6dd9b9ef53129af1b8fb0195996d2de9ca0df9d821ffee67026
Result: b12932b0627d1c060942f5447764155655bd4da0c9afa6dd9b9ef53129af1b8fb0195996d2de9ca0df9d821ffee67026
./sha512 -a sha512 -x
Internal hash tests for ./sha512(SHA512):
./sha512("")
Expect: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
Result: cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
./sha512("a")
Expect: 1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75
Result: 1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75
./sha512("abc")
Expect: ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
Result: ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f
./sha512("message digest")
Expect: 107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c
Result: 107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c
./sha512("abcdefghijklmnopqrstuvwxyz")
Expect: 4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1
Result: 4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1
./sha512("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
Expect: 1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894
Result: 1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894
./sha512("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
Expect: 72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843
Result: 72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843
./sha512 -a sha512-224 -x
Internal hash tests for ./sha512(SHA512/224):
./sha512("")
Expect: 6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4
Result: 6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4
./sha512("a")
Expect: d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327
Result: d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327
./sha512("abc")
Expect: 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa
Result: 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa
./sha512("message digest")
Expect: ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564
Result: ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564
./sha512("abcdefghijklmnopqrstuvwxyz")
Expect: ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8
Result: ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8
./sha512("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
Expect: a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3
Result: a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3
./sha512("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
Expect: ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2
Result: ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2
./sha512 -a sha512-256 -x
Internal hash tests for ./sha512(SHA512/256):
./sha512("")
Expect: c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
Result: c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a
./sha512("a")
Expect: 455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8
Result: 455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8
./sha512("abc")
Expect: 53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23
Result: 53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23
./sha512("message digest")
Expect: 0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb
Result: 0cf471fd17ed69d990daf3433c89b16d63dec1bb9cb42a6094604ee5d7b4e9fb
./sha512("abcdefghijklmnopqrstuvwxyz")
Expect: fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26
Result: fc3189443f9c268f626aea08a756abe7b726b05f701cb08222312ccfd6710a26
./sha512("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
Expect: cdf1cc0effe26ecc0c13758f7b4a48e000615df241284185c39eb05d355bb9c8
Result: cdf1cc0effe26ecc0c13758f7b4a48e000615df241284185c39eb05d355bb9c8
./sha512("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
Expect: 2c9fdbc0c90bdd87612ee8455474f9044850241dc105b1e8b94b8ddf5fac9148
Result: 2c9fdbc0c90bdd87612ee8455474f9044850241dc105b1e8b94b8ddf5fac9148
./sha512 -a sha512t -t 224 -x
Internal hash tests for ./sha512(SHA512/t):
./sha512("")
Expect: 6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4
Result: 6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4
./sha512("a")
Expect: d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327
Result: d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327
./sha512("abc")
Expect: 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa
Result: 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa
./sha512("message digest")
Expect: ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564
Result: ad1a4db188fe57064f4f24609d2a83cd0afb9b398eb2fcaeaae2c564
./sha512("abcdefghijklmnopqrstuvwxyz")
Expect: ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8
Result: ff83148aa07ec30655c1b40aff86141c0215fe2a54f767d3f38743d8
./sha512("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
Expect: a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3
Result: a8b4b9174b99ffc67d6f49be9981587b96441051e16e6dd036b140d3
./sha512("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
Expect: ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2
Result: ae988faaa47e401a45f704d1272d99702458fea2ddc6582827556dd2
./sha512 -a sha384 -f sha512
./sha512(sha512) = 1b52191008c0e0094f0a9ab06227cdfed06863451013263c178c2a70839096a267ee7fc91de63893290a29e480835d28
./sha512 -a sha512 -f sha512
./sha512(sha512) = 3c451ef72cfbb060fb041bec35b0c5738b98ff01dace09794a8a095b5219036f88ad6e5bceba51a624c5889f65d3605a9920a07d4ce8e37b4d9d161e5bd94634
./sha512 -a sha512-224 -f sha512
./sha512(sha512) = 637747ac3951b51946bb80aab9be4951999a0e8a69c033567fc8d5ec
./sha512 -a sha512-256 -f sha512
./sha512(sha512) = 2265caf9c5ef1022ab306501269209561fab94e22efd32df20c3b74a6351547d
./sha512 -a sha512t -t 224 -f sha512
./sha512(sha512) = 637747ac3951b51946bb80aab9be4951999a0e8a69c033567fc8d5ec
最新版本的openssl工具已经支持SHA512系列的哈希算法(SHA-512/t除外),因此可以将sha512工具和openssl执行dgst计算的结果进行比较:
$ sha512 -h
Usage:
Common options: [-x|-f file|-s string| -a sha384|sha512|sha512-224|sha512-256|sha512t | -t num | -h]
Hash a string:
sha512 -a sha384|sha512|sha512-224|sha512-256|sha512t -s string
Hash a file:
sha512 -a sha384|sha512|sha512-224|sha512-256|sha512t -f file
-a Secure hash algorithm: "sha384", "sha512", "sha512-224", "sha512-256"
-t t value for SHA512/t, positive integer without a leading zero, (0<t<512, t/8=0, t!=384)
-x Internal string hash test
-h Display this message
#
# 使用sha512工具分别对文件和字符串计算哈希值
#
$ for h in sha384 sha512 sha512-224 sha512-256; \
do \
echo "sha512 -a $h -f sha512.o"; \
sha512 -a $h -f sha512.o; \
done;
sha512 -a sha384 -f sha512.o
sha512(sha512.o) = 46ebdfd95d7b5819d265ab9c1abe4e77409b59920cee91715e8e75728acc30c7f11e6f2680fedfaed13ddc78b3f9269a
sha512 -a sha512 -f sha512.o
sha512(sha512.o) = 815eab41765653993db44ebe013d496b0fd0d9649f8f88a3d859a507fbcc31f0c24de18514b513ff14bf6508e54f6527da49e627585dc6f8b81a97653020c310
sha512 -a sha512-224 -f sha512.o
sha512(sha512.o) = 999b0a92bd6a8559d3eb4921403c9d3132a1454ef3b1e60f37c17432
sha512 -a sha512-256 -f sha512.o
sha512(sha512.o) = 0e4f315c0af0e2e25e23bdf866338e65dc5885f9e90fa0484d1d1410f24a94b0
$ S="I Love China!"; \
for h in sha384 sha512 sha512-224 sha512-256; \
do \
echo "sha512 -a $h -s \"$S\""; \
sha512 -a $h -s $S; \
done;
sha512 -a sha384 -s "I Love China!"
sha512("I") = 54738b3c22eb17fa6f32dce8ae4c2bbf474ac7d89cf3aad01490246c943579ef28e6537f948eab03e5b8ecece20f0683
sha512 -a sha512 -s "I Love China!"
sha512("I") = 32b1786eca2b9f815b4c52b999e2b34dae877a86c00e8f745e7ac23388665c0703a947085bd7f975c5210ffab9b5a8f3931ab40b26cd7bccc4d7690cd19a4277
sha512 -a sha512-224 -s "I Love China!"
sha512("I") = 38f27409e58691cbd80c0c6258117446b53e75a9895827ddbd85f53a
sha512 -a sha512-256 -s "I Love China!"
sha512("I") = 7cdd023a2896a7c29338a40033fe9b711678861c5b43eaa36347ecc35d25d1c0
#
# 使用开源的openssl工具计算相应的哈希进行对比
#
$ for h in sha384 sha512 sha512-224 sha512-256; \
do \
echo "openssl dgst -$h sha512.o"; \
openssl dgst -$h sha512.o; \
done;
openssl dgst -sha384 sha512.o
SHA384(sha512.o)= 46ebdfd95d7b5819d265ab9c1abe4e77409b59920cee91715e8e75728acc30c7f11e6f2680fedfaed13ddc78b3f9269a
openssl dgst -sha512 sha512.o
SHA512(sha512.o)= 815eab41765653993db44ebe013d496b0fd0d9649f8f88a3d859a507fbcc31f0c24de18514b513ff14bf6508e54f6527da49e627585dc6f8b81a97653020c310
openssl dgst -sha512-224 sha512.o
SHA512-224(sha512.o)= 999b0a92bd6a8559d3eb4921403c9d3132a1454ef3b1e60f37c17432
openssl dgst -sha512-256 sha512.o
SHA512-256(sha512.o)= 0e4f315c0af0e2e25e23bdf866338e65dc5885f9e90fa0484d1d1410f24a94b0
$ S="I Love China!"; \
for h in sha384 sha512 sha512-224 sha512-256; \
do \
echo "echo -n \"$S\" | openssl dgst -$h"; \
echo -n \"$S\" | openssl dgst -$h; \
done;
echo -n "I Love China!" | openssl dgst -sha384
(stdin)= 10e849acdc83e320de1d092a0a582e3af1055bd55150c7d81a88d52145241b686ac0a9ef713a6da8a9e73e5af33c2355
echo -n "I Love China!" | openssl dgst -sha512
(stdin)= fbd797a0ef6fd8cfdb9e5efffbc24eac2e60f4193440ee58a5608a2aff96dab1c22435e05fcc6e018a5a9e4e0827ef670f600e22da028ff2fd9c29d0843aa945
echo -n "I Love China!" | openssl dgst -sha512-224
(stdin)= ecd4de998d134d52ce6c379b9bd7dcd2d4405873b593cdb2ece3ab7c
echo -n "I Love China!" | openssl dgst -sha512-256
(stdin)= 159369bde3fb15b7d5e20a163e66e43601be5eff963b8c554dba114c54f78017
完整代码
完整的代码文件列表如下:
sha512$ ls -lh
total 60K
-rwxr-xr-x 1 rg935739 stb_all 942 Jun 22 17:20 Makefile
-rwxr-xr-x 1 rg935739 stb_all 18K Jun 22 18:21 sha512.c
-rwxr-xr-x 1 rg935739 stb_all 2.6K Jun 21 09:48 sha512.h
-rwxr-xr-x 1 rg935739 stb_all 22K Jun 22 18:06 sha512test.c
-rwxr-xr-x 1 rg935739 stb_all 758 Jun 21 09:48 utils.c
-rwxr-xr-x 1 rg935739 stb_all 1.8K Jun 21 09:48 utils.h
需要代码请访问:
- https://github.com/guyongqiangx/cryptography/
其它
洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。
所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:
- 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。
- 一个Android OTA的讨论组,请说明加Android OTA群。
- 一个git和repo的讨论组,请说明加git和repo群。
在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意:
洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)