SHA512/384 原理及C語言實現(附源碼)

閒來無事,造個哈希輪子,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可以知道每次運算的中間結果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
};

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];
    }

好了,知道了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))

知道這些之後再來看每一輪運算的代碼就非常簡單

#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;

保存運算結果

完成迭代運算後,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*/

實現代碼很簡單,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);
}

配置頭文件
定義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*/

測試

測試命令
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);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章