SHA512/384 原理及C语言实现(附源码)

https://blog.csdn.net/u011280717/article/details/79430408

闲来无事,造个哈希轮子,SHA384/SHA512这两者原理及实现一样的,只是输出和初始化的向量不一样。

原型
hash_val = sha512/384(message). 
hash_val: SHA512输出是512bit(64个byte),SHA384输出是384bit(48个byte) 
message: 0 < bits(message) < 2^128,message的最长不超过2^128 bits。

原理
其实SHA2的原理很简单,维基百科上也有很多说明:https://en.wikipedia.org/wiki/SHA-2。 
这里就结合后面代码实现简单概述一下。 
SHA512首先会将填充message到1024 bits的整数倍。然后将message分成若干个1024 bits的block。循环对每一个block进行处理,最终得到哈希值。如下图可以看到,在算法住处有一个512 bits的初始向量IV=H0, 然后与一个block进行运算得到H1,接着H1会与第二个block进行运算得到H2,经过(len(message) / 1024)次的迭代运算后,得到最终512 bits的Hash码。

填充消息
1.将message转换成byte数组。
2.填充message 直至长度为 896 = bits(message)%1024。这里需要注意的是即使message已经是1024bits的整数倍,比如一个message的长度正好是1024bits,还是需要继续填充的。下面举三个例子。
message    原始长度    填充后长度    附加message bit数后的长度
123456    48 bits    896 bits    1024 bits
0123456789abcdef0123456789abcdef
0123456789abcdef0123456789abcdef
0123456789abcdef0123456789abcdef
0123456789abcdef0123456789abcdef    1024 bits    1920 bits    2048 bits
0123456789abcdef0123456789abcdef
0123456789abcdef0123456789abcdef
0123456789abcdef0123456789abcdef
0123456789abcdef0123456789abcdef
123456    1030 bits    1920 bits    2048 bits
填充规则如下:填充的第一个bit是1,其余都是0。

3.将message的长度(位数)以大端模式填到填充后的message的尾部,再次填充128bit,使最终填充的message的长度正好是1024 bits的整数倍。
设置初始值
SHA512/384 以1024个bit作为一个block,SHA512和SHA384的初始向量不同,其他的流程都是一样的,这里只看SHA512的初始向量,一共是512 bits,这个是固定不变的。

        A = 0x6a09e667f3bcc908ULL;
        B = 0xbb67ae8584caa73bULL;
        C = 0x3c6ef372fe94f82bULL;
        D = 0xa54ff53a5f1d36f1ULL;
        E = 0x510e527fade682d1ULL;
        F = 0x9b05688c2b3e6c1fULL;
        G = 0x1f83d9abfb41bd6bULL; 
        H = 0x5be0cd19137e2179ULL;
1
2
3
4
5
6
7
8
循环运算
从图1可以知道每次运算的中间结果H[n]都是H[n-1] 和 block[n]进行运算得到的。每一次跌倒运算都要经过80轮的加工。下图是一轮加工的过程。假设现在第一轮运算,那么ABCDEFGH就是H[n-1],然后经过一轮运算后得到temp1[ABCDEFGH],然后temp1进行第二轮加工得到temp2,如此进行80轮之后,最终ABCDEFGH就是我们要得到H[n]。 
 
在这幅图中,我们并没有看到block[n]在哪里,看图上的Wt和Kt,t代表该轮的轮数。K是一个固定的5120 bits向量,定义如下:

static const uint64_t K[80] =
{
    0x428A2F98D728AE22ULL,  0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL,  0xE9B5DBA58189DBBCULL,
    0x3956C25BF348B538ULL,  0x59F111F1B605D019ULL, 0x923F82A4AF194F9BULL,  0xAB1C5ED5DA6D8118ULL,
    0xD807AA98A3030242ULL,  0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL,  0x550C7DC3D5FFB4E2ULL,
    0x72BE5D74F27B896FULL,  0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL,  0xC19BF174CF692694ULL,
    0xE49B69C19EF14AD2ULL,  0xEFBE4786384F25E3ULL, 0x0FC19DC68B8CD5B5ULL,  0x240CA1CC77AC9C65ULL,
    0x2DE92C6F592B0275ULL,  0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL,  0x76F988DA831153B5ULL,
    0x983E5152EE66DFABULL,  0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL,  0xBF597FC7BEEF0EE4ULL,
    0xC6E00BF33DA88FC2ULL,  0xD5A79147930AA725ULL, 0x06CA6351E003826FULL,  0x142929670A0E6E70ULL,
    0x27B70A8546D22FFCULL,  0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL,  0x53380D139D95B3DFULL,
    0x650A73548BAF63DEULL,  0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL,  0x92722C851482353BULL,
    0xA2BFE8A14CF10364ULL,  0xA81A664BBC423001ULL, 0xC24B8B70D0F89791ULL,  0xC76C51A30654BE30ULL,
    0xD192E819D6EF5218ULL,  0xD69906245565A910ULL, 0xF40E35855771202AULL,  0x106AA07032BBD1B8ULL,
    0x19A4C116B8D2D0C8ULL,  0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL,  0x34B0BCB5E19B48A8ULL,
    0x391C0CB3C5C95A63ULL,  0x4ED8AA4AE3418ACBULL, 0x5B9CCA4F7763E373ULL,  0x682E6FF3D6B2B8A3ULL,
    0x748F82EE5DEFB2FCULL,  0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL,  0x8CC702081A6439ECULL,
    0x90BEFFFA23631E28ULL,  0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL,  0xC67178F2E372532BULL,
    0xCA273ECEEA26619CULL,  0xD186B8C721C0C207ULL, 0xEADA7DD6CDE0EB1EULL,  0xF57D4F7FEE6ED178ULL,
    0x06F067AA72176FBAULL,  0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL,  0x1B710B35131C471BULL,
    0x28DB77F523047D84ULL,  0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL,  0x431D67C49C100D4CULL,
    0x4CC5D4BECB3E42B6ULL,  0x597F299CFC657E2AULL, 0x5FCB6FAB3AD6FAECULL,  0x6C44198C4A475817ULL
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
W也是一个5120 bits向量,它的值是由每一个block(1024 bits)计算而来,这个计算关系是固定的,如下,其中

    uint64_t W[80];

    /* 1. Calculate the W[80] */
    for(i = 0; i < 16; i++) {
        sha512_decode(&W[i], block, i << 3 );
    }

    for(; i < 80; i++) {
        W[i] = GAMMA1(W[i -  2]) + W[i -  7] + GAMMA0(W[i - 15]) + W[i - 16];
    }
1
2
3
4
5
6
7
8
9
10
好了,知道了W和K之后我们就看一看图中的Ch Ma,Sigma0和Sigma1的定义。 

折合成C语言,代码如下:

#define LSR(x,n) (x >> n)
#define ROR(x,n) (LSR(x,n) | (x << (64 - n)))

#define MA(x,y,z) ((x & y) | (z & (x | y)))
#define CH(x,y,z) (z ^ (x & (y ^ z)))
#define GAMMA0(x) (ROR(x, 1) ^ ROR(x, 8) ^  LSR(x, 7))
#define GAMMA1(x) (ROR(x,19) ^ ROR(x,61) ^  LSR(x, 6))
#define SIGMA0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39))
#define SIGMA1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41))
1
2
3
4
5
6
7
8
9
知道这些之后再来看每一轮运算的代码就非常简单

#define COMPRESS( a,  b,  c, d,  e,  f,  g,  h, x,  k)   \
    tmp0 = h + SIGMA1(e) + CH(e,f,g) + k + x;              \
    tmp1 = SIGMA0(a) + MA(a,b,c); d += tmp0; h = tmp0 + tmp1;
1
2
3
保存运算结果
完成迭代运算后,Hash码保存到了最终的ABCDEFGH中,然后将这些向量按照大端模式输出。

代码实现
sha512_ctx_t定义了SHA512所需要的上下文

easy_sha512.h

/*
 * Copyright (c) 2018, Jiamin Ma
 * BSD License
 */
#ifndef EASY_SHA512_H
#define EASY_SHA512_H

#include "easy_crypto.h"

#ifdef CRYPTO_DEBUG_SUPPORT
#define SHA512_DEBUG printf
#else
#define SHA512_DEBUG(fmt, ...)
#endif

/**
 * @brief   Convert uint64_t to big endian byte array.
 * @param   input       input uint64_t data
 * @param   output      output big endian byte array
 * @param   idx         idx of the byte array.
 * @retval  void
 */
static void inline sha512_encode(uint64_t input, uint8_t *output, uint32_t idx)
{
    output[idx + 0] = (uint8_t)(input >> 56);
    output[idx + 1] = (uint8_t)(input >> 48);
    output[idx + 2] = (uint8_t)(input >> 40);
    output[idx + 3] = (uint8_t)(input >> 32);
    output[idx + 4] = (uint8_t)(input >> 24);
    output[idx + 5] = (uint8_t)(input >> 16);
    output[idx + 6] = (uint8_t)(input >>  8);
    output[idx + 7] = (uint8_t)(input >>  0);
}

/**
 * @brief   Convert big endian byte array to uint64_t data
 * @param   output      output uint64_t data
 * @param   input       input big endian byte array
 * @param   idx         idx of the byte array.
 * @retval  void
 */
static inline void sha512_decode(uint64_t *output, uint8_t *input, uint32_t idx)
{
    *output = ((uint64_t)input[idx + 0] << 56)
            | ((uint64_t)input[idx + 1] << 48)
            | ((uint64_t)input[idx + 2] << 40)
            | ((uint64_t)input[idx + 3] << 32)
            | ((uint64_t)input[idx + 4] << 24)
            | ((uint64_t)input[idx + 5] << 16)
            | ((uint64_t)input[idx + 6] <<  8)
            | ((uint64_t)input[idx + 7] <<  0);
}

typedef struct sha512_ctx_tag {

    uint32_t is_sha384;
    /*SHA512 process the data by one block:1024 bits*/
    uint8_t block[128];
    /*SHA512 will fill 128 bits length field: unit:bit*/
    uint64_t len[2];
    /*Hash values*/
    uint64_t val[8];
    /*Payload address to hash*/
    uint8_t *payload_addr;
    /*Payload length*/
    uint64_t payload_len;
} sha512_ctx_t;


#define LSR(x,n) (x >> n)
#define ROR(x,n) (LSR(x,n) | (x << (64 - n)))

#define MA(x,y,z) ((x & y) | (z & (x | y)))
#define CH(x,y,z) (z ^ (x & (y ^ z)))
#define GAMMA0(x) (ROR(x, 1) ^ ROR(x, 8) ^  LSR(x, 7))
#define GAMMA1(x) (ROR(x,19) ^ ROR(x,61) ^  LSR(x, 6))
#define SIGMA0(x) (ROR(x,28) ^ ROR(x,34) ^ ROR(x,39))
#define SIGMA1(x) (ROR(x,14) ^ ROR(x,18) ^ ROR(x,41))

#define INIT_COMPRESSOR() uint64_t tmp0 = 0, tmp1 = 0
#define COMPRESS( a,  b,  c, d,  e,  f,  g,  h, x,  k)   \
    tmp0 = h + SIGMA1(e) + CH(e,f,g) + k + x;              \
    tmp1 = SIGMA0(a) + MA(a,b,c); d += tmp0; h = tmp0 + tmp1;

#endif /*EASY_SHA512_H*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
实现代码很简单,easy_sha512_impl是主流程,分为三步 
1. sha512_init初始化SHA512根据消息的长度和起始地址的上下文。 
2. sha512_stage1处理数据直到倒数第二个block,将其中间Hash值保存在sha512_ctx_t的val向量中。如果消息的原始长度小于1024 bits,那么这个函数将不处理,因为倒数第二个block不存在,只存在一个1024 bits的block。参考表1的message = 123456。从代码实现中可以看到消息的字节数小于128时,不做任何处理,否则循环处理每一个block。 
3. sha512_stage2处理处理填充后的message的最后一个block,将上一次的Hasn中间结果和该block进行运算得到最终的Hash并且保存到output中。 
4. sha512_hash_factory就是处理每一个block得到其中间结果的函数,里面逻辑很简单,首先初始化了W向量,然后计算80轮的加工,最终将得到中间结果保存到sha512_ctx_t的val中。

easy_sha512.c

/*
 * Copyright (c) 2018, Jiamin Ma
 * BSD License
 */
#include "easy_sha512.h"
#include <stdio.h>

/*
 * Predefined sha512 padding bytes
 */
static const uint8_t sha512_padding[128] =
{
    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,
    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, 0
};

/*
 * K byte array used for iteration
 */
static const uint64_t K[80] =
{
    0x428A2F98D728AE22ULL,  0x7137449123EF65CDULL, 0xB5C0FBCFEC4D3B2FULL,  0xE9B5DBA58189DBBCULL,
    0x3956C25BF348B538ULL,  0x59F111F1B605D019ULL, 0x923F82A4AF194F9BULL,  0xAB1C5ED5DA6D8118ULL,
    0xD807AA98A3030242ULL,  0x12835B0145706FBEULL, 0x243185BE4EE4B28CULL,  0x550C7DC3D5FFB4E2ULL,
    0x72BE5D74F27B896FULL,  0x80DEB1FE3B1696B1ULL, 0x9BDC06A725C71235ULL,  0xC19BF174CF692694ULL,
    0xE49B69C19EF14AD2ULL,  0xEFBE4786384F25E3ULL, 0x0FC19DC68B8CD5B5ULL,  0x240CA1CC77AC9C65ULL,
    0x2DE92C6F592B0275ULL,  0x4A7484AA6EA6E483ULL, 0x5CB0A9DCBD41FBD4ULL,  0x76F988DA831153B5ULL,
    0x983E5152EE66DFABULL,  0xA831C66D2DB43210ULL, 0xB00327C898FB213FULL,  0xBF597FC7BEEF0EE4ULL,
    0xC6E00BF33DA88FC2ULL,  0xD5A79147930AA725ULL, 0x06CA6351E003826FULL,  0x142929670A0E6E70ULL,
    0x27B70A8546D22FFCULL,  0x2E1B21385C26C926ULL, 0x4D2C6DFC5AC42AEDULL,  0x53380D139D95B3DFULL,
    0x650A73548BAF63DEULL,  0x766A0ABB3C77B2A8ULL, 0x81C2C92E47EDAEE6ULL,  0x92722C851482353BULL,
    0xA2BFE8A14CF10364ULL,  0xA81A664BBC423001ULL, 0xC24B8B70D0F89791ULL,  0xC76C51A30654BE30ULL,
    0xD192E819D6EF5218ULL,  0xD69906245565A910ULL, 0xF40E35855771202AULL,  0x106AA07032BBD1B8ULL,
    0x19A4C116B8D2D0C8ULL,  0x1E376C085141AB53ULL, 0x2748774CDF8EEB99ULL,  0x34B0BCB5E19B48A8ULL,
    0x391C0CB3C5C95A63ULL,  0x4ED8AA4AE3418ACBULL, 0x5B9CCA4F7763E373ULL,  0x682E6FF3D6B2B8A3ULL,
    0x748F82EE5DEFB2FCULL,  0x78A5636F43172F60ULL, 0x84C87814A1F0AB72ULL,  0x8CC702081A6439ECULL,
    0x90BEFFFA23631E28ULL,  0xA4506CEBDE82BDE9ULL, 0xBEF9A3F7B2C67915ULL,  0xC67178F2E372532BULL,
    0xCA273ECEEA26619CULL,  0xD186B8C721C0C207ULL, 0xEADA7DD6CDE0EB1EULL,  0xF57D4F7FEE6ED178ULL,
    0x06F067AA72176FBAULL,  0x0A637DC5A2C898A6ULL, 0x113F9804BEF90DAEULL,  0x1B710B35131C471BULL,
    0x28DB77F523047D84ULL,  0x32CAAB7B40C72493ULL, 0x3C9EBE0A15C9BEBCULL,  0x431D67C49C100D4CULL,
    0x4CC5D4BECB3E42B6ULL,  0x597F299CFC657E2AULL, 0x5FCB6FAB3AD6FAECULL,  0x6C44198C4A475817ULL
};

static inline void sha512_memcpy(uint8_t *src, uint8_t *dst, uint32_t size)
{
    uint32_t i = 0;
    for (;i < size;i++) {
        *dst++ = *src++;
    }
}

static inline void sha512_memclr(uint8_t *dst, uint32_t size)
{
    uint32_t i = 0;
    for (;i < size;i++) {
        *dst++ = 0;
    }
}

/**
 * @brief   Init the SHA384/SHA512 Context
 * @param   sha512_ctx      SHA384/512 context
 * @param   payload         address of the hash payload
 * @param   payload_len     length of the hash payload
 * @param   is_sha384       0:SHA512, 1:SHA384
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if hash failed
 *          CRYPTO_SUCCESS if hash successed
 */
static crypto_status_t sha512_init(sha512_ctx_t *sha512_ctx, uint8_t *payload_addr, uint64_t payload_len, uint32_t is_sha384)
{
    crypto_status_t ret = CRYPTO_FAIL;

    SHA512_DEBUG("%s\n", __func__);
    if (payload_len == 0 || payload_addr == NULL) {
        SHA512_DEBUG("%s parameter illegal\n", __func__);
        goto cleanup;
    }

    sha512_memclr((uint8_t *)sha512_ctx, sizeof(sha512_ctx_t));
    if (1 == is_sha384) {
        SHA512_DEBUG("%s SHA384\n", __func__);
        sha512_ctx->val[0] = 0xCBBB9D5DC1059ED8ULL;
        sha512_ctx->val[1] = 0x629A292A367CD507ULL;
        sha512_ctx->val[2] = 0x9159015A3070DD17ULL;
        sha512_ctx->val[3] = 0x152FECD8F70E5939ULL;
        sha512_ctx->val[4] = 0x67332667FFC00B31ULL;
        sha512_ctx->val[5] = 0x8EB44A8768581511ULL;
        sha512_ctx->val[6] = 0xDB0C2E0D64F98FA7ULL;
        sha512_ctx->val[7] = 0x47B5481DBEFA4FA4ULL;
    } else {
        SHA512_DEBUG("%s SHA512\n", __func__);
        sha512_ctx->val[0] = 0x6A09E667F3BCC908ULL;
        sha512_ctx->val[1] = 0xBB67AE8584CAA73BULL;
        sha512_ctx->val[2] = 0x3C6EF372FE94F82BULL;
        sha512_ctx->val[3] = 0xA54FF53A5F1D36F1ULL;
        sha512_ctx->val[4] = 0x510E527FADE682D1ULL;
        sha512_ctx->val[5] = 0x9B05688C2B3E6C1FULL;
        sha512_ctx->val[6] = 0x1F83D9ABFB41BD6BULL;
        sha512_ctx->val[7] = 0x5BE0CD19137E2179ULL;
    }

    sha512_ctx->is_sha384 = is_sha384;
    sha512_ctx->payload_addr = payload_addr;
    sha512_ctx->payload_len = (uint64_t)payload_len;
    sha512_ctx->len[0] = payload_len << 3;
    sha512_ctx->len[1] = payload_len >> 61;
    ret = CRYPTO_SUCCESS;

cleanup:
    return ret;
}

/**
 * @brief   SHA384/512 iteration compression
 * @param   sha512_ctx        context of the sha384/512
 * @param   data              hash block data, 1024 bits.
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if failed
 *          CRYPTO_SUCCESS if successed
 */
static crypto_status_t sha512_hash_factory(sha512_ctx_t *ctx, uint8_t data[128])
{
    uint32_t i = 0;
    uint64_t W[80];
    /* One iteration vectors
     * v[0] --> A
     * ...
     * v[7] --> H
     * */
    uint64_t v[8];

    INIT_COMPRESSOR();
    SHA512_DEBUG("%s\n", __func__);

    /* 1. Calculate the W[80] */
    for(i = 0; i < 16; i++) {
        sha512_decode(&W[i], data, i << 3 );
    }

    for(; i < 80; i++) {
        W[i] = GAMMA1(W[i -  2]) + W[i -  7] + GAMMA0(W[i - 15]) + W[i - 16];
    }

    /* 2.Init the vectors */
    for (i = 0;i < 8; i++) {
        v[i] = ctx->val[i];
    }

    /* 3. Iteration to do the SHA-2 family compression. */
    for(i = 0; i < 80;) {
        COMPRESS(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], W[i], K[i] ); i++;
        COMPRESS(v[7], v[0], v[1], v[2], v[3], v[4], v[5], v[6], W[i], K[i] ); i++;
        COMPRESS(v[6], v[7], v[0], v[1], v[2], v[3], v[4], v[5], W[i], K[i] ); i++;
        COMPRESS(v[5], v[6], v[7], v[0], v[1], v[2], v[3], v[4], W[i], K[i] ); i++;
        COMPRESS(v[4], v[5], v[6], v[7], v[0], v[1], v[2], v[3], W[i], K[i] ); i++;
        COMPRESS(v[3], v[4], v[5], v[6], v[7], v[0], v[1], v[2], W[i], K[i] ); i++;
        COMPRESS(v[2], v[3], v[4], v[5], v[6], v[7], v[0], v[1], W[i], K[i] ); i++;
        COMPRESS(v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[0], W[i], K[i] ); i++;

    }

    /* 4. Move the vectors to hash output */
    for (i = 0; i < 8; i++) {
        ctx->val[i] += v[i];
    }

    return CRYPTO_SUCCESS;
}

/**
 * @brief   SHA384/512 stage1
 * @param   sha512_ctx        context of the sha384/512
 * @param   output            output of hash value
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if failed
 *          CRYPTO_SUCCESS if successed
 */
static crypto_status_t sha512_stage1(sha512_ctx_t *sha512_ctx)
{
    SHA512_DEBUG("%s\n", __func__);

    while (sha512_ctx->payload_len >= 128) {
        sha512_hash_factory(sha512_ctx, sha512_ctx->payload_addr);
        sha512_ctx->payload_addr += 128;
        sha512_ctx->payload_len -= 128;
        SHA512_DEBUG("%x, %x\n", (uint32_t) sha512_ctx->payload_addr, (uint32_t) sha512_ctx->payload_len);
    }

    return CRYPTO_SUCCESS;
}


/**
 * @brief   SHA384/512 stage2:Do padding and digest the fianl bytes
 * @param   sha512_ctx        context of the sha384/512
 * @param   output            output of hash value
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if failed
 *          CRYPTO_SUCCESS if successed
 */
static crypto_status_t sha512_stage2(sha512_ctx_t *sha512_ctx,
        uint8_t output[64])
{

    uint32_t block_pos = sha512_ctx->payload_len;
    uint32_t padding_bytes = 0;
    uint8_t temp_data[128] = {0};
    uint8_t *temp_data_p = (uint8_t *)&temp_data[0];
    uint8_t len_be[16] = {0};
    uint8_t i = 0;

    SHA512_DEBUG("%s\n", __func__);

    /*Copy the last byte to the temp buffer*/
    sha512_memcpy(sha512_ctx->payload_addr, temp_data_p, sha512_ctx->payload_len);
    padding_bytes = 112 - block_pos;
    temp_data_p += block_pos;

    /*Copy the padding byte to the temp buffer*/
    sha512_memcpy((uint8_t *)sha512_padding, temp_data_p, padding_bytes);
    temp_data_p += padding_bytes;

    /*Append the length*/
    sha512_encode(sha512_ctx->len[1], len_be, 0);
    sha512_encode(sha512_ctx->len[0], len_be, 8);
    sha512_memcpy(len_be, temp_data_p, 16);
    sha512_hash_factory(sha512_ctx, temp_data);

    /*encode the hash val to big endian byte array*/
    for (i = 0; i < 6; i++) {
        sha512_encode(sha512_ctx->val[i], output, i * 8);
    }

    /*No need to encode the last 16 bytes for SHA384*/
    for ( ;(i < 8) && (sha512_ctx->is_sha384 == 0); i++) {
        sha512_encode(sha512_ctx->val[i], output, i * 8);
    }

    return CRYPTO_SUCCESS;
}

/**
 * @brief   SHA384/512 implementation function
 * @param   payload         address of the hash payload
 * @param   payload_len     length of the hash payload
 * @param   hash            output of hash value
 * @param   is_sha384       0:SHA512, 1:SHA384
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if hash failed
 *          CRYPTO_SUCCESS if hash successed
 */
crypto_status_t easy_sha512_impl(uint8_t *payload, uint64_t payload_len,
        uint8_t output[64], uint32_t is_sha384)
{

    crypto_status_t ret = CRYPTO_FAIL;

    sha512_ctx_t g_sha512_ctx;
    ret = sha512_init(&g_sha512_ctx, payload, payload_len, is_sha384);
    if (ret != CRYPTO_SUCCESS) {
        goto cleanup;
    }

    ret = sha512_stage1(&g_sha512_ctx);
    if (ret != CRYPTO_SUCCESS) {
        goto cleanup;
    }

    ret = sha512_stage2(&g_sha512_ctx, output);

cleanup:
    return ret;
}

/**
 * @brief   API for SHA512
 * @param   payload         address of the hash payload
 * @param   payload_len     length of the hash payload
 * @param   hash            output of hash value
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if hash failed
 *          CRYPTO_SUCCESS if hash successed
 */
crypto_status_t easy_sha512(uint8_t *payload, uint64_t payload_len, uint8_t hash[64])
{
    return easy_sha512_impl(payload, payload_len, hash, 0);
}

/**
 * @brief   API for SHA384
 * @param   payload         address of the hash payload
 * @param   payload_len     length of the hash payload
 * @param   hash            output of hash value
 * @retval  crypto_status_t
 * @return  CRYPTO_FAIL if hash failed
 *          CRYPTO_SUCCESS if hash successed
 */
crypto_status_t easy_sha384(uint8_t *payload, uint64_t payload_len, uint8_t hash[64])
{
    return easy_sha512_impl(payload, payload_len, hash, 1);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
配置头文件 
定义CRYPTO_DEBUG_SUPPORT宏可以打开DEBUG打印。 
easy_crypto.h

/*
 * Copyright (c) 2018, Jiamin Ma
 * BSD License
 */
#ifndef EASY_CRYPTO_H
#define EASY_CRYPTO_H

#include <stdint.h>

#ifdef CRYPTO_DEBUG_SUPPORT
#include <stdio.h>
#endif

typedef uint32_t crypto_status_t;
#define CRYPTO_FAIL             0x5A5A5A5AUL
#define CRYPTO_SUCCESS          0xA5A5A5A5UL

extern crypto_status_t easy_sha512(uint8_t *payload, uint64_t payaload_len, uint8_t hash[64]);
extern crypto_status_t easy_sha384(uint8_t *payload, uint64_t payaload_len, uint8_t hash[64]);

#endif /*EASY_CRYPTO_H*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试
测试命令 
gcc main.c easy_sha512.c -o sha512 
./sha512 
SHA384 Test 0 Passed 
SHA384 Test 1 Passed 
SHA384 Test 2 Passed 
SHA512 Test 0 Passed 
SHA512 Test 1 Passed 
SHA512 Test 2 Passed

分别测试了表1中的3个消息的SHA384和SHA512。 
main.c

/*
 * Copyright (c) 2018, Jiamin Ma
 * BSD License
 */
#include "easy_crypto.h"
#include <stdio.h>
#include <stdint.h>

#define TEST_VEC_NUM 3
static const uint8_t sha384_res0[TEST_VEC_NUM][48] = {
       {0x0a,0x98,0x9e,0xbc,0x4a,0x77,0xb5,0x6a,0x6e,0x2b,0xb7,0xb1,
        0x9d,0x99,0x5d,0x18,0x5c,0xe4,0x40,0x90,0xc1,0x3e,0x29,0x84,
        0xb7,0xec,0xc6,0xd4,0x46,0xd4,0xb6,0x1e,0xa9,0x99,0x1b,0x76,
        0xa4,0xc2,0xf0,0x4b,0x1b,0x4d,0x24,0x48,0x41,0x44,0x94,0x54,},
       {0xf9,0x32,0xb8,0x9b,0x67,0x8d,0xbd,0xdd,0xb5,0x55,0x80,0x77,
        0x03,0xb3,0xe4,0xff,0x99,0xd7,0x08,0x2c,0xc4,0x00,0x8d,0x3a,
        0x62,0x3f,0x40,0x36,0x1c,0xaa,0x24,0xf8,0xb5,0x3f,0x7b,0x11,
        0x2e,0xd4,0x6f,0x02,0x7f,0xf6,0x6e,0xf8,0x42,0xd2,0xd0,0x8c,},
       {0x4e,0x72,0xf4,0x07,0x66,0xcd,0x1b,0x2f,0x23,0x1b,0x9c,0x14,
        0x9a,0x40,0x04,0x6e,0xcc,0xc7,0x2d,0xa9,0x1d,0x5a,0x02,0x42,
        0xf6,0xab,0x49,0xfe,0xea,0x4e,0xfd,0x55,0x43,0x9b,0x7e,0xd7,
        0x82,0xe0,0x3d,0x69,0x0f,0xb9,0x78,0xc3,0xdb,0xce,0x91,0xc1},
};

static const uint8_t sha512_res0[TEST_VEC_NUM][64] = {
       {0xba,0x32,0x53,0x87,0x6a,0xed,0x6b,0xc2,0x2d,0x4a,0x6f,0xf5,
        0x3d,0x84,0x06,0xc6,0xad,0x86,0x41,0x95,0xed,0x14,0x4a,0xb5,
        0xc8,0x76,0x21,0xb6,0xc2,0x33,0xb5,0x48,0xba,0xea,0xe6,0x95,
        0x6d,0xf3,0x46,0xec,0x8c,0x17,0xf5,0xea,0x10,0xf3,0x5e,0xe3,
        0xcb,0xc5,0x14,0x79,0x7e,0xd7,0xdd,0xd3,0x14,0x54,0x64,0xe2,
        0xa0,0xba,0xb4,0x13},
       {0x45,0x1e,0x75,0x99,0x6b,0x89,0x39,0xbc,0x54,0x0b,0xe7,0x80,
        0xb3,0x3d,0x2e,0x5a,0xb2,0x0d,0x6e,0x2a,0x2b,0x89,0x44,0x2c,
        0x9b,0xfe,0x6b,0x47,0x97,0xf6,0x44,0x0d,0xac,0x65,0xc5,0x8b,
        0x6a,0xff,0x10,0xa2,0xca,0x34,0xc3,0x77,0x35,0x00,0x8d,0x67,
        0x10,0x37,0xfa,0x40,0x81,0xbf,0x56,0xb4,0xee,0x24,0x37,0x29,
        0xfa,0x5e,0x76,0x8e},
       {0x51,0x33,0x35,0xc0,0x7d,0x10,0xed,0x85,0xe7,0xdc,0x3c,0xa9,
        0xb9,0xf1,0x1a,0xe7,0x59,0x1e,0x5b,0x36,0xf9,0xb3,0x71,0xfb,
        0x66,0x21,0xb4,0xec,0x6f,0xc8,0x05,0x57,0xfe,0x1e,0x7b,0x9e,
        0x1c,0xc1,0x12,0x32,0xb0,0xb2,0xdd,0x92,0x1d,0x80,0x56,0xbf,
        0x09,0x7a,0x91,0xc3,0x6d,0xd7,0x28,0x46,0x71,0xfc,0x46,0x8e,
        0x06,0x17,0x49,0xf4},
};

static char *test_vectors[TEST_VEC_NUM]= {
    "123456",
    "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef123456",
};

static uint32_t vector_len[TEST_VEC_NUM] = {6, 128, 134};

int main()
{
    uint8_t output[64];
    uint32_t i = 0, j = 0;

    for (i = 0; i < TEST_VEC_NUM; i++) {
        easy_sha384(test_vectors[i], vector_len[i], output);
        for (j = 0; j < 48; j++) {
            if (output[j] != sha384_res0[i][j]) {
                printf("SHA384 Test %d Failed\n", i);
                printf("hash should be %x, calu:%x\n",  sha384_res0[i][j], output[j]);
                break;
            }
        }
        if (j == 48) {
            printf("SHA384 Test %d Passed\n", i);
        }
    }

    for (i = 0; i < TEST_VEC_NUM; i++) {
        easy_sha512(test_vectors[i], vector_len[i], output);
        for (j = 0; j < 64; j++) {
            if (output[j] != sha512_res0[i][j]) {
                printf("SHA512 Test %d Failed\n", i);
                printf("hash should be %x, calu:%x\n",  sha512_res0[i][j], output[j]);
                break;
            }
        }
        if (j == 64) {
            printf("SHA512 Test %d Passed\n", i);
        }
    }
}
--------------------- 
作者:MJm_HL 
来源:CSDN 
原文:https://blog.csdn.net/u011280717/article/details/79430408 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值