原味的SM3密码杂凑算法

  根据国家密码管理局官网发布的规范文档里的算法描述,对SM3密码杂凑算法进行了原汁原味的实现。代码里的函数、变量名称都尽量使用算法描述中的名称,尽量遵循算法描述的原始步骤,不使用算法技巧进行处理。

    算法描述里的“位”的存储在程序中用字节来存储,因此代码里会有这样的写法:unsigned char Vi[256/8],表示Vi为256位(存储为256/8字节)的意思,而对等的 unsigned char Vi[32] 则表示Vi为32字节。

    算法描述里的“字”是32字节,用 unsigned long 表示。

    最后的函数 void SM3Hash(unsigned char* m, int ml, unsigned char r[32]) 为算法主体,参数 m 是原始数据,ml 是数据长度,r 是返回值。

    本算法通过了官方文档附录里的示例验证。

#include <memory>

 

unsigned char IV[256 / 8] = { 0x73,0x80,0x16,0x6f,0x49,0x14,0xb2,0xb9,0x17,0x24,0x42,0xd7,0xda,0x8a,0x06,0x00,0xa9,0x6f,0x30,0xbc,0x16,0x31,0x38,0xaa,0xe3,0x8d,0xee,0x4d,0xb0,0xfb,0x0e,0x4e };

// 循环左移
unsigned long SL(unsigned long X, int n)
{
    unsigned __int64 x = X;
    x = x << (n % 32);
    unsigned long l = (unsigned long)(x >> 32);
    return x | l;
}

unsigned long Tj(int j)
{
    if (j <= 15)
    {
        return 0x79cc4519;
    }
    else
    {
        return 0x7a879d8a;
    }
}

unsigned long FFj(int j, unsigned long X, unsigned long Y, unsigned long Z)
{
    if (j <= 15)
    {
        return X ^ Y ^ Z;
    }
    else
    {
        return (X & Y) | (X & Z) | (Y & Z);
    }
}

unsigned long GGj(int j, unsigned long X, unsigned long Y, unsigned long Z)
{
    if (j <= 15)
    {
        return X ^ Y ^ Z;
    }
    else
    {
        return (X & Y) | (~X & Z);
    }
}

unsigned long P0(unsigned long X)
{
    return X ^ SL(X, 9) ^ SL(X, 17);
}

unsigned long P1(unsigned long X)
{
    return X ^ SL(X, 15) ^ SL(X, 23);
}

// 扩展
void EB(unsigned char Bi[512 / 8], unsigned long W[68], unsigned long W1[64])
{
    // Bi 分为W0~W15
    for (int i = 0; i < 16; ++i)
    {
        W[i] = Bi[i * 4] << 24 | Bi[i * 4 + 1] << 16 | Bi[i * 4 + 2] << 8 | Bi[i * 4 + 3];
    }

    for (int j = 16; j <= 67; ++j)
    {
        W[j] = P1(W[j - 16] ^ W[j - 9] ^ SL(W[j - 3], 15)) ^ SL(W[j - 13], 7) ^ W[j - 6];
    }

    for (int j = 0; j <= 63; ++j)
    {
        W1[j] = W[j] ^ W[j + 4];
    }
}

// 压缩函数
void CF(unsigned char Vi[256 / 8], unsigned char Bi[512 / 8], unsigned char Vi1[256 / 8])
{
    // Bi 扩展为132个字
    unsigned long W[68] = { 0 };
    unsigned long W1[64] = { 0 };

    EB(Bi, W, W1);

    // 串联 ABCDEFGH = Vi
    unsigned long R[8] = { 0 };
    for (int i = 0; i < 8; ++i)
    {
        R[i] = ((unsigned long)Vi[i * 4]) << 24 | ((unsigned long)Vi[i * 4 + 1]) << 16 | ((unsigned long)Vi[i * 4 + 2]) << 8 | ((unsigned long)Vi[i * 4 + 3]);
    }

    unsigned long A = R[0], B = R[1], C = R[2], D = R[3], E = R[4], F = R[5], G = R[6], H = R[7];

    unsigned long SS1, SS2, TT1, TT2;
    for (int j = 0; j <= 63; ++j)
    {
        SS1 = SL(SL(A, 12) + E + SL(Tj(j), j), 7);
        SS2 = SS1 ^ SL(A, 12);
        TT1 = FFj(j, A, B, C) + D + SS2 + W1[j];
        TT2 = GGj(j, E, F, G) + H + SS1 + W[j];
        D = C;
        C = SL(B, 9);
        B = A;
        A = TT1;
        H = G;
        G = SL(F, 19);
        F = E;
        E = P0(TT2);
    }

    // Vi1 = ABCDEFGH 串联
    R[0] = A, R[1] = B, R[2] = C, R[3] = D, R[4] = E, R[5] = F, R[6] = G, R[7] = H;
    for (int i = 0; i < 8; ++i)
    {
        Vi1[i * 4] = (R[i] >> 24) & 0xFF; 
        Vi1[i * 4 + 1] = (R[i] >> 16) & 0xFF;
        Vi1[i * 4 + 2] = (R[i] >> 8) & 0xFF;
        Vi1[i * 4 + 3] = (R[i]) & 0xFF;
    }
    // Vi1 = ABCDEFGH ^ Vi
    for (int i = 0; i < 256 / 8; ++i)
    {
        Vi1[i] ^= Vi[i];
    }
}

void SM3Hash(unsigned char* m, int ml, unsigned char r[32])
{
    int l = ml * 8;
    int k = 448 - 1 - l % 512;// 添加k个0,k 是满足 l + 1 + k ≡ 448mod512 的最小的非负整数
    if (k <= 0)
    {
        k += 512;
    }

    int n = (l + k + 65) / 512;

    int m1l = n * 512 / 8; // 填充后的长度,512位的倍数
    unsigned char* m1 = new unsigned char[m1l];
    memset(m1, 0, m1l);
    memcpy(m1, m, l / 8);

    m1[l / 8] = 0x80; // 消息后补1

    // 再添加一个64位比特串,该比特串是长度l的二进制表示
    unsigned long l1 = l;
    for (int i = 0; i < 64 / 8 && l1 > 0; ++i)
    {
        m1[m1l - 1 - i] = l1 & 0xFF;
        l1 = l1 >> 8;
    }

    //将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)· · · B(n−1),其中n=(l+k+65)/512。
    unsigned char** B = new unsigned char*[n];
    for (int i = 0; i < n; ++i)
    {
        B[i] = new unsigned char[512 / 8];
        memcpy(B[i], m1 + (512 / 8)*i, 512 / 8);
    }

    delete[] m1;

    unsigned char** V = new unsigned char*[n + 1];
    for (int i = 0; i <= n; ++i)
    {
        V[i] = new unsigned char[256 / 8];
        memset(V[i], 0, 256 / 8);
    }

    // 初始化 V0 = VI
    memcpy(V[0], IV, 256/8);

    // 压缩函数,V 与扩展的B
    for (int i = 0; i < n; ++i)
    {
        CF(V[i], B[i], V[i + 1]);
    }

    for (int i=0; i<n; ++i)
    {
        delete[] B[i];
    }
    delete[] B;

    // V[n]是结果
    memcpy(r, V[n], 32);

    for (int i=0; i<n+1; ++i)
    {
        delete[] V[i];
    }
    delete[] V;
}
 

 

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值