國密複習

國密複習

img

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