國密複習
其中SM1和SM7是不公開的。
ZUC(ZU Chong zhi)演演算法一個串流加密法(序列密碼),主要功能是產生金鑰流,可以用機密性和完整性驗證。
初始金鑰 | 初始向量 | 輸出(每次) | 輪數 |
---|---|---|---|
128bit | 128bit | 32bit | 32輪 |
金鑰流生成演演算法是核心,主要分為兩個階段:初始化階段和工作階段。
演演算法從流程上分為上下三層:16級的線性反饋移位暫存器(LFSR)、位元重組(BR)和非線性函數(F)
分為兩個模式:初始化模式和工作模式
(1)初始化模式
LSFR接收一個31bit的\(u\),其中\(u\)是非線性函數\(F\)的32bit的輸出\(W\)通過捨棄最低位得到的,即\(u=W>>1\)。
\(LFSRWithInitialisation(u)\)
{
}
(2)工作模式
該模式下,LSFR沒有輸入:
$LFSRWithWorkMode() $
{
}
從LSFR中的16個暫存器中抽取128bit組成的4個32bit的\(X_0,X_1,X_2,X_3\),其中\(X_0,X_1,X_2\)用於下面的非線性函數\(F\),\(X_3\)用於金鑰流生成。
\(BitReconstruction()\)
{
}
其中,對於每個\(i\),\(s_i\)是31bit,所以\(s_{iH}\)是取\(s_i\)的第30bit到第15位元。
\(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)\)
{
}
其中\(S()\)是非線性S盒變換【混淆】,與AES和SM4一樣,都是取前4bit為行,後4bit為列,且這裡輸入的32bit,需要經過4個S盒,即\(S=(S_0,S_1,S_0,S_1)\);另外\(L()\)是迴圈左移【擴散】:
將輸入的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的子串:
下面構造擴充套件出16個31bit的整數\(s_{i}=k_{i}\left\|d_{i}\right\| i v_{i}\):
(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;
}
ZUC-128加密演演算法,主要用於新一代寬頻無線行動通訊系統的國際標準(4G標準)中的加解密。
加密演演算法分為三步:初始化、金鑰流生成和加解密:
根據金鑰\(CK\)和其他輸入引數構造初始金鑰\(k\)和初始向量\(IV\):
完整性驗證類似於Hash,對訊息生成一個唯一的MAC碼。
演演算法核心就是為訊息生成一個唯一的認證碼,主要分為:初始化、金鑰流生成和生成訊息鑑別碼的過程:
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演演算法和ECC演演算法相比:
SM2演演算法分為基於素域和基於二元擴域的計算,下面介紹的是基於素域(有限域)計算的。
橢圓曲線公鑰密碼基於橢圓曲線的性質:
在多倍點運算中,已知多倍點\((B)\)和基點\((A)\),求解倍數\((k)\)問題稱為橢圓曲線上的離散對數問題,對於一般橢圓曲線的離散對數問題,目前只存在指數級計算複雜度的求解方法,與大數分解問題及有限域上的離散對數問題相比,橢圓曲線上的離散對數問題的求解難度大的多,因此,在相同安全程度下,橢圓曲線密碼較其他公鑰密碼所需的金鑰規模要小得多!
SM2演演算法用到了三個輔助演演算法:雜湊演演算法(SM3)、金鑰派生函數(KDF)和亂數發生器,這三類輔助演演算法的強弱直接影響到演演算法的安全性。
使用的SM3,生成256bit的雜湊值。
就是從一個共用的祕密位元串中派生出金鑰,金鑰派生函數需要使用雜湊函數:
使用國家釋出的亂數發生器。
假設存在兩方:A(加密)和B(解密)方。
素域\(F_p\)下SM2演演算法的引數:
其中位元串\(SEED\)和引數\((a,b)\)的生成如下:
B方生成使用者金鑰對:私鑰\(d_B\)和公鑰\(P_B\):
A方要加密的是長度為\(klen\)長的位元串\(M\),這裡使用的是公鑰\(P_B\)加密的:
其中訊息\(M\)不是編碼到橢圓曲線上,這裡是直接對字串加密,產生的密文也是字串,加密流程圖如下:
B方收到密文\(C\)後,利用私鑰\(d_B\)解密:
加密和解密都需要使用KDF生成金鑰\(t\),具體解密流程圖如下:
根據生成的使用者公鑰\(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;
}
基本引數設定與加解密相同,假設簽名方為A,驗籤方為B:
/****************************************************************
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通過互動的訊息傳遞,用各自的私鑰和對方的公鑰來商定一個只有他們知道的祕密金鑰,這個共用的祕密金鑰通常用於對稱加密中,金鑰交換協定能用於金鑰管理和協商。
使用者A為發起方,使用者B為響應方,協商獲得的祕密金鑰長度為\(klen\)bit,
/****************************************************************
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是國家2010年公佈的一種密碼雜湊演演算法,該演演算法能對\(l\)bit的訊息hash,生成256bit的雜湊值,演演算法主要分為兩步:訊息填充和迭代壓縮,其中迭代壓縮有包含訊息擴充套件、壓縮函數和輸出雜湊值。
分組長度 | 雜湊長度 |
---|---|
512bit | 256bit |
下面是演演算法用到的常數和函數:
\(l\)bit的訊息經過訊息\(m\)填充後,得到\(m'\)訊息的位元數是512的倍數。
對迭代壓縮前訊息分組\(B^{i}\)(一個字,512bit)進行擴充套件得到132個字\(W_0,...,W_{63},W_0',...,W_{63}'\):
\(ABCDEFGH\)是字暫存器(32bit),壓縮函數輸入的\(V^{(0)}\)是256bit的初始IV,\(B^{(0)}\)是訊息擴充套件後的第一個分組(5125bit),輸出的是256bit的\(V^{(1)}\),依次計算直到計算出\(V^{(n)}\),並作為最後的雜湊值:
#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用於WAPI(無線區域網鑑別和保密基礎協定)的分組密碼演演算法,2006年公佈的第一個商密。
分組長度 | 金鑰長度 | 輪數 |
---|---|---|
128bit | 128bit | 32 |
輸入128bit的明文分組,輸出128bit的密文,下面定義「1個字=32bit=4個位元組」。
輪函數\(F()\)輸入4個字(128bit)\((X_0,X_1,X_2,X_3)\)和一個字(32bit)的輪金鑰\(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}\)
就是4個S盒並行,其作用是混淆,輸入的是\(A=(a_0,a_1,a_2,a_3)\)(4個位元組,32bit),輸出的是\(B=(b_0,b_1,b_2,b_3)\)(32位元)即:
其中\(S(a)\)是一個S盒變換,輸入\(a\)是一個位元組(8bit),輸出的\(S(a)\)也是8bit。
其中S盒變換,與AES相似:行(前4bit),列(後4bit)
線性變換\(L(B)\)的作用是擴散,其功能就是迴圈移位和互斥或,輸入的\(B\)是一個字(32bit),輸出的\(C=L(B)\)也是一個字(32bit),具體如下:
反序變換\(R\)就是在最後一輪後生成的\((x_{32},X_{33},X_{34},X_{35})\)進行反序輸出,即
輸入的初始金鑰為\(MK=(MK_0,MK_1,MK_2,MK_3)\)(128bit),採用32輪迭代,每輪輸出一個輪金鑰\(rk_i,(i=0,...,31)\)(32bit)
所需引數:
引數生成方式:
設\(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個固定引數:
其中\(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'()\)有所不同:
解密與加密相似,不同的是輪金鑰使用的順序,即解密時使用的輪金鑰為\(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;
}
/*
* 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;
}
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)
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)
最後的訊息認證函數,就是將金鑰和密文進行雜湊
解密流程:
/****************************************************************
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)符號介紹:
(2)輔助函數
(3)演演算法流程:
下面是簽名流程圖:
設訊息是位元串\(M\),簽名步驟如下:
下面是驗籤流程圖:
假設驗證者收到訊息和簽名\(\left (h',S' \right )\),簽名步驟如下:
/****************************************************************
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)基本概念
(2)輔助函數
⚠️:\(H1(),H2()\)函數和簽名方案相同,多了一個KDF
/****************************************************************
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;
}