sha256算法 c語言實現

sha256算法,網上有很多的介紹,摘抄一段如下:

SHA-256 算法輸入報文的最大長度不超過2^64 bit,輸入按512-bit 分組進行處理,產生的輸出是一個256-bit 的報文摘要。該算法處理包括以下幾步: 

STEP1:附加填充比特。
對報文進行填充使報文長度與448 模512 同餘(長度=448 mod 512),填充的比特數範圍是1 到512,填充比特串的最高位爲1,其餘位爲0。就是先在報文後面加一個 1,再加很多個0,直到長度 滿足 mod 512=448.
爲什麼是448,因爲448+64=512. 第二步會加上一個 64bit的 原始報文的 長度信息。

STEP2:附加長度值。將用64-bit 表示的初始報文(填充前)的位長度附加在步驟1 的結果後(低位字節優先)。

STEP3:初始化緩存。使用一個256-bit 的緩存來存放該散列函數的中間及最終結果。 
該緩存表示爲A=0x6A09E667 , B=0xBB67AE85 , C=0x3C6EF372 , D=0xA54FF53A, E=0x510E527F , F=0x9B05688C , G=0x1F83D9AB , H=0x5BE0CD19 。

STEP4:處理512-bit(16 個字)報文分組序列。該算法使用了六種基本邏輯函數,由64步迭代運算組成。每步都以256-bit 緩存值ABCDEFGH 爲輸入,然後更新緩存內容。
 

我們來理解一下:
一、補位+長度
sha256算法是將原始的報文按照512bit(64byte)進行分組,最後不足64byte要補位+填充長度至64個字節。
補位:第一個bit爲1其他爲0,也就是說補位時第一個字節爲0x80,其他的都爲0x00。
長度:最後8個字節存放原始報文的長度信息,按bit計算。
到了這裏我們應該就能想到,原始報文長度小於56byte和大於等於56byte,這兩種情況應該分別處理。
處理方法如下:
長度小於56字節的 len=4*8=32(0x20)
bbbbbbbb 80000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000020

長度大與等於56字節的 len=60*8=480(0x1e0)
bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
bbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbb
bbbbbbbb bbbbbbbb bbbbbbbb 80000000

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 000001e0

二、2組常量
8個哈希初值,自然數中前8個質數(2,3,5,7,11,13,17,19)的平方根的小數部分取前32bit。
64個常量是對自然數中前64個質數(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97…)的立方根的小數部分取前32bit。

三、hash的過程,下圖表述的非常形象。

 
 

四、完整代碼實現:
ubuntu 下編譯:gcc zmain.c zsha256.c

//zsha256.h
////////////////////////////////////////////////////////////

#ifndef _M_ZSHA256_H
#define _M_ZSHA256_H

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include <string.h>

#ifdef  __cplusplus  
extern "C" {  
#endif 

int zsha256(const uint8_t *src, uint32_t len, uint32_t *hash);

#ifdef  __cplusplus  
}
#endif 
#endif

//zsha256.c
////////////////////////////////////////////////////////////
#include "zsha256.h"

#define ZDBG 0
#define SHFR(x, n) (((x) >> (n)))
#define ROTR(x, n) (((x) >> (n)) | ((x) << ((sizeof(x) << 3) - (n))))
#define ROTL(x, n) (((x) << (n)) | ((x) >> ((sizeof(x) << 3) - (n))))

#define CHX(x, y, z) (((x) &  (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) &  (y)) ^ ( (x) & (z)) ^ ((y) & (z)))

#define BSIG0(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define BSIG1(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SSIG0(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))
#define SSIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))

#define SHA256_BLOCK_SIZE (512/8)
#define SHA256_COVER_SIZE (SHA256_BLOCK_SIZE*2)


static uint32_t 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
};

#if ZDBG 
static int zdump_hex(const uint8_t *data, int size)
{
    int i;
    int l = 32;

    if (data[0] == 0x21) return 0;
    
    for(i=0; i<size; i++) {
        if((i%l) == 0) {
            printf( "[%02x] ", i/l );
        }
        printf( "%02x", data[i] );
        if(((i+1)%l) == 0) {
            printf( "\n" );
        }
    }
 
    printf( "\n" );
    return 0;
}
#else
#define zdump_hex(a, b) 
#endif

static int ztransform(const uint8_t *msg, uint32_t *h)
{
    uint32_t w[64];
    uint32_t a0, b1, c2, d3, e4, f5, g6, h7;
    uint32_t t1, t2;

    int i = 0;
    int j = 0;

    for (i=0; i<16; i++) {
        w[i] = msg[j]<<24 | msg[j+1]<<16 | msg[j+2]<<8 | msg[j+3];
        j += 4;
    }

    for(i=16; i<64; i++){
        w[i] = SSIG1(w[i-2])+w[i-7]+SSIG0(w[i-15])+w[i-16];
    }
    
    zdump_hex((uint8_t*)w, 64*4);

    a0 = h[0];
    b1 = h[1];
    c2 = h[2];
    d3 = h[3];
    e4 = h[4];
    f5 = h[5];
    g6 = h[6];
    h7 = h[7];

    for (i= 0; i<64; i++) {
        t1 = h7 + BSIG1(e4) + CHX(e4, f5, g6) + k[i] + w[i];
        t2 = BSIG0(a0) + MAJ(a0, b1, c2);

        h7 = g6;
        g6 = f5;
        f5 = e4;
        e4 = d3 + t1;
        d3 = c2;
        c2 = b1;
        b1 = a0;
        a0 = t1 + t2;
    }

    h[0] += a0;
    h[1] += b1;
    h[2] += c2;
    h[3] += d3;
    h[4] += e4;
    h[5] += f5;
    h[6] += g6;
    h[7] += h7;

    return 0;
}

int zsha256(const uint8_t *src, uint32_t len, uint32_t *hash)
{
    uint8_t *tmp = (uint8_t*)src;
    uint8_t  cover_data[SHA256_COVER_SIZE];
    uint32_t cover_size = 0;
    
    uint32_t i = 0;
    uint32_t n = 0;
    uint32_t m = 0;
    uint32_t h[8];

    h[0] = 0x6a09e667;
    h[1] = 0xbb67ae85;
    h[2] = 0x3c6ef372;
    h[3] = 0xa54ff53a;
    h[4] = 0x510e527f;
    h[5] = 0x9b05688c;
    h[6] = 0x1f83d9ab;
    h[7] = 0x5be0cd19;

    memset(cover_data, 0x00, sizeof(uint8_t)*SHA256_COVER_SIZE);

    n = len / SHA256_BLOCK_SIZE;
    m = len % SHA256_BLOCK_SIZE;

    if (m < 56 ) {
        cover_size = SHA256_BLOCK_SIZE;
    }else {
        cover_size = SHA256_BLOCK_SIZE*2;
    }

    if (m != 0) {
        memcpy(cover_data, tmp + (n * SHA256_BLOCK_SIZE), m);
    }
    cover_data[m] = 0x80;
    cover_data[cover_size-4]  = ((len*8)&0xff000000) >> 24;
    cover_data[cover_size-3]  = ((len*8)&0x00ff0000) >> 16;
    cover_data[cover_size-2]  = ((len*8)&0x0000ff00) >> 8;
    cover_data[cover_size-1]  = ((len*8)&0x000000ff);

    zdump_hex(tmp, len-m);
    zdump_hex(cover_data, cover_size);

    for (i=0; i<n; i++) {
        tmp += i*SHA256_BLOCK_SIZE;
        ztransform(tmp, h);
    }

    tmp = cover_data;
    n = cover_size / SHA256_BLOCK_SIZE;
    for (i=0; i<n; i++) {
        tmp += i*SHA256_BLOCK_SIZE;
        ztransform(tmp, h);
    }
    
    if (NULL != hash) {
        memcpy(hash, h, sizeof(uint32_t)*8);
    }
    return 0;
}

//zmain.c
////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include <string.h>

#include "zsha256.h"

int main(int argc, char* argv[])
{
    char *p = "hello";
    int   n = strlen(p);
    int   i = 0;
    uint32_t hash[8];

    printf("len=%d\n", n);
    printf("%s\n", p);

    zsha256((uint8_t*)p, n, hash);
    
    printf("\n");
    for (i=0; i<8; i++) {
        printf("%x", hash[i]);
    }
    printf("\n");

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章