国密复习

复习 · 浏览次数 : 582

小编点评

```c #include #include #include #include #include #define SM3_len 32 int main() { int tmp, i; big ke, x, y; zzn12 g1, g2, g3; int a1[128], b1[128], a2[128], b2[128]; // 主私钥生成 for (i = 0; i <32; i++) printf("%02x", KE[i]); printf("\n"); for (i = 0; i<64; i++) printf("%02x", Ppub[i]); // 用户A私钥生成 for (i = 0; i<128; i++) printf("%02x", deA[i]); // 用户B私钥生成 for (i = 0; i<128; i++) printf("%02x", deB[i]); // SM9 密钥交换 printf("\n"); printf("\////////////////// SM9 密钥交换 A1-A4 ////////////////////\n"); for (i = 0; i <32; i++) printf("%02x", xy[i]); printf("\n"); printf("\////////////////// SM9 密钥交换 B1-B7 ////////////////////\n"); for (i = 0; i <32; i++) printf("%02x", xy[i + 32]); // SM9 密钥交换 II printf("\n"); printf("\////////////////// SM9 密钥交换 A5-A8 ////////////////////\n"); for (i = 0; i <32; i++) printf("%02x", SA[i]); printf("\n"); printf("\////////////////// SM9 密钥交换 B8 ////////////////////\n"); for (i = 0; i <32; i++) printf("%02x", SB[i + 32]); return 0; } ```

正文

国密复习

img
image

其中SM1和SM7是不公开的。

ZUC

ZUC(ZU Chong zhi)算法一个流密码(序列密码),主要功能是产生密钥流,可以用机密性和完整性验证

初始密钥 初始向量 输出(每次) 轮数
128bit 128bit 32bit 32轮

密钥流生成

密钥流生成算法是核心,主要分为两个阶段:初始化阶段和工作阶段

算法从流程上分为上下三层:16级的线性反馈移位寄存器(LFSR)、比特重组(BR)和非线性函数(F)

ZUC-算法结构

  • LFSR

分为两个模式:初始化模式和工作模式

(1)初始化模式

LSFR接收一个31bit的\(u\),其中\(u\)是非线性函数\(F\)的32bit的输出\(W\)通过舍弃最低位得到的,即\(u=W>>1\)

\(LFSRWithInitialisation(u)\)

{

image-20221018212343942

}

(2)工作模式

该模式下,LSFR没有输入:

$LFSRWithWorkMode() $

{

image-20221018212623036

}

  • 比特重组BR

从LSFR中的16个寄存器中抽取128bit组成的4个32bit的\(X_0,X_1,X_2,X_3\),其中\(X_0,X_1,X_2\)用于下面的非线性函数\(F\)\(X_3\)用于密钥流生成。

\(BitReconstruction()\)

{

image-20221018211216142

}

其中,对于每个\(i\)\(s_i\)是31bit,所以\(s_{iH}\)是取\(s_i\)的第30bit到第15比特

  • F函数

\(F\)中包含两个32bit的存储单元\(R_1\)\(R_2\),输入的是来自比特重组的3个32bit的\(X_0,X_1,X_2\),输出的是一个32bit的\(W\),实际上\(F\)函数就是一个把96bit压缩为32bit的一个非线性压缩函数:

\(F(X_0,X_1,X_2)\)

{
image-20221018212004201

}

其中\(S()\)是非线性S盒变换【混淆】,与AES和SM4一样,都是取前4bit为行,后4bit为列,且这里输入的32bit,需要经过4个S盒,即\(S=(S_0,S_1,S_0,S_1)\);另外\(L()\)是循环左移【扩散】:

image-20221018211432667

初始化阶段

  • 密钥装载

输入的128bit的初始密钥\(k\)128bit的初始向量\(IV\)扩展为16个31bit长的整数,作为LFSR寄存器单元\(s_0,...,s_{15}\)的初始值

\(k\)\(IV\)表示为\(k=k_{0}|| k_{1}|| \cdots|| k_{15}\)\(\mathrm{IV}=\mathrm{iv}_{0}|| \mathrm{iv}_{1}|| \cdots \cdots|| \mathrm{iv}_{15}\),其中\(k_i\)\(iv_i\)均是8bit

对于常量\(D=d_{0}\left\|d_{1}\right\| \cdots \| d_{15}\)(240bit),即分为16个15bit的子串:

image-20221018204115156

下面构造扩展出16个31bit的整数\(s_{i}=k_{i}\left\|d_{i}\right\| i v_{i}\)

image-20221018204324989

  • 经过密钥重载后,LFSR中的16个寄存器中都有初始值,作为LFSR的初始状态,并将非线性函数\(F\)中的32bit存储单元\(R_1\)\(R_2\)全部初始化为0。
  • 然后重复执行一下过程32次:
(1)BitReconstruction()  //比特重组
(2)W=F(X_0,X_1,X_2)	//F函数
(3)LFSRWithInitialisation(u) //LFSR中的初始化模式,更新16个寄存器的值

工作阶段

初始化后,首先执行以下过程,并将\(F\)的输出丢弃:

(1)BitReconstruction()  //比特重组
(2)F(X_0,X_1,X_2)	//F函数
(3)LFSRWithWorkMode() //LFSR中的工作模式,更新16个寄存器的值

然后进行密钥输出阶段,以下过程每执行一次就输出一个32bit的密钥\(Z\)

(1)BitReconstruction()  //比特重组
(2)Z=F(X_0,X_1,X_2) ^ X_3	//F函数
(3)LFSRWithWorkMode() //LFSR中的工作模式,更新16个寄存器的值

程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef unsigned char uint8;
typedef unsigned int uint32;

uint8 S0[256] = {
        0x3e, 0x72, 0x5b, 0x47, 0xca, 0xe0, 0x00, 0x33, 0x04, 0xd1, 0x54, 0x98, 0x09, 0xb9, 0x6d, 0xcb,
        0x7b, 0x1b, 0xf9, 0x32, 0xaf, 0x9d, 0x6a, 0xa5, 0xb8, 0x2d, 0xfc, 0x1d, 0x08, 0x53, 0x03, 0x90,
        0x4d, 0x4e, 0x84, 0x99, 0xe4, 0xce, 0xd9, 0x91, 0xdd, 0xb6, 0x85, 0x48, 0x8b, 0x29, 0x6e, 0xac,
        0xcd, 0xc1, 0xf8, 0x1e, 0x73, 0x43, 0x69, 0xc6, 0xb5, 0xbd, 0xfd, 0x39, 0x63, 0x20, 0xd4, 0x38,
        0x76, 0x7d, 0xb2, 0xa7, 0xcf, 0xed, 0x57, 0xc5, 0xf3, 0x2c, 0xbb, 0x14, 0x21, 0x06, 0x55, 0x9b,
        0xe3, 0xef, 0x5e, 0x31, 0x4f, 0x7f, 0x5a, 0xa4, 0x0d, 0x82, 0x51, 0x49, 0x5f, 0xba, 0x58, 0x1c,
        0x4a, 0x16, 0xd5, 0x17, 0xa8, 0x92, 0x24, 0x1f, 0x8c, 0xff, 0xd8, 0xae, 0x2e, 0x01, 0xd3, 0xad,
        0x3b, 0x4b, 0xda, 0x46, 0xeb, 0xc9, 0xde, 0x9a, 0x8f, 0x87, 0xd7, 0x3a, 0x80, 0x6f, 0x2f, 0xc8,
        0xb1, 0xb4, 0x37, 0xf7, 0x0a, 0x22, 0x13, 0x28, 0x7c, 0xcc, 0x3c, 0x89, 0xc7, 0xc3, 0x96, 0x56,
        0x07, 0xbf, 0x7e, 0xf0, 0x0b, 0x2b, 0x97, 0x52, 0x35, 0x41, 0x79, 0x61, 0xa6, 0x4c, 0x10, 0xfe,
        0xbc, 0x26, 0x95, 0x88, 0x8a, 0xb0, 0xa3, 0xfb, 0xc0, 0x18, 0x94, 0xf2, 0xe1, 0xe5, 0xe9, 0x5d,
        0xd0, 0xdc, 0x11, 0x66, 0x64, 0x5c, 0xec, 0x59, 0x42, 0x75, 0x12, 0xf5, 0x74, 0x9c, 0xaa, 0x23,
        0x0e, 0x86, 0xab, 0xbe, 0x2a, 0x02, 0xe7, 0x67, 0xe6, 0x44, 0xa2, 0x6c, 0xc2, 0x93, 0x9f, 0xf1,
        0xf6, 0xfa, 0x36, 0xd2, 0x50, 0x68, 0x9e, 0x62, 0x71, 0x15, 0x3d, 0xd6, 0x40, 0xc4, 0xe2, 0x0f,
        0x8e, 0x83, 0x77, 0x6b, 0x25, 0x05, 0x3f, 0x0c, 0x30, 0xea, 0x70, 0xb7, 0xa1, 0xe8, 0xa9, 0x65,
        0x8d, 0x27, 0x1a, 0xdb, 0x81, 0xb3, 0xa0, 0xf4, 0x45, 0x7a, 0x19, 0xdf, 0xee, 0x78, 0x34, 0x60 };

uint8 S1[256] = {
        0x55, 0xc2, 0x63, 0x71, 0x3b, 0xc8, 0x47, 0x86, 0x9f, 0x3c, 0xda, 0x5b, 0x29, 0xaa, 0xfd, 0x77,
        0x8c, 0xc5, 0x94, 0x0c, 0xa6, 0x1a, 0x13, 0x00, 0xe3, 0xa8, 0x16, 0x72, 0x40, 0xf9, 0xf8, 0x42,
        0x44, 0x26, 0x68, 0x96, 0x81, 0xd9, 0x45, 0x3e, 0x10, 0x76, 0xc6, 0xa7, 0x8b, 0x39, 0x43, 0xe1,
        0x3a, 0xb5, 0x56, 0x2a, 0xc0, 0x6d, 0xb3, 0x05, 0x22, 0x66, 0xbf, 0xdc, 0x0b, 0xfa, 0x62, 0x48,
        0xdd, 0x20, 0x11, 0x06, 0x36, 0xc9, 0xc1, 0xcf, 0xf6, 0x27, 0x52, 0xbb, 0x69, 0xf5, 0xd4, 0x87,
        0x7f, 0x84, 0x4c, 0xd2, 0x9c, 0x57, 0xa4, 0xbc, 0x4f, 0x9a, 0xdf, 0xfe, 0xd6, 0x8d, 0x7a, 0xeb,
        0x2b, 0x53, 0xd8, 0x5c, 0xa1, 0x14, 0x17, 0xfb, 0x23, 0xd5, 0x7d, 0x30, 0x67, 0x73, 0x08, 0x09,
        0xee, 0xb7, 0x70, 0x3f, 0x61, 0xb2, 0x19, 0x8e, 0x4e, 0xe5, 0x4b, 0x93, 0x8f, 0x5d, 0xdb, 0xa9,
        0xad, 0xf1, 0xae, 0x2e, 0xcb, 0x0d, 0xfc, 0xf4, 0x2d, 0x46, 0x6e, 0x1d, 0x97, 0xe8, 0xd1, 0xe9,
        0x4d, 0x37, 0xa5, 0x75, 0x5e, 0x83, 0x9e, 0xab, 0x82, 0x9d, 0xb9, 0x1c, 0xe0, 0xcd, 0x49, 0x89,
        0x01, 0xb6, 0xbd, 0x58, 0x24, 0xa2, 0x5f, 0x38, 0x78, 0x99, 0x15, 0x90, 0x50, 0xb8, 0x95, 0xe4,
        0xd0, 0x91, 0xc7, 0xce, 0xed, 0x0f, 0xb4, 0x6f, 0xa0, 0xcc, 0xf0, 0x02, 0x4a, 0x79, 0xc3, 0xde,
        0xa3, 0xef, 0xea, 0x51, 0xe6, 0x6b, 0x18, 0xec, 0x1b, 0x2c, 0x80, 0xf7, 0x74, 0xe7, 0xff, 0x21,
        0x5a, 0x6a, 0x54, 0x1e, 0x41, 0x31, 0x92, 0x35, 0xc4, 0x33, 0x07, 0x0a, 0xba, 0x7e, 0x0e, 0x34,
        0x88, 0xb1, 0x98, 0x7c, 0xf3, 0x3d, 0x60, 0x6c, 0x7b, 0xca, 0xd3, 0x1f, 0x32, 0x65, 0x04, 0x28,
        0x64, 0xbe, 0x85, 0x9b, 0x2f, 0x59, 0x8a, 0xd7, 0xb0, 0x25, 0xac, 0xaf, 0x12, 0x03, 0xe2, 0xf2 };

uint32 D[16] = {
        0x44d7, 0x26bc, 0x626b, 0x135e, 0x5789, 0x35e2, 0x7135, 0x09af,
        0x4d78, 0x2f13, 0x6bc4, 0x1af1, 0x5e26, 0x3c4d, 0x789a, 0x47ac };

uint32 LFSR[16] = { 0 };
uint32 X[4] = { 0 };
uint32 R1 = 0, R2 = 0;
uint32 W = 0;

uint32 mod_add(uint32 a, uint32 b);
uint32 mod_2exp_mul(uint32 x, int exp);
void LFSRWithInitMode(uint32 u);
void LFSRWithWorkMode();
void BitReconstruction();

uint32 mod_add(uint32 a, uint32 b)
{
    uint32 c = a + b;
    c = (c & 0x7fffffff) + (c >> 31);
    return c;
}

uint32 mod_2exp_mul(uint32 x, int exp)
{
    return ((x << exp) | (x >> (31 - exp))) & 0x7fffffff;
}

uint32 Rot(uint32 x, int move)
{
    return ((x << move) | (x >> (32 - move)));
}

//LFSR初始化模式
void LFSRWithInitMode(uint32 u)
{
    uint32 v = 0, tmp = 0, i = 0;

    v = LFSR[0];
    tmp = mod_2exp_mul(LFSR[0], 8);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[4], 20);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[10], 21);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[13], 17);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[15], 15);
    v = mod_add(v, tmp);

    v = mod_add(v, u);
    if (v == 0)
        v = 0x7fffffff;

    for (i = 0; i < 15; i++)
        LFSR[i] = LFSR[i + 1];
    LFSR[15] = v;
}

//LFSR工作模式
void LFSRWithWorkMode()
{
    uint32 v = 0, tmp = 0, i = 0;

    v = LFSR[0];
    tmp = mod_2exp_mul(LFSR[0], 8);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[4], 20);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[10], 21);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[13], 17);
    v = mod_add(v, tmp);

    tmp = mod_2exp_mul(LFSR[15], 15);
    v = mod_add(v, tmp);

    if (v == 0)
        v = 0x7fffffff;

    for (i = 0; i < 15; i++)
        LFSR[i] = LFSR[i + 1];
    LFSR[15] = v;
}

void BitReconstruction()
{
    X[0] = ((LFSR[15] & 0x7fff8000) << 1) | (LFSR[14] & 0xffff);
    X[1] = (LFSR[11] << 16) | (LFSR[9] >> 15);
    X[2] = (LFSR[7] << 16) | (LFSR[5] >> 15);
    X[3] = (LFSR[2] << 16) | (LFSR[0] >> 15);
}

uint32 L1(uint32 x)
{
    return (x ^ Rot(x, 2) ^ Rot(x, 10) ^ Rot(x, 18) ^ Rot(x, 24));
}

uint32 L2(uint32 x)
{
    return (x ^ Rot(x, 8) ^ Rot(x, 14) ^ Rot(x, 22) ^ Rot(x, 30));
}

uint32 S(uint32 a)
{
    uint8 x[4] = { 0 }, y[4] = { 0 };
    uint32 b = 0;
    int i = 0, row = 0, line = 0;
    x[0] = a >> 24;
    x[1] = (a >> 16) & 0xff;
    x[2] = (a >> 8) & 0xff;
    x[3] = a & 0xff;
    for (i = 0; i < 4; i++)
    {
        //row = x[i] >> 4;
        //line = x[i] & 0xf;
        if (i == 0 || i == 2)
            y[i] = S0[x[i]];
        else
            y[i] = S1[x[i]];
    }
    b = (y[0] << 24) | (y[1] << 16) | (y[2] << 8) | y[3];
    return b;
}

void F()
{
    uint32 W1 = 0, W2 = 0;
    uint32 tmp1 = 0, tmp2 = 0;
    W = (X[0] ^ R1) + R2;
    W1 = R1 + X[1];
    W2 = R2 ^ X[2];
    R1 = S(L1((W1 << 16) | (W2 >> 16)));
    R2 = S(L2((W2 << 16) | (W1 >> 16)));
}

//密钥装载
void Key_IV_Insert(uint8* k, uint8* iv)
{
    int i = 0;
    printf("\ninitial state of LFSR: S[0]-S[15]\n");
    for (i = 0; i < 16; i++)
    {
        LFSR[i] = (k[i] << 23) | (D[i] << 8) | iv[i]; //s_i=k_i || d_i || iv_i
        printf("%08x  ", LFSR[i]);
    }
}

void Init(uint8* k, uint8* iv)
{
    Key_IV_Insert(k, iv); //密钥装载,初始化LFSR
    R1 = R2 = 0; //初始化存储单元R_1,R_2
    uint32 i = 0;
    //初始化
    for (i = 0; i < 32; i++)
    {
        BitReconstruction();
        F(X[0], X[1], X[2]);
        LFSRWithInitMode(W >> 1);
    }
    printf("\n------------------------------------------------------------\nstate of LFSR after executing initialization: S[0]-S[15]\n");
    for (i = 0; i < 16; i++)
    {
        printf("%08x  ", LFSR[i]);
    }
    printf("\n------------------------------------------------------------\ninternal state of Finite State Machine:\n");
    printf("R1=%08x\n", R1);
    printf("R2=%08x\n", R2);
}

//工作阶段
uint32* KeyStream_Generator(int keylen)
{
    uint32 Z = 0, i = 0;
    uint32* keystream = (uint32*)malloc(keylen * sizeof(uint32));
    BitReconstruction();
    F(X[0], X[1], X[2]);  //将F的输出W丢弃
    LFSRWithWorkMode();
    //密钥输出阶段
    for (i = 0; i < keylen; i++)
    {
        BitReconstruction();
        F(X[0], X[1], X[2]);
        keystream[i] = W ^ X[3]; //一次密钥流生成
        LFSRWithWorkMode();
    }
    return keystream;
}

int main()
{
    int i = 0, keylen = 0;
    uint8 key[16] = { 0 };
    uint8 iv[16] = { 0 };

    char k[50] = { 0 };
    char v[50] = { 0 };
    char tmp[2] = { 0 };
    printf("key: ");
    scanf("%s", k);
    printf("iv: ");
    scanf("%s", v);
    printf("keylen : ");
    scanf("%d", &keylen);
    for (i = 0; i < 16; i++)
    {
        key[i] = (((k[2 * i] <= '9') ? (k[2 * i] - '0') : (k[2 * i] - 'a' + 10)) << 4) +
                 ((k[2 * i + 1] <= '9') ? (k[2 * i + 1] - '0') : (k[2 * i + 1] - 'a' + 10));
        iv[i] = (((v[2 * i] <= '9') ? (v[2 * i] - '0') : (v[2 * i] - 'a' + 10)) << 4) +
                ((v[2 * i + 1] <= '9') ? (v[2 * i + 1] - '0') : (v[2 * i + 1] - 'a' + 10));
    }

    Init(key, iv);
    uint32* keylist = KeyStream_Generator(keylen);
    printf("\n输出密钥流:\n");
    for (i = 0; i < keylen; i++)
    {
        printf("KeyStream[%d]=%08x\n",i,keylist[i]);
    }
    printf("\n");
    return 0;
}

image-20221018213955393

机密性

ZUC-128加密算法,主要用于新一代宽带无线移动通信系统的国际标准(4G标准)中的加解密。

  • 输入

image-20221018215317491

  • 输出

image-20221018215328828

算法

加密算法分为三步:初始化、密钥流生成和加解密:

image-20221018215419130

  • 初始化

根据密钥\(CK\)和其他输入参数构造初始密钥\(k\)和初始向量\(IV\)

image-20221018215925818

image-20221018215941537

  • 密钥流生成

image-20221018220032605

  • 加解密

image-20221018220113832

完整性

完整性验证类似于Hash,对消息生成一个唯一的MAC码。

  • 输入

image-20221018221404538

  • 输出

image-20221018221417281

算法

算法核心就是为消息生成一个唯一的认证码,主要分为:初始化、密钥流生成和生成消息认证码的过程:

image-20221018221630590

  • 初始化

image-20221018221958411

image-20221018222012468

  • 密钥流生成

image-20221018222144736

  • 生成消息认证码

image-20221018222207507

参考

1、https://www.jiamisoft.com/blog/28206-zuc-jmsf.html

2、https://www.jiamisoft.com/blog/21611-zuc.html

3、https://blog.csdn.net/anonymous_qsh/article/details/120794011

SM2

SM2是一个基于椭圆曲线上的密码算法,其中包含公钥加密算法、数字签名算法和密钥交换算法

SM2算法和ECC算法相比:

  • ECC采用的通常是国际机构推荐的曲线和参数;而SM2的参数是需要算法生成的,且算法中加入了用户特异性的参数曲线,基点和用户公钥信息等,使得SM2算法的安全性提升。
  • ECC中的哈希算法使用的是MD5活着SHA-1,而SM2使用的是SM3,其安全性与SHA-256相当。

SM2算法分为基于素域和基于二元扩域的计算,下面介绍的是基于素域(有限域)计算的。

椭圆曲线公钥密码基于椭圆曲线的性质:

  • 有限域上的椭圆曲线在点加运算下(B=A+C)构成有限交换群,其阶与有限域规模相近
  • 类似于有限域乘法群中的乘幂(\(a=y^b(mod p)\)),椭圆曲线上多倍点运算(B=[k]A)构成一个单项函数

在多倍点运算中,已知多倍点\((B)\)和基点\((A)\),求解倍数\((k)\)问题称为椭圆曲线上的离散对数问题,对于一般椭圆曲线的离散对数问题,目前只存在指数级计算复杂度的求解方法,与大数分解问题及有限域上的离散对数问题相比,椭圆曲线上的离散对数问题的求解难度大的多,因此,在相同安全程度下,椭圆曲线密码较其他公钥密码所需的密钥规模要小得多

SM2算法用到了三个辅助算法:哈希算法(SM3)、密钥派生函数(KDF)和随机数发生器,这三类辅助算法的强弱直接影响到算法的安全性。

  • 哈希算法

使用的SM3,生成256bit的哈希值。

  • 密钥派生函数

就是从一个共享的秘密比特串中派生出密钥,密钥派生函数需要使用哈希函数:

image-20221020112650281

  • 随机数发生器

使用国家发布的随机数发生器。

公钥加密

假设存在两方:A(加密)和B(解密)方。

参数

素域\(F_p\)下SM2算法的参数:

image-20221020101542986

其中比特串\(SEED\)和参数\((a,b)\)的生成如下:

image-20221020101832220

密钥生成

B方生成用户密钥对:私钥\(d_B\)和公钥\(P_B\)

  • \((1,...,n-1)\)中任取一个随机数\(d_B\)作为私钥
  • 计算公钥:\(P_B=d_BG\),其中\(G=(x_G,y_G)\)是基点。

加密

A方要加密的是长度为\(klen\)长的比特串\(M\),这里使用的是公钥\(P_B\)加密的:

image-20221020111812342

其中消息\(M\)不是编码到椭圆曲线上,这里是直接对字符串加密,产生的密文也是字符串,加密流程图如下:

image-20221020111857902

解密

B方收到密文\(C\)后,利用私钥\(d_B\)解密:

image-20221020113320650

加密和解密都需要使用KDF生成密钥\(t\),具体解密流程图如下:

image-20221020113445376

分析

  • 安全性

根据生成的用户公钥\(P_B=d_BG\)得不到私钥\(d_B\),满足椭圆曲线上的离散对数问题

  • 正确性

因为\((x_2,y_2)=d_BC_1\)产生\(t\)\(u\),所以只需证明\((x_2,y_2)=d_BC_1\)

由于\(P_B=d_BG,C_1=kG=(x_1,y_1)\),所以\(d_BC_1=d_BkG=k(d_BG)=kP_B=(x_2,y_2)\)

程序实现

/****************************************************************
  Function:       SM2_ENC_SelfTest
  Description:    test whether the SM2 calculation is correct by comparing the result with the
standard data
  Calls:          SM2_init,SM2_ENC,SM2_DEC
  Called By:
  Input:          NULL
  Output:         NULL
  Return:         0: sucess
                  1: S is a point at finity
                  2: X or Y coordinate is beyond Fq
                  3: not a valid point on curve
                  4: the given point G is not a point of order n
                  5: KDF output is all zero
                  6: C3 does not match
                  8: public key generation error
                  9: SM2 encryption error
                  a: SM2 decryption error

  Others:
****************************************************************/
int SM2_ENC_SelfTest()
{
    int tmp = 0, i = 0;
    unsigned char Cipher[115] = { 0 };
    unsigned char M[19] = { 0 };
    unsigned char kGxy[SM2_NUMWORD * 2] = { 0 };
    big ks, x, y;
    epoint* kG;

    //standard data 
    unsigned char
            std_priKey[32] = { 0x39,0x45,0x20,0x8F,0x7B,0x21,0x44,0xB1,0x3F,0x36,0xE3,0x8A,0xC6,0xD3,0x9F,0x95,
                               0x88,0x93,0x93,0x69,0x28,0x60,0xB5,0x1A,0x42,0xFB,0x81,0xEF,0x4D,0xF7,0xC5,0xB8 };
    unsigned char
            std_pubKey[64] = { 0x09,0xF9,0xDF,0x31,0x1E,0x54,0x21,0xA1,0x50,0xDD,0x7D,0x16,0x1E,0x4B,0xC5,0xC6,
                               0x72,0x17,0x9F,0xAD,0x18,0x33,0xFC,0x07,0x6B,0xB0,0x8F,0xF3,0x56,0xF3,0x50,0x20,
                               0xCC,0xEA,0x49,0x0C,0xE2,0x67,0x75,0xA5,0x2D,0xC6,0xEA,0x71,0x8C,0xC1,0xAA,0x60,
                               0x0A,0xED,0x05,0xFB,0xF3,0x5E,0x08,0x4A,0x66,0x32,0xF6,0x07,0x2D,0xA9,0xAD,0x13 };
    unsigned char
            std_rand[32] = { 0x59,0x27,0x6E,0x27,0xD5,0x06,0x86,0x1A,0x16,0x68,0x0F,0x3A,0xD9,0xC0,0x2D,0xCC,
                             0xEF,0x3C,0xC1,0xFA,0x3C,0xDB,0xE4,0xCE,0x6D,0x54,0xB8,0x0D,0xEA,0xC1,0xBC,0x21 };
    unsigned char
            std_Message[19] = { 0x65,0x6E,0x63,0x72,0x79,0x70,0x74,0x69,0x6F,0x6E,0x20,0x73,0x74,0x61,0x6E,
                                0x64,0x61,0x72,0x64 };
    unsigned char
            std_Cipher[115] = { 0x04,0xEB,0xFC,0x71,0x8E,0x8D,0x17,0x98,0x62,0x04,0x32,0x26,0x8E,0x77,0xFE,
                                0xB6,0x41,0x5E,0x2E,0xDE,0x0E,0x07,0x3C,0x0F,0x4F,0x64,0x0E,0xCD,0x2E,0x14,0x9A,0x73,
                                0xE8,0x58,0xF9,0xD8,0x1E,0x54,0x30,0xA5,0x7B,0x36,0xDA,0xAB,0x8F,0x95,0x0A,0x3C,
                                0x64,0xE6,0xEE,0x6A,0x63,0x09,0x4D,0x99,0x28,0x3A,0xFF,0x76,0x7E,0x12,0x4D,0xF0,
                                0x59,0x98,0x3C,0x18,0xF8,0x09,0xE2,0x62,0x92,0x3C,0x53,0xAE,0xC2,0x95,0xD3,0x03,
                                0x83,0xB5,0x4E,0x39,0xD6,0x09,0xD1,0x60,0xAF,0xCB,0x19,0x08,0xD0,0xBD,0x87,0x66,
                                0x21,0x88,0x6C,0xA9,0x89,0xCA,0x9C,0x7D,0x58,0x08,0x73,0x07,0xCA,0x93,0x09,0x2D,0x65,0x1E,0xFA };

    mip = mirsys(1000, 16);
    mip->IOBASE = 16;
    x = mirvar(0);
    y = mirvar(0);
    ks = mirvar(0);
    kG = epoint_init();
    bytes_to_big(32, std_priKey, ks);  //ks is the standard private key 

    printf(" 待加密的消息M:");
    for (i = 0; i < 19; i++)
    {
        printf("%c", std_Message[i]);
    }
    printf("\n 待加密的消息[十六进制]M:");
    for (i = 0; i < 19; i++)
    {
        printf("%X", std_Message[i]);
    }
    //initiate SM2 curve 
    SM2_Init();

    printf("\n 私钥Db:");
    for (i = 0; i < 32; i++)
    {
        printf("%X", std_priKey[i]);
    }
    printf("\n 公钥Pb=(x,y):");
    printf("\n 坐标X:");
    for (i = 0; i < 32; i++)
    {
        printf("%X", std_pubKey[i]);
    }
    printf("\n 坐标Y:");
    for (i = 32; i < 64; i++)
    {
        printf("%X", std_pubKey[i]);
    }
    printf("\n\n ************************开始加密************************");
    //generate key pair 
    tmp = SM2_KeyGeneration(ks, kG);
    if (tmp != 0)
        return tmp;
    epoint_get(kG, x, y);
    big_to_bytes(SM2_NUMWORD, x, kGxy, 1);
    big_to_bytes(SM2_NUMWORD, y, kGxy + SM2_NUMWORD, 1);
    if (memcmp(kGxy, std_pubKey, SM2_NUMWORD * 2) != 0)
        return ERR_SELFTEST_KG;

    //encrypt data and compare the result with the standard data 
    tmp = SM2_Encrypt(std_rand, kG, std_Message, 19, Cipher);
    if (tmp != 0)
        return tmp;
    if (memcmp(Cipher, std_Cipher, 19 + SM2_NUMWORD * 3) != 0)
        return ERR_SELFTEST_ENC;

    printf("\n\n ************************开始解密************************");
    //decrypt cipher and compare the result with the standard data 
    tmp = SM2_Decrypt(ks, Cipher, 115, M);
    if (tmp != 0)
        return tmp;
    printf("\n\n 明文M':");
    for (i = 0; i < 19; i++)
    {
        printf("%X", M[i]);
    }
    printf("\n 即为:");
    for (i = 0; i < 19; i++)
    {
        printf("%c", M[i]);
    }
    if (memcmp(M, std_Message, 19) != 0)
        return ERR_SELFTEST_DEC;

    return 0;
}

数字签名

image-20221023213322026

参数

基本参数设置与加解密相同,假设签名方为A,验签方为B:

密钥生成

image-20221023212351744

签名

image-20221023212446711

image-20221023212544319

验签

image-20221023212828555

分析

  • 正确性

image-20221023213343227

程序实现

/****************************************************************
  Function:       SM2_SelfCheck
  Description:    SM2 self check
  Calls:          SM2_Init(), SM2_KeyGeneration,SM2_Sign, SM2_Verify,SM3_256()
  Called By:
  Input:
  Output:
  Return:         0: sucess
                  1: paremeter initialization error
                  2: a point at infinity
                  5: X or Y coordinate is beyond Fq
                  3: not a valid point on curve
                  4: not a point of order n
                  B: public key error
                  8: the signed R out of range [1,n-1]
                  9: the signed S out of range [1,n-1]
                  A: the intermediate data t equals 0
                  C: verification fail
  Others:
****************************************************************/
int SM2_SelfCheck()
{
    //the private key
    unsigned char
            dA[32] = { 0x39,0x45,0x20,0x8f,0x7b,0x21,0x44,0xb1,0x3f,0x36,0xe3,0x8a,0xc6,0xd3,0x9f,
                       0x95,0x88,0x93,0x93,0x69,0x28,0x60,0xb5,0x1a,0x42,0xfb,0x81,0xef,0x4d,0xf7,0xc5,0xb8 };

    unsigned char
            rand[32] = { 0x59,0x27,0x6E,0x27,0xD5,0x06,0x86,0x1A,0x16,0x68,0x0F,0x3A,0xD9,0xC0,0x2D,
                         0xCC,0xEF,0x3C,0xC1,0xFA,0x3C,0xDB,0xE4,0xCE,0x6D,0x54,0xB8,0x0D,0xEA,0xC1,0xBC,0x21 };

    //the public key
    /* unsigned char
         xA[32]={0x09,0xf9,0xdf,0x31,0x1e,0x54,0x21,0xa1,0x50,0xdd,0x7d,0x16,0x1e,0x4b,0xc5,
         0xc6,0x72,0x17,0x9f,0xad,0x18,0x33,0xfc,0x07,0x6b,0xb0,0x8f,0xf3,0x56,0xf3,0x50,0x20};
             unsigned char
         yA[32]={0xcc,0xea,0x49,0x0c,0xe2,0x67,0x75,0xa5,0x2d,0xc6,0xea,0x71,0x8c,0xc1,0xaa,
         0x60,0x0a,0xed,0x05,0xfb,0xf3,0x5e,0x08,0x4a,0x66,0x32,0xf6,0x07,0x2d,0xa9,0xad,0x13};*/

    unsigned char xA[32], yA[32];
    unsigned char r[32], s[32];// Signature

    unsigned char IDA[16] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,
                              0x34,0x35,0x36,0x37,0x38 };//ASCII code of userA's identification
    int IDA_len = 16;
    unsigned char ENTLA[2] = { 0x00,0x80 };
    //the length of userA's identification,presentation in  ASCII code

    unsigned char* message = "message digest";//the message to be signed
    int len = strlen(message);//the length of message

    unsigned char ZA[SM3_len / 8];//ZA=Hash(ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA)
    unsigned char Msg[210]; //210=IDA_len+2+SM2_NUMWORD*6

    int temp;

    miracl* mip = mirsys(10000, 16);
    mip->IOBASE = 16;

    temp = SM2_KeyGeneration(dA, xA, yA); // 密钥生成
    if (temp)
        return temp;

    printf(" 待签名的消息M:%s\n", message);

    //生成签名前,使用HASH函数针对消息进行压缩生成 ZA=HASH256(ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA)
    // ENTLA|| IDA|| a|| b|| Gx || Gy || xA|| yA
    memcpy(Msg, ENTLA, 2);
    memcpy(Msg + 2, IDA, IDA_len);
    memcpy(Msg + 2 + IDA_len, SM2_a, SM2_NUMWORD);
    memcpy(Msg + 2 + IDA_len + SM2_NUMWORD, SM2_b, SM2_NUMWORD);
    memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 2, SM2_Gx, SM2_NUMWORD);
    memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 3, SM2_Gy, SM2_NUMWORD);
    memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 4, xA, SM2_NUMWORD);
    memcpy(Msg + 2 + IDA_len + SM2_NUMWORD * 5, yA, SM2_NUMWORD);
    SM3_256(Msg, 210, ZA);
    printf(" 杂凑值ZA:");
    for (int i = 0; i < SM3_len / 8; i++)
    {
        printf("%X", ZA[i]);
    }

    printf("\n\n******************************开始生成签名******************************");
    //生成签名
    temp = SM2_Sign(message, len, ZA, rand, dA, r, s);
    if (temp)
        return temp;

    printf("\n******************************开始验证签名******************************");
    //验证签名
    temp = SM2_Verify(message, len, ZA, xA, yA, r, s);
    if (temp)
        return temp;

    return 0;
}

密钥交换

密钥交换又叫做密钥协商,就是两个用户A和B通过交互的消息传递,用各自的私钥和对方的公钥来商定一个只有他们知道的秘密密钥,这个共享的秘密密钥通常用于对称加密中,密钥交换协议能用于密钥管理和协商

参数

  • 密钥

image-20221025111830549

  • 标识信息

image-20221025111917690

协议

用户A为发起方,用户B为响应方,协商获得的秘密密钥长度为\(klen\)bit,

  • A
image-20221025112507565
  • B

image-20221025112735620

  • A

image-20221025113156416

  • B

image-20221025113212840

分析

  • 这里使用的密码杂凑算法(KDF)与加密和签名算法所用相同。
  • 通信次数:3次

流程图

image-20221025113319556

程序实现

/****************************************************************
  Function:       SM2_KeyEX_SelfTest
  Description:    self check of SM2 key exchange
  Calls:          SM2_Init, SM3_Z, SM2_KeyEx_Init_I, SM2_KeyEx_Re_I, SM2_KeyEx_Init_II,
SM2_KeyEx_Re_II
  Called By:
  Input:
  Output:
  Return:         0: sucess
                  1:  a point at infinity
                  2: X or Y coordinate is beyond Fq
                  3: not a valid point on curve
                  4: not a point of order n
                  6: RA is not valid
                  7:  RB is not valid
                  8:  key validation failed,form B to A,S1!=SB
                  A: the hash value Z error,Z=hash(ELAN||ID||a ||b||Gx||Gy||Px||Py)
                  B: initialization I failed
                  C; the shared key KA error,self check failed
                  D; the shared key KB error,self check failed
                  9: key validation failed,form A to B,S2!=SA
  Others:
****************************************************************/
int SM2_KeyEX_SelfTest()
{
    //standard data
    unsigned char
            std_priKeyA[SM2_NUMWORD] = { 0x81,0xEB,0x26,0xE9,0x41,0xBB,0x5A,0xF1,0x6D,0xF1,0x16,0x49,0x5F,0x90,
                                         0x69,0x52,0x72,0xAE,0x2C,0xD6,0x3D,0x6C,0x4A,0xE1,0x67,0x84,0x18,0xBE,0x48,0x23,0x00,0x29 };
    unsigned char
            std_pubKeyA[SM2_NUMWORD * 2] = { 0x16,0x0E,0x12,0x89,0x7D,0xF4,0xED,0xB6,0x1D,0xD8,0x12,0xFE,0xB9
            ,0x67,0x48,0xFB,
                                             0xD3,0xCC,0xF4,0xFF,0xE2,0x6A,0xA6,0xF6,0xDB,0x95,0x40,0xAF,0x49,0xC9,0x42,0x32,
                                             0x4A,0x7D,0xAD,0x08,0xBB,0x9A,0x45,0x95,0x31,0x69,0x4B,0xEB,0x20,0xAA,0x48,0x9D,
                                             0x66,0x49,0x97,0x5E,0x1B,0xFC,0xF8,0xC4,0x74,0x1B,0x78,0xB4,0xB2,0x23,0x00,0x7F };
    unsigned char std_randA[SM2_NUMWORD] =
            { 0xD4,0xDE,0x15,0x47,0x4D,0xB7,0x4D,0x06,0x49,0x1C,0x44,0x0D,0x30,0x5E,0x01,0x24,
              0x00,0x99,0x0F,0x3E,0x39,0x0C,0x7E,0x87,0x15,0x3C,0x12,0xDB,0x2E,0xA6,0x0B,0xB3 };
    unsigned char
            std_priKeyB[SM2_NUMWORD] = { 0x78,0x51,0x29,0x91,0x7D,0x45,0xA9,0xEA,0x54,0x37,0xA5,0x93,0x56,0xB8,0x23,0x38,
                                         0xEA,0xAD,0xDA,0x6C,0xEB,0x19,0x90,0x88,0xF1,0x4A,0xE1,0x0D,0xEF,0xA2,0x29,0xB5 };
    unsigned char
            std_pubKeyB[SM2_NUMWORD * 2] = { 0x6A,0xE8,0x48,0xC5,0x7C,0x53,0xC7,0xB1,0xB5,0xFA,0x99,0xEB,0x22
            ,0x86,0xAF,0x07,
                                             0x8B,0xA6,0x4C,0x64,0x59,0x1B,0x8B,0x56,0x6F,0x73,0x57,0xD5,0x76,0xF1,0x6D,0xFB,
                                             0xEE,0x48,0x9D,0x77,0x16,0x21,0xA2,0x7B,0x36,0xC5,0xC7,0x99,0x20,0x62,0xE9,0xCD,
                                             0x09,0xA9,0x26,0x43,0x86,0xF3,0xFB,0xEA,0x54,0xDF,0xF6,0x93,0x05,0x62,0x1C,0x4D };
    unsigned char std_randB[SM2_NUMWORD] =
            { 0x7E,0x07,0x12,0x48,0x14,0xB3,0x09,0x48,0x91,0x25,0xEA,0xED,0x10,0x11,0x13,0x16,
              0x4E,0xBF,0x0F,0x34,0x58,0xC5,0xBD,0x88,0x33,0x5C,0x1F,0x9D,0x59,0x62,0x43,0xD6 };
    unsigned char
            std_IDA[16] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38
    };
    unsigned char
            std_IDB[16] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38
    };
    unsigned short int std_ENTLA = 0x0080;
    unsigned short int std_ENTLB = 0x0080;
    unsigned char
            std_ZA[SM3_len] = { 0x3B,0x85,0xA5,0x71,0x79,0xE1,0x1E,0x7E,0x51,0x3A,0xA6,0x22,0x99,0x1F,0x2C,
                                0xA7,0x4D,0x18,0x07,0xA0,0xBD,0x4D,0x4B,0x38,0xF9,0x09,0x87,0xA1,0x7A,0xC2,0x45,0xB1 };
    unsigned char
            std_ZB[SM3_len] = { 0x79,0xC9,0x88,0xD6,0x32,0x29,0xD9,0x7E,0xF1,0x9F,0xE0,0x2C,0xA1,0x05,0x6E,
                                0x01,0xE6,0xA7,0x41,0x1E,0xD2,0x46,0x94,0xAA,0x8F,0x83,0x4F,0x4A,0x4A,0xB0,0x22,0xF7 };
    unsigned char
            std_RA[SM2_NUMWORD * 2] = { 0x64,0xCE,0xD1,0xBD,0xBC,0x99,0xD5,0x90,0x04,0x9B,0x43,0x4D,0x0F,0xD7
            ,0x34,0x28,0xCF,0x60,0x8A,0x5D,0xB8,0xFE,0x5C,0xE0,0x7F,0x15,0x02,0x69,0x40,0xBA,0xE4,0x0E,

                                        0x37,0x66,0x29,0xC7,0xAB,0x21,0xE7,0xDB,0x26,0x09,0x22,0x49,0x9D,0xDB,0x11,0x8F,0x07,0xCE,0x8E,0xAA,0xE3,0xE7,0x72,0x0A,0xFE,0xF6,0xA5,0xCC,0x06,0x20,0x70,0xC0 };
    unsigned char
            std_K[16] = { 0x6C,0x89,0x34,0x73,0x54,0xDE,0x24,0x84,0xC6,0x0B,0x4A,0xB1,0xFD,0xE4,0xC6,0xE5 };
    unsigned char std_RB[SM2_NUMWORD * 2] =
            { 0xAC,0xC2,0x76,0x88,0xA6,0xF7,0xB7,0x06,0x09,0x8B,0xC9,0x1F,0xF3,0xAD,0x1B,0xFF,
              0x7D,0xC2,0x80,0x2C,0xDB,0x14,0xCC,0xCC,0xDB,0x0A,0x90,0x47,0x1F,0x9B,0xD7,0x07,
              0x2F,0xED,0xAC,0x04,0x94,0xB2,0xFF,0xC4,0xD6,0x85,0x38,0x76,0xC7,0x9B,0x8F,0x30,
              0x1C,0x65,0x73,0xAD,0x0A,0xA5,0x0F,0x39,0xFC,0x87,0x18,0x1E,0x1A,0x1B,0x46,0xFE };
    unsigned char
            std_SB[SM3_len] = { 0xD3,0xA0,0xFE,0x15,0xDE,0xE1,0x85,0xCE,0xAE,0x90,0x7A,0x6B,0x59,0x5C,0xC3,
                                0x2A,0x26,0x6E,0xD7,0xB3,0x36,0x7E,0x99,0x83,0xA8,0x96,0xDC,0x32,0xFA,0x20,0xF8,0xEB };
    int std_Klen = 128;//bit len
    int temp;

    big x, y, dA, dB, rA, rB;
    epoint* pubKeyA, * pubKeyB, * RA, * RB, * V;

    unsigned char hash[SM3_len / 8] = { 0 };
    unsigned char ZA[SM3_len / 8] = { 0 };
    unsigned char ZB[SM3_len / 8] = { 0 };
    unsigned char xy[SM2_NUMWORD * 2] = { 0 };
    unsigned char* KA, * KB;
    unsigned char SA[SM3_len / 8];


    KA = malloc(std_Klen / 8);
    KB = malloc(std_Klen / 8);

    mip = mirsys(1000, 16);
    mip->IOBASE = 16;

    x = mirvar(0);
    y = mirvar(0);
    dA = mirvar(0);
    dB = mirvar(0);
    rA = mirvar(0);
    rB = mirvar(0);
    pubKeyA = epoint_init();
    pubKeyB = epoint_init();
    RA = epoint_init();
    RB = epoint_init();
    V = epoint_init();
    SM2_Init();

    bytes_to_big(SM2_NUMWORD, std_priKeyA, dA);
    bytes_to_big(SM2_NUMWORD, std_priKeyB, dB);
    bytes_to_big(SM2_NUMWORD, std_randA, rA);
    bytes_to_big(SM2_NUMWORD, std_randB, rB);
    bytes_to_big(SM2_NUMWORD, std_pubKeyA, x);
    bytes_to_big(SM2_NUMWORD, std_pubKeyA + SM2_NUMWORD, y);
    epoint_set(x, y, 0, pubKeyA);
    bytes_to_big(SM2_NUMWORD, std_pubKeyB, x);
    bytes_to_big(SM2_NUMWORD, std_pubKeyB + SM2_NUMWORD, y);
    epoint_set(x, y, 0, pubKeyB);

    printf("\n 用户A的私钥Da:");
    cotnum(dA, stdout);
    printf(" 用户A的公钥Pa=(x,y):");
    printf("\n 坐标x:");
    cotnum(pubKeyA->X, stdout);
    printf(" 坐标y:");
    cotnum(pubKeyA->Y, stdout);

    printf(" 用户B的私钥Db:");
    cotnum(dB, stdout);
    printf(" 用户B的公钥Pb=(x,y):");
    printf("\n 坐标x:");
    cotnum(pubKeyB->X, stdout);
    printf(" 坐标y:");
    cotnum(pubKeyB->Y, stdout);

    SM3_Z(std_IDA, std_ENTLA, pubKeyA, ZA);
    if (memcmp(ZA, std_ZA, SM3_len / 8) != 0)
        return ERR_SELFTEST_Z;
    SM3_Z(std_IDB, std_ENTLB, pubKeyB, ZB);
    if (memcmp(ZB, std_ZB, SM3_len / 8) != 0)
        return ERR_SELFTEST_Z;
    printf("\n 杂凑值ZA:");
    for (int i = 0; i < SM3_len / 8; i++)
    {
        printf("%X", ZA[i]);
    }
    printf("\n 杂凑值ZB:");
    for (int i = 0; i < SM3_len / 8; i++)
    {
        printf("%X", ZB[i]);
    }
    printf("\n\n ************************密钥交换A1-A3************************");

    temp = SM2_KeyEx_Init_I(rA, RA);
    if (temp) return temp;
    printf("\n 产生随机数rA:");
    cotnum(rA, stdout);
    printf(" 计算椭圆曲线RA:");
    printf("\n 坐标x:");
    cotnum(RA->X, stdout);
    printf(" 坐标y:");
    cotnum(RA->Y, stdout);

    epoint_get(RA, x, y);
    big_to_bytes(SM2_NUMWORD, x, xy, 1);
    big_to_bytes(SM2_NUMWORD, y, xy + SM2_NUMWORD, 1);
    if (memcmp(xy, std_RA, SM2_NUMWORD * 2) != 0)
        return ERR_SELFTEST_INI_I;
    printf("\n ************************密钥交换B1-B9************************");
    temp = SM2_KeyEx_Re_I(rB, dB, RA, pubKeyA, ZA, ZB, KA, std_Klen, RB, V, hash);

    if (temp) return temp;
    if (memcmp(KA, std_K, std_Klen / 8) != 0)
        return ERR_SELFTEST_RES_I;
    printf("\n ************************密钥交换A4-A10************************\n");
    temp = SM2_KeyEx_Init_II(rA, dA, RA, RB, pubKeyB, ZA, ZB, hash, KB, std_Klen, SA);
    if (temp) return temp;
    if (memcmp(KB, std_K, std_Klen / 8) != 0)
        return ERR_SELFTEST_INI_II;
    printf("\n ************************密钥交换B10************************");
    if (SM2_KeyEx_Re_II(V, RA, RB, ZA, ZB, SA) != 0)
        return ERR_EQUAL_S2SA;

    free(KA); free(KB);

    return 0;
}

SM3

SM3是国家2010年公布的一种密码哈希算法,该算法能对\(l\)bit的消息hash,生成256bit的哈希值,算法主要分为两步:消息填充和迭代压缩,其中迭代压缩有包含消息扩展、压缩函数和输出哈希值。

image-20221019164653783

  • 用于签名和认证
  • 在SHA-256算法上改进的,安全性与SHA-256相当
  • 迭代过程和消息填充与MD5相似,也采用Merkle-Damgard结构。
分组长度 哈希长度
512bit 256bit

下面是算法用到的常量和函数:

image-20221019164100846

消息填充

image-20221019164411248

\(l\)bit的消息经过消息\(m\)填充后,得到\(m'\)消息的比特数是512的倍数。

迭代压缩

image-20221019165233940

消息扩展

对迭代压缩前消息分组\(B^{i}\)(一个字,512bit)进行扩展得到132个字\(W_0,...,W_{63},W_0',...,W_{63}'\)

image-20221019165537241

image-20221019165652634

压缩函数

\(ABCDEFGH\)是字寄存器(32bit),压缩函数输入的\(V^{(0)}\)是256bit的初始IV,\(B^{(0)}\)是消息扩展后的第一个分组(5125bit),输出的是256bit的\(V^{(1)}\),依次计算直到计算出\(V^{(n)}\),并作为最后的哈希值:

image-20221019202329867

image-20221019202919001

输出哈希值

image-20221019203315397

程序

#include <iostream>
#include <string>
#include <cmath>
using namespace std;

//二进制转换为十六进制函数实现
string BinToHex(string str) {
    string hex = "";//用来存储最后生成的十六进制数
    int temp = 0;//用来存储每次四位二进制数的十进制值
    while (str.size() % 4 != 0) {//因为每四位二进制数就能够成为一个十六进制数,所以将二进制数长度转换为4的倍数
        str = "0" + str;//最高位添0直到长度为4的倍数即可
    }
    for (int i = 0; i < str.size(); i += 4) {
        temp = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + (str[i + 3] - '0') * 1;//判断出4位二进制数的十进制大小为多少
        if (temp < 10) {//当得到的值小于10时,可以直接用0-9来代替
            hex += to_string(temp);
        }
        else {//当得到的值大于10时,需要进行A-F的转换
            hex += 'A' + (temp - 10);
        }
    }
    return hex;
}

//十六进制转换为二进制函数实现
string HexToBin(string str) {
    string bin = "";
    string table[16] = { "0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };
    for (int i = 0; i < str.size(); i++) {
        if (str[i] >= 'A'&&str[i] <= 'F') {
            bin += table[str[i] - 'A' + 10];
        }
        else {
            bin += table[str[i] - '0'];
        }
    }
    return bin;
}

//二进制转换为十进制的函数实现
int BinToDec(string str) {
    int dec = 0;
    for (int i = 0; i < str.size(); i++) {
        dec += (str[i] - '0')*pow(2, str.size() - i - 1);
    }
    return dec;
}

//十进制转换为二进制的函数实现
string DecToBin(int str) {
    string bin = "";
    while (str >= 1) {
        bin = to_string(str % 2) + bin;
        str = str / 2;
    }
    return bin;
}

//十六进制转换为十进制的函数实现
int HexToDec(string str) {
    int dec = 0;
    for (int i = 0; i < str.size(); i++) {
        if (str[i] >= 'A'&&str[i] <= 'F') {
            dec += (str[i] - 'A' + 10)*pow(16, str.size() - i - 1);
        }
        else {
            dec += (str[i] - '0')*pow(16, str.size() - i - 1);
        }
    }
    return dec;
}

//十进制转换为十六进制的函数实现
string DecToHex(int str) {
    string hex = "";
    int temp = 0;
    while (str >= 1) {
        temp = str % 16;
        if (temp < 10 && temp >= 0) {
            hex = to_string(temp) + hex;
        }
        else {
            hex += ('A' + (temp - 10));
        }
        str = str / 16;
    }
    return hex;
}

string padding(string str) {//对数据进行填充
    string res = "";
    for (int i = 0; i < str.size(); i++) {//首先将输入值转换为16进制字符串
        res += DecToHex((int)str[i]);
    }
    cout << "输入字符串的ASCII码表示为:" << endl;
    for (int i = 0; i < res.size(); i++) {
        cout << res[i];
        if ((i + 1) % 8 == 0) {
            cout << "  ";
        }
        if ((i + 1) % 64 == 0 || (i + 1) == res.size()) {
            cout << endl;
        }
    }
    cout << endl;
    //填充方式:先补加1,然后填充0至112位,最后16bit填充0+原来长度(二进制)
    int res_length = res.size() * 4;//记录的长度为2进制下的长度
    res += "8";//在获得的数据后面添1,在16进制下相当于是添加8
    while (res.size() % 128 != 112) {
        res += "0";//“0”数据填充
    }
    string res_len = DecToHex(res_length);//用于记录数据长度的字符串
    while (res_len.size() != 16) {
        res_len = "0" + res_len;
    }
    res += res_len;
    return res;
}

string LeftShift(string str, int len) {//实现循环左移len位功能
    string res = HexToBin(str);
    res = res.substr(len) + res.substr(0, len);
    return BinToHex(res);
}

string XOR(string str1, string str2) {//实现异或操作
    string res1 = HexToBin(str1);
    string res2 = HexToBin(str2);
    string res = "";
    for (int i = 0; i < res1.size(); i++) {
        if (res1[i] == res2[i]) {
            res += "0";
        }
        else {
            res += "1";
        }
    }
    return BinToHex(res);
}

string AND(string str1, string str2) {//实现与操作
    string res1 = HexToBin(str1);
    string res2 = HexToBin(str2);
    string res = "";
    for (int i = 0; i < res1.size(); i++) {
        if (res1[i] == '1' && res2[i] == '1') {
            res += "1";
        }
        else {
            res += "0";
        }
    }
    return BinToHex(res);
}

string OR(string str1, string str2) {//实现或操作
    string res1 = HexToBin(str1);
    string res2 = HexToBin(str2);
    string res = "";
    for (int i = 0; i < res1.size(); i++) {
        if (res1[i] == '0' && res2[i] == '0') {
            res += "0";
        }
        else {
            res += "1";
        }
    }
    return BinToHex(res);
}

string NOT(string str) {//实现非操作
    string res1 = HexToBin(str);
    string res = "";
    for (int i = 0; i < res1.size(); i++) {
        if (res1[i] == '0') {
            res += "1";
        }
        else {
            res += "0";
        }
    }
    return BinToHex(res);
}

char binXor (char str1, char str2) {//实现单比特的异或操作
    return str1 == str2 ? '0' : '1';
}

char binAnd(char str1, char str2) {//实现单比特的与操作
    return (str1 == '1'&&str2 == '1') ? '1' : '0';
}

string ModAdd(string str1, string str2) {//mod 2^32运算的函数实现
    string res1 = HexToBin(str1);
    string res2 = HexToBin(str2);
    char temp = '0';
    string res = "";
    for (int i = res1.size() - 1; i >= 0; i--) {
        res = binXor(binXor(res1[i], res2[i]), temp) + res;
        if (binAnd(res1[i], res2[i]) == '1') {
            temp = '1';
        }
        else {
            if (binXor(res1[i], res2[i]) == '1') {
                temp = binAnd('1', temp);
            }
            else {
                temp = '0';
            }
        }
    }
    return BinToHex(res);
}

string P1(string str) {//实现置换功能P1(X)
    return XOR(XOR(str, LeftShift(str, 15)), LeftShift(str, 23));
}

string P0(string str) {//实现置换功能P0(X)
    return XOR(XOR(str, LeftShift(str, 9)), LeftShift(str, 17));
}

string T(int j) {//返回Tj常量值的函数实现
    if (0 <= j && j <= 15) {
        return "79CC4519";
    }
    else {
        return "7A879D8A";
    }
}

string FF(string str1, string str2, string str3, int j) {//实现布尔函数FF功能
    if (0 <= j && j <= 15) {
        return XOR(XOR(str1, str2), str3);
    }
    else {
        return OR(OR(AND(str1, str2), AND(str1, str3)), AND(str2, str3));
    }
}

string GG(string str1, string str2, string str3, int j) {//实现布尔函数GG功能
    if (0 <= j && j <= 15) {
        return XOR(XOR(str1, str2), str3);
    }
    else {
        return OR(AND(str1, str2), AND(NOT(str1), str3));
    }
}
string extension(string str) {//消息扩展函数
    string res = str;//字符串类型存储前68位存储扩展字W值
    for (int i = 16; i < 68; i++) {//根据公式生成第17位到第68位的W值
        res += XOR(
                XOR(
                        P1(
                                XOR(
                                        XOR(
                                                res.substr((i-16)*8,8), res.substr((i - 9) * 8, 8)),
                                                LeftShift(res.substr((i - 3) * 8, 8), 15)
                                        )
                                ),
                    LeftShift(res.substr((i - 13) * 8, 8), 7)
                        ),
            res.substr((i - 6) * 8, 8));
    }
    cout << "扩展后的消息:" << endl;
    cout << "W0,W1,……,W67的消息:" << endl;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            cout << res.substr(i * 64 + j * 8, 8) << "  ";
        }
        cout << endl;
    }
    cout << res.substr(512, 8) << "  " << res.substr(520, 8) << "  " << res.substr(528, 8) << "  " << res.substr(536, 8) << endl;
    cout << endl;
    for (int i = 0; i < 64; i++) {//根据公式生成64位W'值
        res += XOR(res.substr(i * 8, 8), res.substr((i + 4) * 8, 8));
    }
    cout << "W0',W1',……,W63'的消息:" << endl;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            cout << res.substr(544+i * 64 + j * 8, 8) << "  ";
        }
        cout << endl;
    }
    cout << endl;
    return res;
}

string compress(string str1, string str2) {//消息压缩函数
    string IV = str2;
    string A = IV.substr(0, 8), B = IV.substr(8, 8), C = IV.substr(16, 8), D = IV.substr(24, 8), E = IV.substr(32, 8), F = IV.substr(40, 8), G = IV.substr(48, 8), H = IV.substr(56, 8);
    string SS1 = "", SS2 = "", TT1 = "", TT2 = "";
    cout << "迭代压缩中间值: " << endl;
    cout << "    A         B         C         D         E         F        G         H " << endl;
    cout << A << "  " << B << "  " << C << "  " << D << "  " << E << "  " << F << "  " << G << "  " << H << endl;
    for (int j = 0; j < 64; j++) {
        SS1 = LeftShift(ModAdd(ModAdd(LeftShift(A, 12), E), LeftShift(T(j), (j%32))), 7);
        SS2 = XOR(SS1, LeftShift(A, 12));
        TT1 = ModAdd(ModAdd(ModAdd(FF(A, B, C, j), D), SS2), str1.substr((j + 68) * 8, 8));
        TT2 = ModAdd(ModAdd(ModAdd(GG(E, F, G, j), H), SS1), str1.substr(j * 8, 8));
        D = C;
        C = LeftShift(B, 9);
        B = A;
        A = TT1;
        H = G;
        G = LeftShift(F, 19);
        F = E;
        E = P0(TT2);
        cout << A << "  " << B << "  " << C << "  " << D << "  " << E << "  " << F << "  " << G << "  " << H << endl;
    }
    string res = (A + B + C + D + E + F + G + H);
    cout << endl;
    return res;
}

string iteration(string str) {//迭代压缩函数实现
    int num = str.size() / 128; //求有多少分组
    cout << "消息经过填充之后共有 " + to_string(num) + " 个消息分组。" << endl;
    cout << endl;
    string V = "7380166F4914B2B9172442D7DA8A0600A96F30BC163138AAE38DEE4DB0FB0E4E"; //初始IV(256bit)
    string B = "", extensionB = "", compressB = "";
    for (int i = 0; i < num; i++) {
        cout << "第 " << to_string(i+1) << " 个消息分组:" << endl;
        cout << endl;
        B = str.substr(i * 128, 128);//取一个分组(512bit)
        extensionB = extension(B); //密钥扩展,得到132个字
        compressB = compress(extensionB, V); //压缩函数,返回的是ABCDEFGH
        V = XOR(V, compressB); //V^{i+1}=V^{i} ^ V ^{i}
    }
    return V;
}

int main() {//主函数
    string str[2];
    str[0] = "abc";
    str[1] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
    for (int num = 0; num < 2; num++) {
        //to_string():将数字常量转换为字符串,返回值为转换后的字符串
        cout << "示例 " + to_string(num + 1) + " :输入消息为字符串: " + str[num] << endl;
        cout << endl;
        string paddingValue = padding(str[num]);
        cout << "填充后的消息为:" << endl;
        for (int i = 0; i < paddingValue.size() / 64; i++) {
            for (int j = 0; j < 8; j++) {
                //substr(pos,len):从初始位置pos开始读取长度为len个字符
                cout << paddingValue.substr(i * 64 + j * 8, 8) << "  ";
            }
            cout << endl;
        }
        cout << endl;
        string result = iteration(paddingValue);
        cout << "杂凑值:" << endl;
        for (int i = 0; i < 8; i++) {
            cout << result.substr(i * 8, 8) << "  ";
        }
        cout << endl;
        cout << endl;
    }
}

参考

1、SM3密码杂凑算法

2、https://blog.csdn.net/qq_40662424/article/details/121637732

SM4

SM4用于WAPI(无线局域网鉴别和保密基础协议)的分组密码算法,2006年公布的第一个商密

分组长度 密钥长度 轮数
128bit 128bit 32

img

  • 密钥扩展算法:将初始密钥扩展为轮密钥。
  • 数据解密和数据加密的算法结构相同,只是轮密钥的使用顺序相反解密轮密钥是加密轮密钥的逆序
  • 优势:
    • 密钥扩展算法与加密算法结构类似,在设计上做到资源重用
    • SM4采用的是非平衡Feistel网络
    • SM4中使用了唯一的非线性变换(S盒),提高了算法的非线性,隐藏代数结构,提高混淆作用
    • SM4中使用了线性变换(\(L()\)),增加了各输出值的相关性,使S盒的输出值得到扩散,使得密码算法能够抵抗差分攻击和线性分析

加密

输入128bit的明文分组,输出128bit的密文,下面定义“1个字=32bit=4个字节”。

img

轮函数

轮函数\(F()\)输入4个字(128bit)\((X_0,X_1,X_2,X_3)\)和一个字(32bit)的轮密钥\(rk\),变换为:

\[F(X_0,X_1,X_2,X_3,rk)=X_0\oplus T(X_1\oplus X_2\oplus X_3\oplus rk)= \\ X_0\oplus L(\tau (X_1\oplus X_2\oplus X_3\oplus rk)) \]

其中\(T()\)是合成变换,即\(T()=L(\tau())\)\(\tau ()\)是非线性变换(S盒),\(L()\)是线性变换。

\(B=(X_1\oplus X_2\oplus X_3\oplus rk)\),则\(F(X_0,X_1,X_2,X_3,rk)\begin{aligned}=& X_{0} \oplus[S(B)]\oplus[S(B)<<<2]\oplus[S(B)<<<10]& \oplus[S(B)<<<18] \oplus[S(B)<<<24]\end{aligned}\)

img

  • 非线性变换

img

就是4个S盒并行,其作用是混淆,输入的是\(A=(a_0,a_1,a_2,a_3)\)(4个字节,32bit),输出的是\(B=(b_0,b_1,b_2,b_3)\)(32位)即:

\[B=(b_0,b_1,b_2,b_3)=\tau (A)=(S(a_0),S(a_1),S(s_2),S(a_3)) \]

其中\(S(a)\)是一个S盒变换,输入\(a\)是一个字节(8bit),输出的\(S(a)\)也是8bit。

其中S盒变换,与AES相似:行(前4bit),列(后4bit)

img

  • 线性变换

线性变换\(L(B)\)的作用是扩散,其功能就是循环移位和异或,输入的\(B\)是一个字(32bit),输出的\(C=L(B)\)也是一个字(32bit),具体如下:

\[C=L(B)=B \oplus(B<<<2) \oplus(B<<<10) \oplus(B<<<18) \oplus(B<<<24) \]

反序变换

img

反序变换\(R\)就是在最后一轮后生成的\((x_{32},X_{33},X_{34},X_{35})\)进行反序输出,即

\[\left(Y_{0}, Y_{1}, Y_{2}, Y_{3}\right)=\left(X_{35}, X_{34}, X_{33}, X_{32}\right)=R\left(X_{32}, X_{33}, X_{34}, X_{35}\right) \]

密钥扩展

输入的初始密钥为\(MK=(MK_0,MK_1,MK_2,MK_3)\)(128bit),采用32轮迭代,每轮输出一个轮密钥\(rk_i,(i=0,...,31)\)(32bit)

img

所需参数:

  • 常数FK

\[F K_{0}=(A3B1BAC6),FK_{1}=(56AA3350),FK_{2}=(677D9197),FK_{3}=(B27022DC) \]

  • 固定参数CK

参数生成方式:

\(ck_{i,j}\)\(CK_i\)的第\(j\)个字节\((i=0,1, \cdots, 31 ; j=0,1,2,3)\),即\(C K_{i}=\left(c k_{i, 0}, c k_{i, 1}, c k_{i, 2}, c k_{i, 3}\right)\),其中\(c k_{i, j}=(4 i+j) \times 7(\bmod 256)\)

以下是生成好的32个固定参数:

image-20221017103834707

  • 32轮迭代

img

其中\(K_i(i=0,1,...,35)\)为中间数据:

\(\text { (1) }\left(K_{0}, K_{1}, K_{2}, K_{3}\right)=\left(\mathrm{MK}_{0} \oplus \mathrm{FK}_{0}, \mathrm{MK}_{1} \oplus \mathrm{FK}_{1}, \mathrm{MK}_{2} \oplus \mathrm{FK}_{2}, \mathrm{MK}_{3} \oplus \mathrm{FK}_{3}\right)\)

\(\text { (2) }\mathrm{rk}_{i}=K_{i+4}=K_{i} \oplus T^{\prime}\left(K_{i+1} \oplus K_{i+2} \oplus K_{i+3} \oplus CK_{i}\right)\),对于\(i=0,...,31\)

其中的\(T'()\)与加密算法中的轮函数相似,只是其中的线性变换\(L'()\)有所不同:

\[L^{\prime}(B)=B \oplus(B<<<13) \oplus(B<<<23) \]

解密

解密与加密相似,不同的是轮密钥使用的顺序,即解密时使用的轮密钥为\(rk_{31},...,rk_0\)

程序

  • 简单实现加解密
#include <iostream>
#include <string>
using namespace std;

string BinToHex(string str) {//二进制转换为十六进制的函数实现
    string hex = "";
    int temp = 0;
    while (str.size() % 4 != 0) {
        str = "0" + str;
    }
    for (int i = 0; i < str.size(); i += 4) {
        temp = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + (str[i + 3] - '0') * 1;
        if (temp < 10) {
            hex += to_string(temp);
        }
        else {
            hex += 'A' + (temp - 10);
        }
    }
    return hex;
}

string HexToBin(string str) {//十六进制转换为二进制的函数实现
    string bin = "";
    string table[16] = { "0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };
    for (int i = 0; i < str.size(); i++) {
        if (str[i] >= 'A'&&str[i] <= 'F') {
            bin += table[str[i] - 'A' + 10];
        }
        else {
            bin += table[str[i] - '0'];
        }
    }
    return bin;
}


int HexToDec(char str) {//十六进制转换为十进制的函数实现
    int dec = 0;
    if (str >= 'A' && str <= 'F') {
        dec += (str - 'A' + 10);
    }
    else {
        dec += (str - '0');
    }
    return dec;
}

string LeftShift(string str, int len) {//循环左移len位函数实现
    string res = HexToBin(str);
    res = res.substr(len) + res.substr(0, len);
    return BinToHex(res);
}

string XOR(string str1, string str2) {//异或函数实现
    string res1 = HexToBin(str1);
    string res2 = HexToBin(str2);
    string res = "";
    for (int i = 0; i < res1.size(); i++) {
        if (res1[i] == res2[i]) {
            res += "0";
        }
        else {
            res += "1";
        }
    }
    return BinToHex(res);
}

string NLTransform(string str) {//非线性变换t函数实现
    string Sbox[16][16] = { {"D6","90","E9","FE","CC","E1","3D","B7","16","B6","14","C2","28","FB","2C","05"},
                            {"2B","67","9A","76","2A","BE","04","C3","AA","44","13","26","49","86","06","99"},
                            {"9C","42","50","F4","91","EF","98","7A","33","54","0B","43","ED","CF","AC","62"},
                            {"E4","B3","1C","A9","C9","08","E8","95","80","DF","94","FA","75","8F","3F","A6"},
                            {"47","07","A7","FC","F3","73","17","BA","83","59","3C","19","E6","85","4F","A8"},
                            {"68","6B","81","B2","71","64","DA","8B","F8","EB","0F","4B","70","56","9D","35"},
                            {"1E","24","0E","5E","63","58","D1","A2","25","22","7C","3B","01","21","78","87"},
                            {"D4","00","46","57","9F","D3","27","52","4C","36","02","E7","A0","C4","C8","9E"},
                            {"EA","BF","8A","D2","40","C7","38","B5","A3","F7","F2","CE","F9","61","15","A1"},
                            {"E0","AE","5D","A4","9B","34","1A","55","AD","93","32","30","F5","8C","B1","E3"},
                            {"1D","F6","E2","2E","82","66","CA","60","C0","29","23","AB","0D","53","4E","6F"},
                            {"D5","DB","37","45","DE","FD","8E","2F","03","FF","6A","72","6D","6C","5B","51"},
                            {"8D","1B","AF","92","BB","DD","BC","7F","11","D9","5C","41","1F","10","5A","D8"},
                            {"0A","C1","31","88","A5","CD","7B","BD","2D","74","D0","12","B8","E5","B4","B0"},
                            {"89","69","97","4A","0C","96","77","7E","65","B9","F1","09","C5","6E","C6","84"},
                            {"18","F0","7D","EC","3A","DC","4D","20","79","EE","5F","3E","D7","CB","39","48"} };
    string res = "";
    for (int i = 0; i < 4; i++) {
        res = res + Sbox[HexToDec(str[2 * i])][HexToDec(str[2 * i + 1])];
    }
    return res;
}

string LTransform(string str) {//线性变换L函数实现
    return XOR(XOR(XOR(XOR(str, LeftShift(str, 2)), LeftShift(str, 10)), LeftShift(str, 18)), LeftShift(str, 24));
}

string L2Transform(string str) {//线性变换L'函数实现
    return XOR(XOR(str, LeftShift(str, 13)), LeftShift(str, 23));
}

string T(string str) {//用于加解密算法中的合成置换T函数实现
    return LTransform(NLTransform(str));//NLTransform()是S盒置换,LTransform()是线性L()变换
}

string T2(string str) {//用于密钥扩展算法中的合成置换T函数实现
    return L2Transform(NLTransform(str));//NLTransform()是S盒置换,L2Transform()是线性L'()变换
}

string KeyExtension(string MK) {//密钥扩展函数实现
    string FK[4] = { "A3B1BAC6", "56AA3350", "677D9197", "B27022DC" };
    string CK[32] = { "00070E15", "1C232A31", "383F464D", "545B6269",
                      "70777E85", "8C939AA1", "A8AFB6BD", "C4CBD2D9",
                      "E0E7EEF5", "FC030A11", "181F262D", "343B4249",
                      "50575E65", "6C737A81", "888F969D", "A4ABB2B9",
                      "C0C7CED5", "DCE3EAF1", "F8FF060D", "141B2229",
                      "30373E45", "4C535A61", "686F767D", "848B9299",
                      "A0A7AEB5", "BCC3CAD1", "D8DFE6ED", "F4FB0209",
                      "10171E25", "2C333A41", "484F565D", "646B7279" };
    string K[36] = { XOR(MK.substr(0,8),FK[0]),XOR(MK.substr(8,8),FK[1]),XOR(MK.substr(16,8),FK[2]),XOR(MK.substr(24),FK[3]) };
    string rks = "";
    for (int i = 0; i < 32; i++) {
        K[i + 4] = XOR(K[i], T2(XOR(XOR(XOR(K[i + 1], K[i + 2]), K[i + 3]), CK[i])));//T2()是密钥扩展的变换
        rks += K[i + 4];
    }
    return rks;
}

string encode(string plain, string key) {//加密函数实现
    cout << "轮密钥与每轮输出状态:" << endl;
    cout << endl;
    string cipher[36] = { plain.substr(0,8),plain.substr(8,8),plain.substr(16,8),plain.substr(24) };
    string rks = KeyExtension(key); //密钥扩展
    for (int i = 0; i < 32; i++) {
        cipher[i + 4] = XOR(cipher[i], T(XOR(XOR(XOR(cipher[i + 1], cipher[i + 2]), cipher[i + 3]), rks.substr(8 * i, 8))));
        cout << "rk[" + to_string(i) + "] = " + rks.substr(8 * i, 8) + "    X[" + to_string(i) + "] = " + cipher[i + 4] << endl;
    }
    cout << endl;
    return cipher[35] + cipher[34] + cipher[33] + cipher[32]; //反序变换R
}

string decode(string cipher, string key) {//解密函数实现
    cout << "轮密钥与每轮输出状态:" << endl;
    cout << endl;
    string plain[36] = { cipher.substr(0,8),cipher.substr(8,8), cipher.substr(16,8), cipher.substr(24,8) };
    string rks = KeyExtension(key); //密钥扩展
    for (int i = 0; i < 32; i++) {
        plain[i + 4] = XOR(plain[i], T(XOR(XOR(XOR(plain[i + 1], plain[i + 2]), plain[i + 3]), rks.substr(8 * (31 - i), 8))));
        cout << "rk[" + to_string(i) + "] = " + rks.substr(8 * (31 - i), 8) + "    X[" + to_string(i) + "] = " + plain[i + 4] << endl;
    }
    cout << endl;
    return plain[35] + plain[34] + plain[33] + plain[32]; //反序变换R
}

int main() {//主函数
    string str = "0123456789ABCDEFFEDCBA9876543210";
    cout << "明    文:" << str.substr(0, 8) << "  " << str.substr(8, 8) << "  " << str.substr(16, 8) << "  " << str.substr(24, 8) << endl;
    cout << endl;

    string key = "0123456789ABCDEFFEDCBA9876543210";
    cout << "加密密钥:" << key.substr(0, 8) << "  " << key.substr(8, 8) << "  " << key.substr(16, 8) << "  " << key.substr(24, 8) << endl;
    cout << endl;

    string cipher = encode(str, key);
    cout << "密    文:" << cipher.substr(0, 8) << "  " << cipher.substr(8, 8) << "  " << cipher.substr(16, 8) << "  " << cipher.substr(24, 8) << endl;
    cout << endl;

    cout << "解密密钥:" << key.substr(0, 8) << "  " << key.substr(8, 8) << "  " << key.substr(16, 8) << "  " << key.substr(24, 8) << endl;
    cout << endl;

    string plain = decode(cipher, key);
    cout << "明    文:" << plain.substr(0, 8) << "  " << plain.substr(8, 8) << "  " << plain.substr(16, 8) << "  " << plain.substr(24, 8) << endl;
}

image-20221017214700430

image-20221017214718806

  • openSSL中提取
/*
 * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
 * Copyright 2017 Ribose Inc. All Rights Reserved.
 * Ported from Ribose contributions from Botan.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include "sm4.h"
#define ossl_inline inline
static const uint8_t SM4_S[256] = {
        0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2,
        0x28, 0xFB, 0x2C, 0x05, 0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3,
        0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 0x9C, 0x42, 0x50, 0xF4,
        0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 0x62,
        0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA,
        0x75, 0x8F, 0x3F, 0xA6, 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA,
        0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 0xA8, 0x68, 0x6B, 0x81, 0xB2,
        0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 0x35,
        0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B,
        0x01, 0x21, 0x78, 0x87, 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52,
        0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xC8, 0x9E, 0xEA, 0xBF, 0x8A, 0xD2,
        0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 0xA1,
        0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30,
        0xF5, 0x8C, 0xB1, 0xE3, 0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60,
        0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 0x6F, 0xD5, 0xDB, 0x37, 0x45,
        0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 0x51,
        0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41,
        0x1F, 0x10, 0x5A, 0xD8, 0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD,
        0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 0xB0, 0x89, 0x69, 0x97, 0x4A,
        0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 0x84,
        0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E,
        0xD7, 0xCB, 0x39, 0x48
};

/*
 * SM4_SBOX_T[j] == L(SM4_SBOX[j]).
 */
static const uint32_t SM4_SBOX_T[256] = {
        0x8ED55B5B, 0xD0924242, 0x4DEAA7A7, 0x06FDFBFB, 0xFCCF3333, 0x65E28787,
        0xC93DF4F4, 0x6BB5DEDE, 0x4E165858, 0x6EB4DADA, 0x44145050, 0xCAC10B0B,
        0x8828A0A0, 0x17F8EFEF, 0x9C2CB0B0, 0x11051414, 0x872BACAC, 0xFB669D9D,
        0xF2986A6A, 0xAE77D9D9, 0x822AA8A8, 0x46BCFAFA, 0x14041010, 0xCFC00F0F,
        0x02A8AAAA, 0x54451111, 0x5F134C4C, 0xBE269898, 0x6D482525, 0x9E841A1A,
        0x1E061818, 0xFD9B6666, 0xEC9E7272, 0x4A430909, 0x10514141, 0x24F7D3D3,
        0xD5934646, 0x53ECBFBF, 0xF89A6262, 0x927BE9E9, 0xFF33CCCC, 0x04555151,
        0x270B2C2C, 0x4F420D0D, 0x59EEB7B7, 0xF3CC3F3F, 0x1CAEB2B2, 0xEA638989,
        0x74E79393, 0x7FB1CECE, 0x6C1C7070, 0x0DABA6A6, 0xEDCA2727, 0x28082020,
        0x48EBA3A3, 0xC1975656, 0x80820202, 0xA3DC7F7F, 0xC4965252, 0x12F9EBEB,
        0xA174D5D5, 0xB38D3E3E, 0xC33FFCFC, 0x3EA49A9A, 0x5B461D1D, 0x1B071C1C,
        0x3BA59E9E, 0x0CFFF3F3, 0x3FF0CFCF, 0xBF72CDCD, 0x4B175C5C, 0x52B8EAEA,
        0x8F810E0E, 0x3D586565, 0xCC3CF0F0, 0x7D196464, 0x7EE59B9B, 0x91871616,
        0x734E3D3D, 0x08AAA2A2, 0xC869A1A1, 0xC76AADAD, 0x85830606, 0x7AB0CACA,
        0xB570C5C5, 0xF4659191, 0xB2D96B6B, 0xA7892E2E, 0x18FBE3E3, 0x47E8AFAF,
        0x330F3C3C, 0x674A2D2D, 0xB071C1C1, 0x0E575959, 0xE99F7676, 0xE135D4D4,
        0x661E7878, 0xB4249090, 0x360E3838, 0x265F7979, 0xEF628D8D, 0x38596161,
        0x95D24747, 0x2AA08A8A, 0xB1259494, 0xAA228888, 0x8C7DF1F1, 0xD73BECEC,
        0x05010404, 0xA5218484, 0x9879E1E1, 0x9B851E1E, 0x84D75353, 0x00000000,
        0x5E471919, 0x0B565D5D, 0xE39D7E7E, 0x9FD04F4F, 0xBB279C9C, 0x1A534949,
        0x7C4D3131, 0xEE36D8D8, 0x0A020808, 0x7BE49F9F, 0x20A28282, 0xD4C71313,
        0xE8CB2323, 0xE69C7A7A, 0x42E9ABAB, 0x43BDFEFE, 0xA2882A2A, 0x9AD14B4B,
        0x40410101, 0xDBC41F1F, 0xD838E0E0, 0x61B7D6D6, 0x2FA18E8E, 0x2BF4DFDF,
        0x3AF1CBCB, 0xF6CD3B3B, 0x1DFAE7E7, 0xE5608585, 0x41155454, 0x25A38686,
        0x60E38383, 0x16ACBABA, 0x295C7575, 0x34A69292, 0xF7996E6E, 0xE434D0D0,
        0x721A6868, 0x01545555, 0x19AFB6B6, 0xDF914E4E, 0xFA32C8C8, 0xF030C0C0,
        0x21F6D7D7, 0xBC8E3232, 0x75B3C6C6, 0x6FE08F8F, 0x691D7474, 0x2EF5DBDB,
        0x6AE18B8B, 0x962EB8B8, 0x8A800A0A, 0xFE679999, 0xE2C92B2B, 0xE0618181,
        0xC0C30303, 0x8D29A4A4, 0xAF238C8C, 0x07A9AEAE, 0x390D3434, 0x1F524D4D,
        0x764F3939, 0xD36EBDBD, 0x81D65757, 0xB7D86F6F, 0xEB37DCDC, 0x51441515,
        0xA6DD7B7B, 0x09FEF7F7, 0xB68C3A3A, 0x932FBCBC, 0x0F030C0C, 0x03FCFFFF,
        0xC26BA9A9, 0xBA73C9C9, 0xD96CB5B5, 0xDC6DB1B1, 0x375A6D6D, 0x15504545,
        0xB98F3636, 0x771B6C6C, 0x13ADBEBE, 0xDA904A4A, 0x57B9EEEE, 0xA9DE7777,
        0x4CBEF2F2, 0x837EFDFD, 0x55114444, 0xBDDA6767, 0x2C5D7171, 0x45400505,
        0x631F7C7C, 0x50104040, 0x325B6969, 0xB8DB6363, 0x220A2828, 0xC5C20707,
        0xF531C4C4, 0xA88A2222, 0x31A79696, 0xF9CE3737, 0x977AEDED, 0x49BFF6F6,
        0x992DB4B4, 0xA475D1D1, 0x90D34343, 0x5A124848, 0x58BAE2E2, 0x71E69797,
        0x64B6D2D2, 0x70B2C2C2, 0xAD8B2626, 0xCD68A5A5, 0xCB955E5E, 0x624B2929,
        0x3C0C3030, 0xCE945A5A, 0xAB76DDDD, 0x867FF9F9, 0xF1649595, 0x5DBBE6E6,
        0x35F2C7C7, 0x2D092424, 0xD1C61717, 0xD66FB9B9, 0xDEC51B1B, 0x94861212,
        0x78186060, 0x30F3C3C3, 0x897CF5F5, 0x5CEFB3B3, 0xD23AE8E8, 0xACDF7373,
        0x794C3535, 0xA0208080, 0x9D78E5E5, 0x56EDBBBB, 0x235E7D7D, 0xC63EF8F8,
        0x8BD45F5F, 0xE7C82F2F, 0xDD39E4E4, 0x68492121 };

static ossl_inline uint32_t rotl(uint32_t a, uint8_t n)
{
return (a << n) | (a >> (32 - n));
}

static ossl_inline uint32_t load_u32_be(const uint8_t *b, uint32_t n)
{
    return ((uint32_t)b[4 * n] << 24) |
    ((uint32_t)b[4 * n + 1] << 16) |
    ((uint32_t)b[4 * n + 2] << 8) |
    ((uint32_t)b[4 * n + 3]);
}

static ossl_inline void store_u32_be(uint32_t v, uint8_t *b)
{
    b[0] = (uint8_t)(v >> 24);
    b[1] = (uint8_t)(v >> 16);
    b[2] = (uint8_t)(v >> 8);
    b[3] = (uint8_t)(v);
}
//合成变换T()=L(S())
static ossl_inline uint32_t SM4_T_slow(uint32_t X)
{
    uint32_t t = 0;

    //S盒变换(非线性变换)
    t |= ((uint32_t)SM4_S[(uint8_t)(X >> 24)]) << 24;
    t |= ((uint32_t)SM4_S[(uint8_t)(X >> 16)]) << 16;
    t |= ((uint32_t)SM4_S[(uint8_t)(X >> 8)]) << 8;
    t |= SM4_S[(uint8_t)X];

    /*
     * L linear transform L()变换(左循环移位)-线性变换
     */
    return t ^ rotl(t, 2) ^ rotl(t, 10) ^ rotl(t, 18) ^ rotl(t, 24);
}

//
static ossl_inline uint32_t SM4_T(uint32_t X)
{
    return SM4_SBOX_T[(uint8_t)(X >> 24)] ^
    rotl(SM4_SBOX_T[(uint8_t)(X >> 16)], 24) ^
    rotl(SM4_SBOX_T[(uint8_t)(X >> 8)], 16) ^
    rotl(SM4_SBOX_T[(uint8_t)X], 8);

    //没有循环移位(线性变换)
}

int ossl_sm4_set_key(const uint8_t *key, SM4_KEY *ks)
{
    /*
     * Family Key
     */
    static const uint32_t FK[4] =
            { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };

    /*
     * Constant Key
     */
    static const uint32_t CK[32] = {
            0x00070E15, 0x1C232A31, 0x383F464D, 0x545B6269,
            0x70777E85, 0x8C939AA1, 0xA8AFB6BD, 0xC4CBD2D9,
            0xE0E7EEF5, 0xFC030A11, 0x181F262D, 0x343B4249,
            0x50575E65, 0x6C737A81, 0x888F969D, 0xA4ABB2B9,
            0xC0C7CED5, 0xDCE3EAF1, 0xF8FF060D, 0x141B2229,
            0x30373E45, 0x4C535A61, 0x686F767D, 0x848B9299,
            0xA0A7AEB5, 0xBCC3CAD1, 0xD8DFE6ED, 0xF4FB0209,
            0x10171E25, 0x2C333A41, 0x484F565D, 0x646B7279
    };

    uint32_t K[4];
    int i;

    K[0] = load_u32_be(key, 0) ^ FK[0];
    K[1] = load_u32_be(key, 1) ^ FK[1];
    K[2] = load_u32_be(key, 2) ^ FK[2];
    K[3] = load_u32_be(key, 3) ^ FK[3];

    for (i = 0; i != SM4_KEY_SCHEDULE; ++i) {
        uint32_t X = K[(i + 1) % 4] ^ K[(i + 2) % 4] ^ K[(i + 3) % 4] ^ CK[i]; //B'
        uint32_t t = 0;

        //4个S盒变换
        t |= ((uint32_t)SM4_S[(uint8_t)(X >> 24)]) << 24;
        t |= ((uint32_t)SM4_S[(uint8_t)(X >> 16)]) << 16;
        t |= ((uint32_t)SM4_S[(uint8_t)(X >> 8)]) << 8;
        t |= SM4_S[(uint8_t)X];

        t = t ^ rotl(t, 13) ^ rotl(t, 23);//L'()函数
        K[i % 4] ^= t; //K_{i+4}
        ks->rk[i] = K[i % 4]; //rk_i
    }

    return 1;
}

#define SM4_RNDS(k0, k1, k2, k3, F)          \
      do {                                   \
         B0 ^= F(B1 ^ B2 ^ B3 ^ ks->rk[k0]); \
         B1 ^= F(B0 ^ B2 ^ B3 ^ ks->rk[k1]); \
         B2 ^= F(B0 ^ B1 ^ B3 ^ ks->rk[k2]); \
         B3 ^= F(B0 ^ B1 ^ B2 ^ ks->rk[k3]); \
      } while(0)

void ossl_sm4_encrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks)
{
    //8bit扩展为32bit,最终形成128bit=4*32bit
    uint32_t B0 = load_u32_be(in, 0);
    uint32_t B1 = load_u32_be(in, 1);
    uint32_t B2 = load_u32_be(in, 2);
    uint32_t B3 = load_u32_be(in, 3);

    /*
     * Uses byte-wise sbox in the first and last rounds to provide some
     * protection from cache based side channels.
     * 32轮迭代(4个为一个组)
     */
    SM4_RNDS( 0,  1,  2,  3, SM4_T_slow);//前4轮迭代
    SM4_RNDS( 4,  5,  6,  7, SM4_T);
    SM4_RNDS( 8,  9, 10, 11, SM4_T);
    SM4_RNDS(12, 13, 14, 15, SM4_T);
    SM4_RNDS(16, 17, 18, 19, SM4_T);
    SM4_RNDS(20, 21, 22, 23, SM4_T);
    SM4_RNDS(24, 25, 26, 27, SM4_T);
    SM4_RNDS(28, 29, 30, 31, SM4_T_slow);//后4轮迭代

    store_u32_be(B3, out);
    store_u32_be(B2, out + 4);
    store_u32_be(B1, out + 8);
    store_u32_be(B0, out + 12);
}

void ossl_sm4_decrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks)
{
    uint32_t B0 = load_u32_be(in, 0);
    uint32_t B1 = load_u32_be(in, 1);
    uint32_t B2 = load_u32_be(in, 2);
    uint32_t B3 = load_u32_be(in, 3);

    SM4_RNDS(31, 30, 29, 28, SM4_T_slow);
    SM4_RNDS(27, 26, 25, 24, SM4_T);
    SM4_RNDS(23, 22, 21, 20, SM4_T);
    SM4_RNDS(19, 18, 17, 16, SM4_T);
    SM4_RNDS(15, 14, 13, 12, SM4_T);
    SM4_RNDS(11, 10,  9,  8, SM4_T);
    SM4_RNDS( 7,  6,  5,  4, SM4_T);
    SM4_RNDS( 3,  2,  1,  0, SM4_T_slow);

    store_u32_be(B3, out);
    store_u32_be(B2, out + 4);
    store_u32_be(B1, out + 8);
    store_u32_be(B0, out + 12);
}
int main()
{
    const char* Sm4Key = "12345678";
    SM4_KEY key;
    ossl_sm4_set_key((const unsigned char* )Sm4Key, & key);

    const char* indata = "0123456789ABCDEF";
    unsigned char Encrydata[256] = { 0 };

    printf("明文消息:%s\n",indata);
    printf("密钥:%s\n",Sm4Key);

    //该函数每次加密128bit分组,即16字节,需自行补齐、分组
    ossl_sm4_encrypt((unsigned char*)indata, Encrydata, &key);
    printf("密文:%sX\n",Encrydata);

    unsigned char Decrydata[256] = { 0 };
    SM4_KEY key2;
    ossl_sm4_set_key((const unsigned char*)Sm4Key, &key2);
    ossl_sm4_decrypt((unsigned char*)Encrydata, Decrydata, &key2);
    printf("解密后明文:%s\n",Decrydata);
    return  0;
}

image-20221017214311433

SM9

SM9是一种标识密码(Identity-Based Cryptography),其用户的私钥由密钥生成中心(KGC)根据主密钥和用户标识计算出,用户的公钥由用户标识唯一确定。

下面解释一些名词:

  • 用户标识:指唯一可以确定用户身份的信息,即用户无法否认的信息,例如:身份证,电话号码等

  • 主密钥:分为主私钥和主公钥,其中主私钥由KGC通过随机数发生器产生,并由KGC秘密保存,主公钥由主私钥结合系统参数产生

  • KGC:负责选择系统参数,生成主密钥并产生用户私钥

  • 有限域、素域和扩域(更多参考:https://www.cnblogs.com/pam-sh/p/16540779.html)

  • 有限域上的离散对数问题(DLP)和椭圆曲线上的离散对数问题(ECDLP)(更多参考:https://www.cnblogs.com/pam-sh/p/16778293.html)

    • 解以上两个问题的方法(攻击方式):
    image-20221110204419162 image-20221110204441525
    • 对一般曲线上的离散对手问题,求解复杂度是指数级计算,对一些特殊曲线的离散对数问题,存在多项式级或亚指数计算的复杂度
  • 有限域上椭圆曲线是由椭圆曲线上的点组成的集合(包含无穷远点),且这些点结合“加法”运算,构成一个交换群,在该群中的计算有:

    • \(O+O=O\)
    • \(P+O=Q+P=P\)
    • \(-P=(x,-y),P+(-P)=0\)
    • \(P3=P1+P2=(x_3,y_3)\)
    image-20221110202839017
    • 倍点计算:\(P3=[2]P1\)
    image-20221110202817580
    • 多倍点计算:\(Q=[k]P\)
    image-20221110203121241 image-20221110203155693 image-20221110203948097
    • 椭圆曲线上的双线性对:
    image-20221110204120942
    • 双线性对的安全问题:
    image-20221110204231663

加解密

SM9是用椭圆曲线实现基于标识的公钥加密算法,即消息发送者利用接受者的标识对消息加密,只有接收者可以使用自己的用户私钥解密该消息。与密钥封装不同,公钥加密算法是密钥封装和消息封装的结合,且消息封装包括基于KDF的序列密码以及基于KDF的分组密码算法两种加密方式,最后对消息和密钥进行完整性验证,保证消息的机密性和完整性!

(1)公钥加密与密钥封装的区别:公钥加密包括密钥封装,前半部分是密钥封装,后半部分是消息封装(加密)

(2)消息认证函数与哈希函数的区别:MAC是对消息和密钥进行哈希,Hash是对消息进行哈希

(3)密钥生成和辅助函数与上述一样

(4)消息封装,即加密部分,分为两种情况,即序列密码(异或)和分组密码(SM4)

(5)既然是公钥加密算法:消息是\(M\),公钥是\(ID_B\),私钥是\(de_B\)

密钥生成

image-20221114103034393

加密

  • A需要给B发送长度为\(mlen\)的明文比特串\(M\),其中\(K_1-len\)是密钥\(K_1\)的比特长度,\(K_2-len\)是密钥\(K_2\)的比特长度

  • 密钥封装

![image-20221114112344182](/Users/hangshao/Library/Application Support/typora-user-images/image-20221114112344182.png)

  • 消息封装

image-20221114112432296

  • 加密流程:

image-20221114112839581

解密

  • B得到密文\(C=C_1||C_2||C_3\)后,使用私钥\(de_B\)解密

image-20221114113003844

  • 最后的消息认证函数,就是将密钥和密文进行哈希

  • 解密流程:

image-20221114113116008

程序实现

/****************************************************************
Function:       SM9_SelfCheck
Description:    SM9 self check
Calls:          MIRACL functions,SM9_Init(),SM9_GenerateEncryptKey(),
SM9_Encrypt,SM9_Decrypt
Called By:
Input:
Output:
Return:         0: self-check success
1: asking for memory error
2: element is out of order q
3: R-ate calculation error
4: test if C1 is on G1
5: base point P1 error
6: base point P2 error
7: Encryption public key generated error
8: Encryption private key generated error
9: encryption error
A: K1 equals 0
B: compare error of C3
C: decryption error
Others:
****************************************************************/
int SM9_SelfCheck()
{
    int MAX_LEN=1024;
    //时间定义
    time_t begin, end;

    //the master private key
    unsigned char KE[32] = { 0x00,0x01,0xED,0xEE,0x37,0x78,0xF4,0x41,0xF8,0xDE,0xA3,0xD9,0xFA,0x0A,0xCC,0x4E,
                             0x07,0xEE,0x36,0xC9,0x3F,0x9A,0x08,0x61,0x8A,0xF4,0xAD,0x85,0xCE,0xDE,0x1C,0x22 };

    unsigned char rand[32] = {0x00,0x00,0xAA,0xC0,0x54,0x17,0x79,0xC8,0xFC,0x45,0xE3,0xE2,0xCB,0x25,0xC1,0x2B,
                              0x5D,0x25,0x76,0xB2,0x12,0x9A,0xE8,0xBB,0x5E,0xE2,0xCB,0xE5,0xEC,0x9E,0x78,0x5C };
    //standard datas
    unsigned char std_Ppub[64] = { 0x78,0x7E,0xD7,0xB8,0xA5,0x1F,0x3A,0xB8,0x4E,0x0A,0x66,0x00,0x3F,0x32,0xDA,0x5C,
                                   0x72,0x0B,0x17,0xEC,0xA7,0x13,0x7D,0x39,0xAB,0xC6,0x6E,0x3C,0x80,0xA8,0x92,0xFF,
                                   0x76,0x9D,0xE6,0x17,0x91,0xE5,0xAD,0xC4,0xB9,0xFF,0x85,0xA3,0x13,0x54,0x90,0x0B,
                                   0x20,0x28,0x71,0x27,0x9A,0x8C,0x49,0xDC,0x3F,0x22,0x0F,0x64,0x4C,0x57,0xA7,0xB1 };
    unsigned char std_deB[128] = { 0x94,0x73,0x6A,0xCD,0x2C,0x8C,0x87,0x96,0xCC,0x47,0x85,0xE9,0x38,0x30,0x1A,0x13,
                                   0x9A,0x05,0x9D,0x35,0x37,0xB6,0x41,0x41,0x40,0xB2,0xD3,0x1E,0xEC,0xF4,0x16,0x83,
                                   0x11,0x5B,0xAE,0x85,0xF5,0xD8,0xBC,0x6C,0x3D,0xBD,0x9E,0x53,0x42,0x97,0x9A,0xCC,
                                   0xCF,0x3C,0x2F,0x4F,0x28,0x42,0x0B,0x1C,0xB4,0xF8,0xC0,0xB5,0x9A,0x19,0xB1,0x58,
                                   0x7A,0xA5,0xE4,0x75,0x70,0xDA,0x76,0x00,0xCD,0x76,0x0A,0x0C,0xF7,0xBE,0xAF,0x71,
                                   0xC4,0x47,0xF3,0x84,0x47,0x53,0xFE,0x74,0xFA,0x7B,0xA9,0x2C,0xA7,0xD3,0xB5,0x5F,
                                   0x27,0x53,0x8A,0x62,0xE7,0xF7,0xBF,0xB5,0x1D,0xCE,0x08,0x70,0x47,0x96,0xD9,0x4C,
                                   0x9D,0x56,0x73,0x4F,0x11,0x9E,0xA4,0x47,0x32,0xB5,0x0E,0x31,0xCD,0xEB,0x75,0xC1 };

    unsigned char std_C_stream[116] = { 0x24,0x45,0x47,0x11,0x64,0x49,0x06,0x18,0xE1,0xEE,0x20,0x52,0x8F,0xF1,0xD5,0x45,
                                        0xB0,0xF1,0x4C,0x8B,0xCA,0xA4,0x45,0x44,0xF0,0x3D,0xAB,0x5D,0xAC,0x07,0xD8,0xFF,
                                        0x42,0xFF,0xCA,0x97,0xD5,0x7C,0xDD,0xC0,0x5E,0xA4,0x05,0xF2,0xE5,0x86,0xFE,0xB3,
                                        0xA6,0x93,0x07,0x15,0x53,0x2B,0x80,0x00,0x75,0x9F,0x13,0x05,0x9E,0xD5,0x9A,0xC0,
                                        0xBA,0x67,0x23,0x87,0xBC,0xD6,0xDE,0x50,0x16,0xA1,0x58,0xA5,0x2B,0xB2,0xE7,0xFC,
                                        0x42,0x91,0x97,0xBC,0xAB,0x70,0xB2,0x5A,0xFE,0xE3,0x7A,0x2B,0x9D,0xB9,0xF3,0x67,
                                        0x1B,0x5F,0x5B,0x0E,0x95,0x14,0x89,0x68,0x2F,0x3E,0x64,0xE1,0x37,0x8C,0xDD,0x5D,
                                        0xA9,0x51,0x3B,0x1C };
    unsigned char std_C_cipher[128] = { 0x24,0x45,0x47,0x11,0x64,0x49,0x06,0x18,0xE1,0xEE,0x20,0x52,0x8F,0xF1,0xD5,0x45,
                                        0xB0,0xF1,0x4C,0x8B,0xCA,0xA4,0x45,0x44,0xF0,0x3D,0xAB,0x5D,0xAC,0x07,0xD8,0xFF,
                                        0x42,0xFF,0xCA,0x97,0xD5,0x7C,0xDD,0xC0,0x5E,0xA4,0x05,0xF2,0xE5,0x86,0xFE,0xB3,
                                        0xA6,0x93,0x07,0x15,0x53,0x2B,0x80,0x00,0x75,0x9F,0x13,0x05,0x9E,0xD5,0x9A,0xC0,
                                        0xFD,0x3C,0x98,0xDD,0x92,0xC4,0x4C,0x68,0x33,0x26,0x75,0xA3,0x70,0xCC,0xEE,0xDE,
                                        0x31,0xE0,0xC5,0xCD,0x20,0x9C,0x25,0x76,0x01,0x14,0x9D,0x12,0xB3,0x94,0xA2,0xBE,
                                        0xE0,0x5B,0x6F,0xAC,0x6F,0x11,0xB9,0x65,0x26,0x8C,0x99,0x4F,0x00,0xDB,0xA7,0xA8,
                                        0xBB,0x00,0xFD,0x60,0x58,0x35,0x46,0xCB,0xDF,0x46,0x49,0x25,0x08,0x63,0xF1,0x0A };

    unsigned char *std_message = "Chinese IBE standard";
    unsigned char hid[] = { 0x03 };
    unsigned char *IDA = "Alice", *IDB = "Bob";

    unsigned char Ppub[64], deB[128];
    unsigned char message[1000], C[1000];
    int M_len, C_len;//M_len the length of message //C_len the length of C
    int k1_len = 16, k2_len = 32;
    int EncID = 0;//0,stream  //1 block
    int tmp, i;
    big ke;

    tmp = SM9_Init();//参数设置
    if (tmp != 0) return tmp;

    ke = mirvar(0);
    bytes_to_big(32, KE, ke);

    printf("\n***********************SM9 密钥生成***************************\n");
    printf("用户A的ID号为:%s\n用户B的ID号为:%s\n",IDA,IDB);
    tmp = SM9_GenerateEncryptKey(hid, IDB, strlen(IDB), ke, Ppub, deB);
    if (tmp != 0)  return tmp;
    if (memcmp(Ppub, std_Ppub, 64) != 0)
        return SM9_GEPUB_ERR;
    if (memcmp(deB, std_deB, 128) != 0)
        return SM9_GEPRI_ERR;

    printf("\n***********************SM9 加密算法**************************\n");
    printf("要加密的明文消息为:%s\n",std_message);
    begin = clock();
    tmp = SM9_Encrypt(hid, IDB, std_message, strlen(std_message), rand, EncID, k1_len, k2_len, Ppub, C, &C_len);
    end = clock();
    printf("\n\n\t\t\t加密时间: %f seconds\n", (double)(end - begin) / CLOCKS_PER_SEC);

    if (tmp != 0) return tmp;
    printf("\n******************************密文为:************************************\n");
    for (i = 0; i<C_len; i++) printf("%02x", C[i]);
    if (EncID == 0) tmp = memcmp(C, std_C_stream,C_len); else tmp=memcmp(C,std_C_cipher,C_len);
    if (tmp) return SM9_ENCRYPT_ERR;

    printf("\n\n");
    printf("\n**********************SM9 解密算法**************************\n");
    begin = clock();
    tmp = SM9_Decrypt(std_C_cipher, 128, deB, IDB, 2, k1_len, k2_len, message, &M_len);
    end = clock();

    printf("\n");
    message[M_len] = '\0';
    printf("明文:%s\n",message);
    if (tmp != 0)
        return tmp;
    if (memcmp(message, std_message, M_len) != 0)
        return SM9_DECRYPT_ERR;
    printf("\n\n\t\t\t解密时间: %f seconds\n", (double)(end - begin) / CLOCKS_PER_SEC);
    printf("\n");
    return 0;
}

数字签名

适用于接收者通过签名者的标识验证数据的完整性和数据发送者的身份,也可以用于第三方确定签名及所签数据的真实性。

(1)符号介绍:

  • \(cid\):曲线标识符,表示使用曲线的类别
  • \(N\):曲线的素因子
  • \(k\):曲线\(E(F_q)\)相对于\(N\)的嵌入次数
  • \(P_1\)\(N\)阶循环子群\(G_1\)的生成元
  • \(P_2\)\(N\)阶循环子群\(G_2\)的生成元
  • \(eid\):双线性对\(e()\)的标识符,表示双线性对类别
  • \(ID_A\):用户标识
  • \(hid\):用户私钥生成函数识别符(一个字节)

(2)辅助函数

  • 哈希函数:\(H_v()\),一般使用SM3,即生成256位的哈希值
  • \(H1()\)函数:

image-20221110215244048

image-20221110215319199
  • \(H2()\)函数:

image-20221110215359306

(3)算法流程:

  • 由KGC生成主私钥和主公钥,并且根据用户标识生成用户私钥
  • 签名者使用用户私钥对消息签名
  • 验签者使用用户标识(相当于用户公钥)对签名验签

密钥生成

  • 主私钥\(ks\):KGC产生随机数\(ks\in [1,N=1]\),秘密保留主私钥
  • 主公钥\(P_{pub}\):KGC计算\(G_2\)中的元素\(P_{pub}=[ks]P_2\),公开主公钥
  • 用户私钥\(d_{s_A}\):KGC选择并公开\(hid\),首先在有限域\(F_N\)上计算\(t_1=H_1(ID_A || hid,N)+ks\),若\(t_1=0\)则需重新生成\(ks\),并重新计算其他密钥,否则计算\(t_2=ks*t_1^{-1}\),最后计算出\(d_{s_A}=[t_2]P_1\)

签名

下面是签名流程图:

image-20221110221015549

设消息是比特串\(M\),签名步骤如下:

image-20221110221109233

image-20221110220923232

验签

下面是验签流程图:

image-20221110221222566

假设验证者收到消息和签名\(\left (h',S' \right )\),签名步骤如下:

image-20221110221414347

正确性

img

程序实现

int main()
{
    int res = 0;
    int len;
    int i;
    //char message[MAX_LEn];
    unsigned char *message[MAX_LEN] = { 0 };
    unsigned char buf[MAX_LEN];
    unsigned char *input;

    FILE *fp;
    printf("****************************SM9签名****************************\n");
    printf("demo.txt中的消息:");
    if((fp = fopen("../demo.txt","r")) == NULL)
    {
        perror("fail to read");
        exit (1) ;
    }
    while(fgets(buf,MAX_LEN,fp) != NULL)
    {
        len=strlen(buf);
        printf("%s\n",buf);
        printf("长度:%d\n",len);
    }
    printf("十六进制:");
    for (i=0; i<len; i++)
        printf("%02x ", buf[i]);
    input=buf;

    //scanf("%s", message);
    //gets(message);
    printf("\n****************************开始****************************\n");

    if (0 != (res = SM9_SelfCheck(input)))
        printf("程序运行错误!\n");
    printf("****************************完成****************************\n");
    system("pause");
    return 0;
}

密钥封装

密钥封装可以封装密钥给特定实体,即发送一个安全的密钥,这里和密钥交换相似。密钥封装使得封装者可以产生并加密一个秘密密钥给目标用户,而只有目标用户可以加密该封装秘密密钥,并把它作为进一步的会话密钥。

(1)这里的辅助函数\(H1(),H2().KDF()\)与密钥交换相同

  • \(H1()\)
image-20221113184754465
  • \(H2()\)
image-20221113184809234
  • \(KDF()\)
image-20221113184907322

(2)密钥封装与公钥加密很像,只不过是将密钥加密发送给目标用户,目标用户再使用私钥解密即可

密钥生成

  • 密钥生成与数字签名相同

image-20221114103034393

密钥封装

  • A用户需要封装长度为\(klen\)的密钥给用户B

image-20221114103212718

  • 这里的\(K\)是被封装的密钥,\(C\)是对\(K\)的加密,即秘密密钥,目标用户B需要从\(C\)中恢复出\(K\)
  • 封装流程:

image-20221114103414366

  • 其中双线性对的计算结果\(g\)是一个数,不是椭圆曲线上的点
  • 有个疑问,为什么需要发送\(K\),目标用户B最后就是为了得到\(K\),并且后面也没有用到(对比)

密钥接封装

image-20221114103522020

  • 解封装流程:

image-20221114103606122

  • 其中\(w‘=e(C,de_B)\),可以看成用用户私钥\(de_B\)解密\(C\)

程序实现

/****************************************************************
  Function:       SM9_SelfCheck
  Description:    SM9 self check
  Calls:          MIRACL functions,SM9_Init(),SM9_GenerateEncryptKey(),SM9_Key_encap,
                  SM9_Key_decap
  Called By:
  Input:
  Output:
  Return:         0: self-check success
                  1: asking for memory error
                  2: element is out of order q
                  3: R-ate calculation error
                  4: test if C is on G1
                  5: base point P1 error
                  6: base point P2 error
                  7: Encryption public key generated error
                  8: Encryption private key generated error
                  9: K equals 0
                  A: cipher error in key encapsulation
                  B: key to be encapsulated
                  C: key generated by decapsulation
  Others:
****************************************************************/
int SM9_SelfCheck()
{
    //the master private key
    unsigned char KE[32] =
            {0x00,0x01,0xED,0xEE,0x37,0x78,0xF4,0x41,0xF8,0xDE,0xA3,0xD9,0xFA,0x0A,0xCC,0x4E,
             0x07,0xEE,0x36,0xC9,0x3F,0x9A,0x08,0x61,0x8A,0xF4,0xAD,0x85,0xCE,0xDE,0x1C,0x22};

    unsigned char rand[32]={0x00,0x00,0x74,0x01,0x5F,0x84,0x89,0xC0,0x1E,0xF4,0x27,0x04,0x56,0xF9,0xE6,0x47,
                            0x5B,0xFB,0x60,0x2B,0xDE,0x7F,0x33,0xFD,0x48,0x2A,0xB4,0xE3,0x68,0x4A,0x67,0x22};
    //standard datas
    unsigned char std_Ppub[64]=
            {0x78,0x7E,0xD7,0xB8,0xA5,0x1F,0x3A,0xB8,0x4E,0x0A,0x66,0x00,0x3F,0x32,0xDA,0x5C,
             0x72,0x0B,0x17,0xEC,0xA7,0x13,0x7D,0x39,0xAB,0xC6,0x6E,0x3C,0x80,0xA8,0x92,0xFF,
             0x76,0x9D,0xE6,0x17,0x91,0xE5,0xAD,0xC4,0xB9,0xFF,0x85,0xA3,0x13,0x54,0x90,0x0B,
             0x20,0x28,0x71,0x27,0x9A,0x8C,0x49,0xDC,0x3F,0x22,0x0F,0x64,0x4C,0x57,0xA7,0xB1};
    unsigned char std_deB[128]=
            {0x94,0x73,0x6A,0xCD,0x2C,0x8C,0x87,0x96,0xCC,0x47,0x85,0xE9,0x38,0x30,0x1A,0x13,
             0x9A,0x05,0x9D,0x35,0x37,0xB6,0x41,0x41,0x40,0xB2,0xD3,0x1E,0xEC,0xF4,0x16,0x83,
             0x11,0x5B,0xAE,0x85,0xF5,0xD8,0xBC,0x6C,0x3D,0xBD,0x9E,0x53,0x42,0x97,0x9A,0xCC,
             0xCF,0x3C,0x2F,0x4F,0x28,0x42,0x0B,0x1C,0xB4,0xF8,0xC0,0xB5,0x9A,0x19,0xB1,0x58,
             0x7A,0xA5,0xE4,0x75,0x70,0xDA,0x76,0x00,0xCD,0x76,0x0A,0x0C,0xF7,0xBE,0xAF,0x71,
             0xC4,0x47,0xF3,0x84,0x47,0x53,0xFE,0x74,0xFA,0x7B,0xA9,0x2C,0xA7,0xD3,0xB5,0x5F,
             0x27,0x53,0x8A,0x62,0xE7,0xF7,0xBF,0xB5,0x1D,0xCE,0x08,0x70,0x47,0x96,0xD9,0x4C,
             0x9D,0x56,0x73,0x4F,0x11,0x9E,0xA4,0x47,0x32,0xB5,0x0E,0x31,0xCD,0xEB,0x75,0xC1};
    unsigned char std_K[64] =
            {0x4F,0xF5,0xCF,0x86,0xD2,0xAD,0x40,0xC8,0xF4,0xBA,0xC9,0x8D,0x76,0xAB,0xDB,0xDE,
             0x0C,0x0E,0x2F,0x0A,0x82,0x9D,0x3F,0x91,0x1E,0xF5,0xB2,0xBC,0xE0,0x69,0x54,0x80};
    unsigned char std_C[64] =
            {0x1E,0xDE,0xE2,0xC3,0xF4,0x65,0x91,0x44,0x91,0xDE,0x44,0xCE,0xFB,0x2C,0xB4,0x34,
             0xAB,0x02,0xC3,0x08,0xD9,0xDC,0x5E,0x20,0x67,0xB4,0xFE,0xD5,0xAA,0xAC,0x8A,0x0F,
             0x1C,0x9B,0x4C,0x43,0x5E,0xCA,0x35,0xAB,0x83,0xBB,0x73,0x41,0x74,0xC0,0xF7,0x8F,
             0xDE,0x81,0xA5,0x33,0x74,0xAF,0xF3,0xB3,0x60,0x2B,0xBC,0x5E,0x37,0xBE,0x9A,0x4C};

    unsigned char hid[]={0x03},*IDB="Bob";
    unsigned char Ppub[64],deB[128],C[64],K[32],K_decap[32];
    big ke;
    int tmp,i;
    int Klen=32;

    mip=mirsys(1000, 16);
    mip->IOBASE=16;
    ke=mirvar(0);
    bytes_to_big(32,KE,ke);

    tmp=SM9_Init();
    if(tmp!=0) return tmp;

    printf("\n***********************  SM9 密钥产生    ***************************");
    tmp=SM9_GenerateEncryptKey(hid,IDB,strlen(IDB),ke,Ppub,deB);
    if(tmp!=0)  return tmp;
    if(memcmp(Ppub,std_Ppub,64)!=0)
        return SM9_GEPUB_ERR;
    if(memcmp(deB,std_deB,128)!=0)
        return SM9_GEPRI_ERR;

    printf("\n***********************  主加密私钥 KE:    ***************************\n");
    for(i=0;i<32;i++){printf("%02x",KE[i]);}
    printf("\n***********************  主加密公钥 Ppubs=[ke]P1:    ***************************\n");
    for(i=0;i<64;i++){if(i==32) printf("\n");printf("%02x",Ppub[i]);}
    printf("\n\t******用户私钥 deB = (xdeB, ydeB):*************\n");
    for(i=0;i<128;i++)
    {   if(i==64) printf("\n");
        printf("%02x",deB[i]);}

    printf("\n\n///////////////////密钥封装//////////////////////");
    tmp=SM9_Key_encap( hid,IDB,rand, Ppub, C, K,Klen);
    if(tmp!=0) return tmp;

    if(memcmp(C,std_C,64)!=0)
        return SM9_ERR_Encap_C;
    if(memcmp(K,std_K,Klen)!=0)
        return SM9_ERR_Encap_K;

    printf("\n\n///////////////////密钥解封装//////////////////////");
    tmp=SM9_Key_decap(IDB, deB, C,Klen,K_decap);
    if(tmp!=0) return tmp;

    if(memcmp(K_decap,std_K,32)!=0)
        return SM9_ERR_Decap_K;
    return 0;
} 

密钥交换

协议可以通过双方的标识和私钥经过两次货可选三次信息传递,计算获得一个由双方共同决定的共享密钥,该密钥可作为对称加密的绘画密钥。

(1)基本概念

image-20221113184057084

  • 这里认为密钥交换就是密钥协商
  • 密钥交换和签名的不同:
    • 密钥交换需要交互多次,且需要两方的用户标识
    • 密钥交换需要KDF,即密钥派生函数
  • KDF:作用于共享密钥和双方都知道的其他参数,产生一个或多个共享密钥的密钥,可以看成对(共享密钥和共享参数)的哈希
  • 双方均能通过可选项实现密钥确认

(2)辅助函数

⚠️:\(H1(),H2()\)函数和签名方案相同,多了一个KDF

  • \(H1()\)
image-20221113184754465
  • \(H2()\)
image-20221113184809234
  • \(KDF()\)
image-20221113184907322

密钥生成

  • 密钥生成和签名方案一样:KGC生成主私钥和主公钥,并且主私钥和用户标识一起生成用户私钥,注意,这里双昂都需要生成用户私钥
image-20221113212745718

密钥交换

  • 双方协商生成长度为\(klen\)的密钥

(1)Alice

image-20221113212926337

(2)Bob

image-20221113213000615
  • 这里的\(Hash()\)指的是SM3算法

(3)Alice

image-20221113213119552

(4)Bob

image-20221113213138858

流程图

image-20221113213247272

程序实现

/****************************************************************
Function:       SM9_SelfCheck
Description:    SM9 self check
Calls:          MIRACL functions,SM9_Init(),SM9_GenerateEncryptKey(),SM9_KeyEx_InitA_I,
SM9_KeyEx_InitA_II,SM9_KeyEx_ReB_I,SM9_KeyEx_ReB_II
Called By:
Input:
Output:
Return:         0: self-check success
1: asking for memory error
2: element is out of order q
3: R-ate calculation error
4: test if C1 is on G1
5: base point P1 error
6: base point P2 error
7: Encryption public key generated error
8: Encryption private key generated error
9: key exchange failed,form B to A,S1!=SB
A: key exchange failed,form A to B,S2!=SA
B: RA generated error
C: RB generated error
D: SA generated error
E: SB generated error
Others:
****************************************************************/
int ARS_SM9_SelfCheck()
{
    //the master private key
    unsigned char KE[32] = { 0x00,0x02,0xE6,0x5B,0x07,0x62,0xD0,0x42,0xF5,0x1F,0x0D,0x23,0x54,0x2B,0x13,0xED,
                             0x8C,0xFA,0x2E,0x9A,0x0E,0x72,0x06,0x36,0x1E,0x01,0x3A,0x28,0x39,0x05,0xE3,0x1F };

    unsigned char randA[32] = { 0x00,0x00,0x58,0x79,0xDD,0x1D,0x51,0xE1,0x75,0x94,0x6F,0x23,0xB1,0xB4,0x1E,0x93,
                                0xBA,0x31,0xC5,0x84,0xAE,0x59,0xA4,0x26,0xEC,0x10,0x46,0xA4,0xD0,0x3B,0x06,0xC8 };
    unsigned char randB[32] = { 0x00,0x01,0x8B,0x98,0xC4,0x4B,0xEF,0x9F,0x85,0x37,0xFB,0x7D,0x07,0x1B,0x2C,0x92,
                                0x8B,0x3B,0xC6,0x5B,0xD3,0xD6,0x9E,0x1E,0xEE,0x21,0x35,0x64,0x90,0x56,0x34,0xFE };
    //standard datas
    unsigned char std_Ppub[64] = { 0x91,0x74,0x54,0x26,0x68,0xE8,0xF1,0x4A,0xB2,0x73,0xC0,0x94,0x5C,0x36,0x90,0xC6,
                                   0x6E,0x5D,0xD0,0x96,0x78,0xB8,0x6F,0x73,0x4C,0x43,0x50,0x56,0x7E,0xD0,0x62,0x83,
                                   0x54,0xE5,0x98,0xC6,0xBF,0x74,0x9A,0x3D,0xAC,0xC9,0xFF,0xFE,0xDD,0x9D,0xB6,0x86,
                                   0x6C,0x50,0x45,0x7C,0xFC,0x7A,0xA2,0xA4,0xAD,0x65,0xC3,0x16,0x8F,0xF7,0x42,0x10 };
    unsigned char std_deA[128] = { 0x0F,0xE8,0xEA,0xB3,0x95,0x19,0x9B,0x56,0xBF,0x1D,0x75,0xBD,0x2C,0xD6,0x10,0xB6,
                                   0x42,0x4F,0x08,0xD1,0x09,0x29,0x22,0xC5,0x88,0x2B,0x52,0xDC,0xD6,0xCA,0x83,0x2A,
                                   0x7D,0xA5,0x7B,0xC5,0x02,0x41,0xF9,0xE5,0xBF,0xDD,0xC0,0x75,0xDD,0x9D,0x32,0xC7,
                                   0x77,0x71,0x00,0xD7,0x36,0x91,0x6C,0xFC,0x16,0x5D,0x8D,0x36,0xE0,0x63,0x4C,0xD7,
                                   0x83,0xA4,0x57,0xDA,0xF5,0x2C,0xAD,0x46,0x4C,0x90,0x3B,0x26,0x06,0x2C,0xAF,0x93,
                                   0x7B,0xB4,0x0E,0x37,0xDA,0xDE,0xD9,0xED,0xA4,0x01,0x05,0x0E,0x49,0xC8,0xAD,0x0C,
                                   0x69,0x70,0x87,0x6B,0x9A,0xAD,0x1B,0x7A,0x50,0xBB,0x48,0x63,0xA1,0x1E,0x57,0x4A,
                                   0xF1,0xFE,0x3C,0x59,0x75,0x16,0x1D,0x73,0xDE,0x4C,0x3A,0xF6,0x21,0xFB,0x1E,0xFB };
    unsigned char std_deB[128] = { 0x74,0xCC,0xC3,0xAC,0x9C,0x38,0x3C,0x60,0xAF,0x08,0x39,0x72,0xB9,0x6D,0x05,0xC7,
                                   0x5F,0x12,0xC8,0x90,0x7D,0x12,0x8A,0x17,0xAD,0xAF,0xBA,0xB8,0xC5,0xA4,0xAC,0xF7,
                                   0x01,0x09,0x2F,0xF4,0xDE,0x89,0x36,0x26,0x70,0xC2,0x17,0x11,0xB6,0xDB,0xE5,0x2D,
                                   0xCD,0x5F,0x8E,0x40,0xC6,0x65,0x4B,0x3D,0xEC,0xE5,0x73,0xC2,0xAB,0x3D,0x29,0xB2,
                                   0x44,0xB0,0x29,0x4A,0xA0,0x42,0x90,0xE1,0x52,0x4F,0xF3,0xE3,0xDA,0x8C,0xFD,0x43,
                                   0x2B,0xB6,0x4D,0xE3,0xA8,0x04,0x0B,0x5B,0x88,0xD1,0xB5,0xFC,0x86,0xA4,0xEB,0xC1,
                                   0x8C,0xFC,0x48,0xFB,0x4F,0xF3,0x7F,0x1E,0x27,0x72,0x74,0x64,0xF3,0xC3,0x4E,0x21,
                                   0x53,0x86,0x1A,0xD0,0x8E,0x97,0x2D,0x16,0x25,0xFC,0x1A,0x7B,0xD1,0x8D,0x55,0x39 };
    unsigned char std_RA[64] = { 0x7C,0xBA,0x5B,0x19,0x06,0x9E,0xE6,0x6A,0xA7,0x9D,0x49,0x04,0x13,0xD1,0x18,0x46,
                                 0xB9,0xBA,0x76,0xDD,0x22,0x56,0x7F,0x80,0x9C,0xF2,0x3B,0x6D,0x96,0x4B,0xB2,0x65,
                                 0xA9,0x76,0x0C,0x99,0xCB,0x6F,0x70,0x63,0x43,0xFE,0xD0,0x56,0x37,0x08,0x58,0x64,
                                 0x95,0x8D,0x6C,0x90,0x90,0x2A,0xBA,0x7D,0x40,0x5F,0xBE,0xDF,0x7B,0x78,0x15,0x99 };
    unsigned char std_RB[64] = { 0x86,0x1E,0x91,0x48,0x5F,0xB7,0x62,0x3D,0x27,0x94,0xF4,0x95,0x03,0x1A,0x35,0x59,
                                 0x8B,0x49,0x3B,0xD4,0x5B,0xE3,0x78,0x13,0xAB,0xC7,0x10,0xFC,0xC1,0xF3,0x44,0x82,
                                 0x32,0xD9,0x06,0xA4,0x69,0xEB,0xC1,0x21,0x6A,0x80,0x2A,0x70,0x52,0xD5,0x61,0x7C,
                                 0xD4,0x30,0xFB,0x56,0xFB,0xA7,0x29,0xD4,0x1D,0x9B,0xD6,0x68,0xE9,0xEB,0x96,0x00 };
    unsigned char std_SA[32] = { 0x19,0x5D,0x1B,0x72,0x56,0xBA,0x7E,0x0E,0x67,0xC7,0x12,0x02,0xA2,0x5F,0x8C,0x94,
                                 0xFF,0x82,0x41,0x70,0x2C,0x2F,0x55,0xD6,0x13,0xAE,0x1C,0x6B,0x98,0x21,0x51,0x72 };
    unsigned char std_SB[32] = { 0x3B,0xB4,0xBC,0xEE,0x81,0x39,0xC9,0x60,0xB4,0xD6,0x56,0x6D,0xB1,0xE0,0xD5,0xF0,
                                 0xB2,0x76,0x76,0x80,0xE5,0xE1,0xBF,0x93,0x41,0x03,0xE6,0xC6,0x6E,0x40,0xFF,0xEE };

    unsigned char hid[] = { 0x02 }, *IDA = "Alice", *IDB = "Bob";
    unsigned char Ppub[64], deA[128], deB[128];
    unsigned char xy[64], SA[SM3_len / 8], SB[SM3_len / 8];
    epoint *RA, *RB;
    big ke, x, y;
    zzn12 g1, g2, g3;
    int tmp, i;

    mip = mirsys(1000, 16);
    mip->IOBASE = 16;

    x = mirvar(0); y = mirvar(0); ke = mirvar(0);
    bytes_to_big(32, KE, ke);//主私钥,即随机数,这里事先定义好
    RA = epoint_init(); RB = epoint_init();
    zzn12_init(&g1); zzn12_init(&g2); zzn12_init(&g3);

    //初始化,设定参数和曲线
    tmp = ARS_SM9_Init();
    if (tmp != 0) return tmp;
    printf("\n用户A的ID号为:%s\n用户B的ID号为:%s\n",IDA,IDB);

    printf("\n*********************** SM9 密钥生成 ***************************");
    tmp = ARS_SM9_GenerateEncryptKey(hid, IDA, strlen(IDA), ke, Ppub, deA);//Alice的用户私钥deA生成
    if (tmp != 0)  return tmp;

    tmp = ARS_SM9_GenerateEncryptKey(hid, IDB, strlen(IDB), ke, Ppub, deB);//Bob的用户私钥deB生成
    if (tmp != 0)  return tmp;

    if (memcmp(Ppub, std_Ppub, 64) != 0)
        return SM9_GEPUB_ERR;

    if (memcmp(deA, std_deA, 128) != 0)
        return SM9_GEPRI_ERR;
    if (memcmp(deB, std_deB, 128) != 0)
        return SM9_GEPRI_ERR;

    printf("\n\n**********************主私钥 KE:*************************\n");
    for (i = 0; i<32; i++) printf("%02x", KE[i]);
    printf("\n\n**********************主公钥 Ppubs=[ke]P1:*************************\n");
    for (i = 0; i<64; i++) printf("%02x", Ppub[i]);
    printf("\n\n**************用户A私钥 deA = (xdeA, ydeA):*********************\n");
    for (i = 0; i<128; i++) printf("%02x", deA[i]);
    printf("\n\n**************用户B私钥 deB = (xdeB, ydeB):*********************\n");
    for (i = 0; i<128; i++) printf("%02x", deB[i]);

    printf("\n");
    printf("\n*********************** SM9 密钥交换 ***************************\n");

    printf("\n//////////////////// SM9 密钥交换 A1-A4://////////////////////////\n");
    tmp = ARS_SM9_KeyEx_InitA_I(hid, IDB, randA, Ppub, deA, RA);//计算RA
    if (tmp != 0) return tmp;

    printf("\n//////////////////////////// RA=[r]QB //////////////////////////////\n");
    epoint_get(RA, x, y);
    cotnum(x, stdout); cotnum(y, stdout);
    big_to_bytes(BNLEN, x, xy, 1); big_to_bytes(BNLEN, y, xy + BNLEN, 1);
    if (memcmp(xy, std_RA, BNLEN * 2) != 0)
        return SM9_ERR_RA;

    printf("\n//////////////////////// SM9 密钥交换 B1-B7:///////////////////////\n");
    tmp = ARS_SM9_KeyEx_ReB_I(hid, IDA, IDB, randB, Ppub, deB, RA, RB, SB, &g1, &g2, &g3);
    if (tmp != 0) return tmp;
    epoint_get(RB, x, y);
    big_to_bytes(BNLEN, x, xy, 1); big_to_bytes(BNLEN, y, xy + BNLEN, 1);
    if (memcmp(xy, std_RB, BNLEN * 2) != 0)
        return SM9_ERR_RB;
    if (memcmp(SB, std_SB, SM3_len / 8) != 0)
        return SM9_ERR_SB;

    printf("\n");
    printf("\n//////////////////////// SM9 密钥交换 A5-A8:///////////////////////");
    tmp = ARS_SM9_KeyEx_InitA_II(IDA, IDB, randA, Ppub, deA, RA, RB, SB, SA);
    if (tmp != 0) return tmp;
    if (memcmp(SA, std_SA, SM3_len / 8) != 0)
        return SM9_ERR_SA;

    printf("\n");
    printf("\n//////////////////////// SM9 密钥交换 B8:///////////////////////");
    tmp = ARS_SM9_KeyEx_ReB_II(IDA, IDB, g1, g2, g3, RA, RB, SA);
    if (tmp != 0) return tmp;

    printf("\n");
    return 0;
}

与国密复习相似的内容:

国密复习

国密复习 其中SM1和SM7是不公开的。 ZUC ZUC(ZU Chong zhi)算法一个流密码(序列密码),主要功能是产生密钥流,可以用机密性和完整性验证。 | 初始密钥 | 初始向量 | 输出(每次) | 轮数 | | | | | | | 128bit | 128bit | 32bit | 3

国密、商密和普密

国密、商密和普密 区分 国家将信息安全划分为三个等级:核密、普密和商密。其中核密最高,普密次之,商密最低。 核密指国家党政领导人及绝密单位的安全级别,此领域不存在任何商务行为; 普密是指国家党政军机关的信息安全级别 国密是国家自己制定的密码算法标准,商密和普密是《密码法》按密码用途进行分类。 三者的

[转帖]SM系列 国密算法

https://www.cndba.cn/dave/article/3347 为了保障商用密码的安全性,国家商用密码管理办公室制定了一系列密码标准,包括SM1(SCB2)、SM2、SM3、SM4、SM7、SM9、祖冲之密码算法(ZUC)那等等。 1 SM1对称密码 SM1 算法是分组密码算法,分组长

ECC(SM2) 简介及 C# 和 js 实现【加密知多少系列_6】

本文首先简单介绍了国密 ECC 的特点,然后再通过两种方式实现 SM2 进行了实践,提供的实现代码均已经过验证。

[转帖]瀚高数据库 SM3和MD5密码验证配置

我们都知道,瀚高数据库安全版v4.5和企业版v6都支持国密sm3。一般我们在initdb的时候,会通过选项“-A sm3”来指定,这样的效果是创建用户或修改密码时,默认就会使用sm3取密码的散列值。我们也可以在后期添将密码动态改为md5。 例如,我们当前默认是md5,现在要添加一个用户,使用sm3,

RELIC库学习

《RELIC库学习》 文章介绍:密码学与区块链技术实验室向开源项目RELIC贡献国密算法代码 了解 RELIC是由Diego F. Aranha开发的高效、灵活的开源密码原语工具箱,包含多精度整数运算、有限域(包含素数域和二元域)运算、椭圆曲线、双线性映射和扩域运算、密码协议(如RSA、Rabin、

文章学习:TPRE-分布式门限代理重加密

学习文章:TPRE:分布式门限代理重加密 前言 成方金科新技术实验室与隐语团队合作,构建了“基于国密的分布式门限代理重加密算法TPRE”,为用户提供了一种安全、高效、自主可控的数据共享和授权管理方案。在数据隐私保护和数据安全共享方面具有广泛的应用前景。 ⚠️:该算法由成方金科密码学研究员张曙光(知乎

商用密码应用安全性评估

> 了解密评,参考:https://www.zxcsec.com/Assessment.html ## 什么是商用密码应用安全性评估? 商用密码应用安全性评估(简称“**密评**”)是指对采用商用密码技术、产品和服务集成建设的网络和信息系统密码应用的**合规性、正确性、有效性进行评估**。 ## 国

[转帖]国发终于成功了!歼15开始换装太行发动机,国产战机全面淘汰俄发

https://www.toutiao.com/article/7169123680814105095/?wid=1670030647459 在刚结束的珠海航展上,国产太行发动机首次以家族的形式亮相,展出了包括二元矢量版本和轴对称矢量版本在内的5款太行发动机,让广大军迷大呼过瘾。而央视23号播出的《

冯登国院士:数据安全新方向——数据使用安全

链接: 冯登国院士:数据安全新方向——数据使用安全 近日,在2023中关村论坛——数据安全治理与发展分论坛上,冯登国院士做了主题为:《数据安全新方向:数据使用安全》的分享,以下是分享全文。 各位专家,各位嘉宾,大家好: 很高兴有这个机会与大家进行交流一下对数据安全的一些认识,发言题目是《数据安全新方