SM3

算法过程

代码实现

国标

/************************************************************************
  File name:    SM3.c
  Version:      SM3_V1.1
  Date:         Sep 18,2016
  Description:  to calculate a hash message from a given message
  Function List:
    1.SM3_256        //calls SM3_init, SM3_process and SM3_done to calculate hash value
    2.SM3_init       //init the SM3 state
    3.SM3_process    //compress the the first len/64 blocks of the message
    4.SM3_done       //compress the rest message and output the hash value
    5.SM3_compress   //called by SM3_process and SM3_done, compress a single block of message
    6.BiToW          //called by SM3_compress,to calculate W from Bi
    7.WToW1          //called by SM3_compress, calculate W1 from W
    8.CF             //called by SM3_compress, to calculate CF function.
    9.BigEndian      //called by SM3_compress and SM3_done.GM/T 0004-2012 requires to use
big-endian.
                     //if CPU uses little-endian, BigEndian function is a necessary call to
change the
                     //little-endian format into big-endian format.
    10.SM3_SelfTest  //test whether the SM3 calculation is correct by comparing the hash result
with the standard result
  History:
    1. Date:         Sep 18,2016
       Author:       Mao Yingying, Huo Lili
       Modification: 1)add notes to all the functions
                     2)add SM3_SelfTest function
**************************************************************************/
#include "SM3.h" 

/******************************************************************************
  Function:       inputChar
  Description:    输出
*******************************************************************************/
void inputChar(unsigned char* Msg, int len)
{
    int i,count=0;
    for (i = 0; i < len; i++)
    {
        printf("%02X\t", Msg[i]);
        count++;
        if ( count%8 == 0)
        {
            printf("\n");
        }
    }
}


/******************************************************************************
  Function:       inputInt
  Description:    输出
*******************************************************************************/
void inputInt(unsigned int* Msg, int len)
{
    int i, count = 0;
    for (i = 0; i < len; i++)
    {
        printf("%08X\t", Msg[i]);
        count++;
        if (count % 8 == 0)
        {
            printf("\n");
        }
    }
}

/****************************************************************
  Function:       BiToW
  Description:    calculate W from Bi【消息扩展】
  Calls:
  Called By:      SM3_compress
  Input:          Bi[16]    //a block of a message
  Output:         W[64]
  Return:         null
  Others:         将消息分组B[i]扩展生成132个消息字W和W1,这里生成的是W
****************************************************************/
void BiToW(unsigned int Bi[], unsigned int W[])
{
    int i,count=0;
    unsigned int tmp;
    //消息扩展-A
    //将消息分组B[i]划分为16个字W[i]
    for (i = 0; i <= 15; i++)
    {
        W[i] = Bi[i];
    }
    //消息扩展-B
    for (i = 16; i <= 67; i++)
    {
        tmp = W[i - 16]^ W[i - 9]^ SM3_rotl32(W[i - 3], 15);
        W[i] = SM3_p1(tmp)^ (SM3_rotl32(W[i - 13], 7))^ W[i - 6];
    }
    inputInt(W, 68);
}


/*****************************************************************
  Function:       WToW1
  Description:    calculate W1 from W
  Calls:
  Called By:      SM3_compress
  Input:          W[64]
  Output:         W1[64]
  Return:         null
  Others:         将消息分组B[i]扩展生成132个消息字W和W1,这里生成的是W1
*****************************************************************/
void WToW1(unsigned int W[], unsigned int W1[])
{
    int i;
    //消息扩展-C,生成W1
    for (i = 0; i <= 63; i++)
    {
        W1[i] = W[i] ^ W[i + 4];
    }
    inputInt(W1, 64);
}


/******************************************************************
  Function:       CF
  Description:    calculate the CF compress function and update V【压缩函数】
  Calls:
  Called By:      SM3_compress
  Input:          W[64]
                  W1[64]
                  V[8]
  Output:         V[8]
  Return:         null
  Others:
********************************************************************/
void CF(unsigned int W[], unsigned int W1[], unsigned int V[])
{
    unsigned int SS1;
    unsigned int SS2;
    unsigned int TT1;
    unsigned int TT2;
    unsigned int A, B, C, D, E, F, G, H;
    unsigned int T = SM3_T1;
    unsigned int FF;
    unsigned int GG;
    int j;
    printf("\n\n迭代压缩后的中间值:");

    //ABCDEFGH=V0 
    A = V[0];
    B = V[1];
    C = V[2];
    D = V[3];
    E = V[4];
    F = V[5];
    G = V[6];
    H = V[7];
    printf("\nj\tA\t B\t  C\t   D\t    E\t     F\t      G\t       H\n");
    printf("\n\t%08X %08X %08X %08X %08X %08X %08X %08X\n", A, B, C, D, E, F, G, H);
    for (j = 0; j <= 63; j++)
    {
        //SS1 
        if (j == 0)
        {
            T = SM3_T1;
        }
        else if (j == 16)
        {
            T = SM3_rotl32(SM3_T2, 16);
        }
        else
        {
            T = SM3_rotl32(T, 1);
        }
        SS1 = SM3_rotl32((SM3_rotl32(A, 12) + E + T), 7);

        //SS2 
        SS2 = SS1 ^ SM3_rotl32(A, 12);

        //TT1 
        if (j <= 15)
        {
            FF = SM3_ff0(A, B, C);
        }

        else
        {
            FF = SM3_ff1(A, B, C);
        }
        TT1 = FF + D + SS2 + *W1;
        W1++;

        //TT2 
        if (j <= 15)
        {
            GG = SM3_gg0(E, F, G);
        }
        else
        {
            GG = SM3_gg1(E, F, G);
        }
        TT2 = GG + H + SS1 + *W;
        W++;

        //D 
        D = C;

        //C 
        C = SM3_rotl32(B, 9);

        //B 
        B = A;

        //A 
        A = TT1;

        //H 
        H = G;

        //G 
        G = SM3_rotl32(F, 19);

        //F 
        F = E;

        //E 
        E = SM3_p0(TT2);

        printf("\n%d\t%08X %08X %08X %08X %08X %08X %08X %08X\n", j,A, B, C, D, E, F, G, H);
    }

    //update V 
    V[0] = A ^ V[0];
    V[1] = B ^ V[1];
    V[2] = C ^ V[2];
    V[3] = D ^ V[3];
    V[4] = E ^ V[4];
    V[5] = F ^ V[5];
    V[6] = G ^ V[6];
    V[7] = H ^ V[7];
}


/******************************************************************************
  Function:       BigEndian
  Description:    大端,高字节存放在低地址,低字节存放在高地址
  Calls:
  Called By:      SM3_compress, SM3_done
  Input:          src[bytelen]
                  bytelen
  Output:         des[bytelen]
  Return:         null
  Others:         src and des could implies the same address
*******************************************************************************/
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[])
{
    unsigned char tmp = 0;
    unsigned int i = 0;

    for (i = 0; i < bytelen / 4; i++)
    {
        tmp = des[4 * i];
        des[4 * i] = src[4 * i + 3];
        src[4 * i + 3] = tmp;

        tmp = des[4 * i + 1];
        des[4 * i + 1] = src[4 * i + 2];
        des[4 * i + 2] = tmp;
    }
}


/******************************************************************************
  Function:       SM3_init
  Description:    initiate SM3 state
  Calls:
  Called By:      SM3_256
  Input:          SM3_STATE *md
  Output:         SM3_STATE *md
  Return:         null
  Others:
*******************************************************************************/
void SM3_init(SM3_STATE* md)
{
    //将IV存于md->state中,即V中
    md->curlen = md->length = 0;
    md->state[0] = SM3_IVA;
    md->state[1] = SM3_IVB;
    md->state[2] = SM3_IVC;
    md->state[3] = SM3_IVD;
    md->state[4] = SM3_IVE;
    md->state[5] = SM3_IVF;
    md->state[6] = SM3_IVG;
    md->state[7] = SM3_IVH;
}


/******************************************************************************
  Function:       SM3_compress
  Description:    compress a single block of message
  Calls:          BigEndian
                  BiToW
                  WToW1
                  CF
  Called By:      SM3_256
  Input:          SM3_STATE *md
  Output:         SM3_STATE *md
  Return:         null
  Others:
*******************************************************************************/
void SM3_compress(SM3_STATE* md)
{
    //将消息分组B[i]扩展生成132个消息字W0,W1,...,W67,W'0,W'1,...,W'63
    unsigned int W[68];  //存储W
    unsigned int W1[64]; //存储W'

    //字存储为大端格式,坐标为高有效位,右边为低有效位 
    BigEndian(md->buf, 64, md->buf);

    //消息扩展
    printf("\n\n扩展后的消息:");
    printf("\n\n*******W0,W1,...,W67*******:\n");
    BiToW((unsigned int*)md->buf, W);
    printf("\n\n*******W'0,W'1,...,W'63*******:\n");
    WToW1(W, W1);

    //压缩函数(W,W1,V[i])
    CF(W, W1, md->state);
}

/******************************************************************************
  Function:       SM3_process
  Description:    compress the first (len/64) blocks of message【迭代过程】
  Calls:          SM3_compress
  Called By:      SM3_256
  Input:          SM3_STATE *md
                  unsigned char buf[len]  //the input message
                  int len                 //bytelen of message
  Output:         SM3_STATE *md
  Return:         null
  Others:
*******************************************************************************/
void SM3_process(SM3_STATE* md, unsigned char* buf, int len)
{
    //将填充后的消息m'按512比特进行分组为B0,B1,...,Bn-1
    int n = 1;//消息分组的个数
    while (len--)
    {
        /* copy byte */
        md->buf[md->curlen] = *buf++;
        md->curlen++;
        
        /* is 64 bytes full?  即是否是512比特为一组*/
        if (md->curlen == 64)
        {
            printf("\n\n第%d个消息分组:\n\n",n);
            SM3_compress(md);
            md->length += 512;
            n++;
            md->curlen = 0;
        }
    }
}


/******************************************************************************
  Function:       SM3_done
  Description:    compress the rest message that the SM3_process has left behind
  Calls:          SM3_compress
  Called By:      SM3_256
  Input:          SM3_STATE *md
  Output:         unsigned char *hash
  Return:         null
  Others:
*******************************************************************************/
void SM3_done(SM3_STATE* md, unsigned char hash[])
{
    int i,count=1;
    unsigned char tmp = 0;

    /* increase the bit length of the message 增长1字节的长度*/
    md->length += md->curlen << 3;

    /* append the '1' bit 首先将比特'1'添加到消息的末尾*/
    md->buf[md->curlen] = 0x80;
    md->curlen++;

    /* if the length is currently above 56 bytes, appends zeros till
       it reaches 64 bytes, compress the current block, creat a new
       block by appending zeros and length,and then compress it
       若当前长度超过56字节(512比特),则添加0直到64字节,然后迭代压缩
     */
    if (md->curlen > 56)
    {
        for (; md->curlen < 64;)
        {
            md->buf[md->curlen] = 0;
            md->curlen++;
        }
        //64字节为一组进行迭代压缩
        SM3_compress(md);
        //长度置0,重新创建新块
        md->curlen = 0;
    }

    /* if the length is less than 56 bytes, pad upto 56 bytes of zeroes
       若长度小于56字节,则填充0至56个字节
    */
    for (; md->curlen < 56;)
    {
        md->buf[md->curlen] = 0;
        md->curlen++;
    }

    /* since all messages are under 2^32 bits we mark the top bits zero
       由于所有消息都在2^32位以下,故将最高位标记为0
    */
    for (i = 56; i < 60; i++)
    {
        md->buf[i] = 0;
    }

    /* append length 添加一个64比特串,该比特串是长度为l的二进制表示*/
    md->buf[63] = md->length & 0xff;
    md->buf[62] = (md->length >> 8) & 0xff;
    md->buf[61] = (md->length >> 16) & 0xff;
    md->buf[60] = (md->length >> 24) & 0xff;

    printf("\n*******填充后的消息*******:\n");
    inputChar(md->buf, 64);

    SM3_compress(md);

    /* copy output */
    memcpy(hash, md->state, SM3_len / 8);
    //if CPU uses little-endian, BigEndian function is a necessary call
    BigEndian(hash, SM3_len / 8, hash);   
}


/******************************************************************************
  Function:       SM3_256
  Description:    calculate a hash value from a given message
  Calls:          SM3_init
                  SM3_process
                  SM3_done
  Called By:
  Input:          unsigned char buf[len]  //the input message
                  int len                 //bytelen of the message
  Output:         unsigned char hash[32]
  Return:         null
  Others:
*******************************************************************************/
void SM3_256(unsigned char buf[], int len, unsigned char hash[])
{
    SM3_STATE md;
    SM3_init(&md);
    SM3_process(&md, buf, len);
    SM3_done(&md, hash);
}

/******************************************************************************
  Function:       SM3_SelfTest
  Description:    test whether the SM3 calculation is correct by comparing
                  the hash result with the standard result
  Calls:          SM3_256
  Called By:
  Input:          null
  Output:         null
  Return:         0      //the SM3 operation is correct
                  1      //the sm3 operation is wrong
  Others:
*******************************************************************************/
void SM3_SelfTest()
{
    unsigned int i = 0, a = 1, b = 1;
    int choose;
    printf("请选择输入示例:1.示例1\t\t2.示例2\n");
    scanf("%d", &choose);

    if (choose == 1)
    {
        //示例1
        unsigned char Msg1[3] = { 0x61,0x62,0x63 };// ASCII码
        int MsgLen1 = 3;
		unsigned char MsgHash1[32] = { 0 }; //生成的Hash值
        printf("\n*******输入的字符串消息*******:\n");
        inputChar(Msg1, MsgLen1);
        
        /*
        unsigned char StdHash1[32] = { 0x66,0xC7,0xF0,0xF4,0x62,0xEE,0xED,0xD9,0xD1,0xF2,0xD4,0x6B,0xDC,0x10,0xE4,0xE2,
            0x41,0x67,0xC4,0x87,0x5C,0xF2,0xF7,0xA2,0x29,0x7D,0xA0,0x2B,0x8F,0x4B,0xA8,0xE0 };//已经计算好的Hash值
        */
        SM3_256(Msg1, MsgLen1, MsgHash1);
        printf("\n*******输出杂凑值*******:\n");
        inputChar(MsgHash1, 32);
    }
    else if (choose == 2)
    {
        //示例2
        unsigned char Msg2[64] = { 0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
            0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
            0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
            0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64 };// ASCII码
        int MsgLen2 = 64;
		unsigned char MsgHash2[32] = { 0 };//生成的Hash值
        printf("\n*******输入的字符串消息*******:\n");
        inputChar(Msg2, MsgLen2);
        
        /*
        unsigned char StdHash2[32] = { 0xde,0xbe,0x9f,0xf9,0x22,0x75,0xb8,0xa1,0x38,0x60,0x48,0x89,0xc1,0x8e,0x5a,0x4d,
            0x6f,0xdb,0x70,0xe5,0x38,0x7e,0x57,0x65,0x29,0x3d,0xcb,0xa3,0x9c,0x0c,0x57,0x32 };//已经计算好的Hash值
        */
        SM3_256(Msg2, MsgLen2, MsgHash2);
        printf("\n*******输出杂凑值*******:\n");
        inputChar(MsgHash2, 32);
    }
    else
        printf("输入错误,请重新输入!\n");

    //比较是否相同
    /*
    a = memcmp(MsgHash1, StdHash1, SM3_len / 8); 
    b = memcmp(MsgHash2, StdHash2, SM3_len / 8);
  
    if ((a == 0) && (b == 0))
    {
        return 0;
    }
    else
    {
        return 1;
    }
    */
}


int main()
{
    printf("*********************************************************\n");
    printf("*\t\t\tSM3密码杂凑算法\t\t\t*\n");
    printf("*********************************************************\n\n");
    SM3_SelfTest();
    printf("\n");
    system("pause");
    return 0;
}

openSSL中提取

参考:SM3算法 C语言 (从OpenSSL库中分离算法:六)

 

#include <iostream>
#include "sm3/sm3.h"
int main()
{
    SM3_CTX SMC;
    ossl_sm3_init(&SMC);

    const unsigned char Data[1024] = "Hello World";
    unsigned char md[SM3_DIGEST_LENGTH] = { 0 };

    printf("input message:%s\n",Data);
    ossl_sm3_update(&SMC, Data, strlen((const char *) Data));
    ossl_sm3_final(md, &SMC);

    printf("output hash value:");
    for (int i = 0; i < SM3_DIGEST_LENGTH; i++) {
        printf("%02x ", *(md + i));
    }
}

注:代码见github

参考

1、国标-SM3

2、商用密码检测中心-源码下载

3、密码学-基础理论与应用(李子臣著)

posted @ 2021-05-08 21:55  PamShao  阅读(1101)  评论(0编辑  收藏  举报