文章目录
- 《密码系统设计》实验
-
- 实验项目
- 实验二 密码算法实现
-
- 1-3 学时实践要求(30 分)
-
- 1. 在 Ubuntu或openEuler中(推荐 openEuler)中调试运行[商用密码检测中心https://www.scctc.org.cn/xzzx/sfydm/ydmxz/](https://www.scctc.org.cn/xzzx/sfydm/ydmxz/)提供的源代码,至少运行SM2,SM3,SM4代码。使用GmSSL命令验证你代码的正确性。使用Markdown记录详细记录实践过程,每完成一项功能或者一个函数git commit 一次。(14分)
- 2. 在[密标委网站http://www.gmbz.org.cn/main/bzlb.html](http://www.gmbz.org.cn/main/bzlb.html)查找SM2,SM3,SM4相关标准,分析代码实现与标准的对应关系。(6分)
- 3. 使用Rust完成SM2,SM3,SM4算法的实现(选做,10分)
- 4. 实验记录中提交 gitee 课程项目链接,提交本次实验相关 git log运行结果
- 5. 提交要求:
《密码系统设计》实验
实验项目
实验序号 | 实验名称 | 实验学时数 | 实验目的 | 实验内容 | 实验类型 | 学生学习预期成果 |
---|---|---|---|---|---|---|
实验二 | 密码算法实现 | 6 | 掌握常见商用密码算法的原理与实现 | 基于国产化平台使用C语言编程实现SM2、SM3、SM4等算法; | 验证性 | 1.基于Arm等平台和国产化操作系统使用C语言编程实现SM2、SM3、SM4算法; 2.对比分析算法实现的正确性和效率。 |
实验二 密码算法实现
1-3 学时实践要求(30 分)
1. 在 Ubuntu或openEuler中(推荐 openEuler)中调试运行商用密码检测中心https://www.scctc.org.cn/xzzx/sfydm/ydmxz/提供的源代码,至少运行SM2,SM3,SM4代码。使用GmSSL命令验证你代码的正确性。使用Markdown记录详细记录实践过程,每完成一项功能或者一个函数git commit 一次。(14分)
//SM2
//main.c加密解密
#include "miracl.h"
#include "mirdef.h"
#include "SM2_ENC.h"
#include "kdf.h"
#include <stdio.h>
#include <string.h>
// 主函数,调用SM2算法相关函数进行加密解密操作
int main()
{
int result;
big priKey;
epoint *pubKey;
unsigned char message[128];
unsigned char ciphertext[115 + 128];
unsigned char decryptedMessage[128];
unsigned char randK[32];
// 初始化MIRACL系统
mip = mirsys(1000, 16);
mip->IOBASE = 16;
priKey = mirvar(0);
pubKey = epoint_init();
// 初始化SM2相关参数
result = SM2_Init();
if (result!= 0)
{
printf("SM2初始化失败,错误码: %d\n", result);
return 1;
}
// 生成密钥对
// 这里简单生成一个随机私钥(实际应用中应使用安全的随机数生成器)
irand((long)time(NULL));
bigrand(para_n, priKey);
result = SM2_KeyGeneration(priKey, pubKey);
if (result!= 0)
{
printf("密钥生成失败,错误码: %d\n", result);
return 1;
}
// 准备要加密的消息
strcpy((char *)message, "20221417wzy");
// 生成随机数randK(实际应用中应使用安全的随机数生成器)
for (int i = 0; i < 32; i++)
{
randK[i] = (unsigned char)rand();
}
// 加密消息
result = SM2_Encrypt(randK, pubKey, message, strlen((char *)message), ciphertext);
if (result!= 0)
{
printf("加密失败,错误码: %d\n", result);
return 1;
}
printf("加密成功,密文:\n");
for (int i = 0; i < sizeof(ciphertext); i++)
{
printf("%02X", ciphertext[i]);
}
printf("\n");
// 解密消息
result = SM2_Decrypt(priKey, ciphertext, sizeof(ciphertext), decryptedMessage);
if (result!= 0)
{
printf("解密失败,错误码: %d\n", result);
return 1;
}
printf("解密成功,消息: %s\n", decryptedMessage);
// 清理MIRACL系统资源
mirexit();
return 0;
}
//SM2_ENC.c
#include "miracl.h"
#include "mirdef.h"
#include "SM2_ENC.h"
#include "kdf.h"
int Test_Point(epoint* point)
{
big x, y, x_3, tmp;
x = mirvar(0);
y = mirvar(0);
x_3 = mirvar(0);
tmp = mirvar(0);
//test if y^2=x^3+ax+b
epoint_get(point, x, y);
power(x, 3, para_p, x_3);
multiply(x, para_a, x);
divide(x, para_p, tmp);
add(x_3, x, x);
add(x, para_b, x);
divide(x, para_p, tmp);
power(y, 2, para_p, y);
if (compare(x, y) != 0)
return ERR_NOT_VALID_POINT;
else
return 0;
}
int Test_PubKey(epoint* pubKey)
{
big x, y, x_3, tmp;
epoint* nP;
x = mirvar(0);
y = mirvar(0);
x_3 = mirvar(0);
tmp = mirvar(0);
nP = epoint_init();
//test if the pubKey is the point at infinity
if (point_at_infinity(pubKey))// if pubKey is point at infinity, return error;
return ERR_INFINITY_POINT;
//test if x<p and y<p both hold
epoint_get(pubKey, x, y);
if ((compare(x, para_p) != -1) || (compare(y, para_p) != -1))
return ERR_NOT_VALID_ELEMENT;
if (Test_Point(pubKey) != 0)
return ERR_NOT_VALID_POINT;
//test if the order of pubKey is equal to n
ecurve_mult(para_n, pubKey, nP); // nP=[n]P
if (!point_at_infinity(nP)) // if np is point NOT at infinity, return error;
return ERR_ORDER;
return 0;
}
int Test_Null(unsigned char array[], int len)
{
int i = 0;
for (i = 0; i < len; i++) {
if (array[i] != 0x00)
return 0;
}
return 1;
}
int SM2_Init()
{
epoint* nG;
para_p = mirvar(0);
para_a = mirvar(0);
para_b = mirvar(0);
para_n = mirvar(0);
para_Gx = mirvar(0);
para_Gy = mirvar(0);
para_h = mirvar(0);
G = epoint_init();
nG = epoint_init();
bytes_to_big(SM2_NUMWORD, SM2_p, para_p);
bytes_to_big(SM2_NUMWORD, SM2_a, para_a);
bytes_to_big(SM2_NUMWORD, SM2_b, para_b);
bytes_to_big(SM2_NUMWORD, SM2_n, para_n);
bytes_to_big(SM2_NUMWORD, SM2_Gx, para_Gx);
bytes_to_big(SM2_NUMWORD, SM2_Gy, para_Gy);
bytes_to_big(SM2_NUMWORD, SM2_h, para_h);
ecurve_init(para_a, para_b, para_p, MR_PROJECTIVE);//Initialises GF(p) elliptic curve.
//MR_PROJECTIVE specifying projective coordinates
if (!epoint_set(para_Gx, para_Gy, 0, G))//initialise point G
{
return ERR_ECURVE_INIT;
}
ecurve_mult(para_n, G, nG);
if (!point_at_infinity(nG)) //test if the order of the point is n
{
return ERR_ORDER;
}
return 0;
}
int SM2_KeyGeneration(big priKey, epoint* pubKey)
{
int i = 0;
big x, y;
x = mirvar(0);
y = mirvar(0);
ecurve_mult(priKey, G, pubKey);//通过大数和基点产生公钥
epoint_get(pubKey, x, y);
if (Test_PubKey(pubKey) != 0)
return 1;
else
return 0;
}
int SM2_Encrypt(unsigned char* randK, epoint* pubKey, unsigned char M[], int klen, unsigned char C[])
{
big C1x, C1y, x2, y2, rand;
epoint* C1, * kP, * S;
int i = 0;
unsigned char x2y2[SM2_NUMWORD * 2] = {
0 };
SM3_STATE md;
C1x = mirvar(0);
C1y = mirvar(0);
x2 = mirvar(0);
y2 = mirvar(0);
rand = mirvar(0);
C1 = epoint_init();
kP = epoint_init();
S = epoint_init();
//Step2. calculate C1=[k]G=(rGx,rGy)
bytes_to_big(SM2_NUMWORD, randK, rand);
ecurve_mult(rand, G, C1); //C1=[k]G
epoint_get(C1, C1x, C1y);
big_to_bytes(SM2_NUMWORD, C1x, C, 1);
big_to_bytes(SM2_NUMWORD, C1y, C + SM2_NUMWORD, 1);
//Step3. test if S=[h]pubKey if the point at infinity
ecurve_mult(para_h, pubKey, S);
if (point_at_infinity(S))// if S is point at infinity, return error;
return ERR_INFINITY_POINT;
//Step4. calculate [k]PB=(x2,y2)
ecurve_mult(rand, pubKey, kP); //kP=[k]P
epoint_get(kP, x2, y2);
//Step5. KDF(x2||y2,klen)
big_to_bytes(SM2_NUMWORD, x2, x2y2, 1);
big_to_bytes(SM2_NUMWORD, y2, x2y2 + SM2_NUMWORD, 1);
SM3_KDF(x2y2, SM2_NUMWORD * 2, klen, C + SM2_NUMWORD * 3);
if (Test_Null(C + SM2_NUMWORD * 3, klen) != 0)
return ERR_ARRAY_NULL;
//Step6. C2=M^t
for (i = 0; i < klen; i++) {
C[SM2_NUMWORD * 3 + i] = M[i] ^ C[SM2_NUMWORD * 3 + i];
}
//Step7. C3=hash(x2,M,y2)
SM3_init(&md);
SM3_process(&md, x2y2, SM2_NUMWORD);
SM3_process(&md, M, klen);
SM3_process(&md, x2y2 + SM2_NUMWORD, SM2_NUMWORD);
SM3_done(&md, C + SM2_NUMWORD * 2);
return 0;
}
int SM2_Decrypt(big dB, unsigned char C[], int Clen, unsigned char M[]) {
SM3_STATE md;
int i = 0;
unsigned char x2y2[SM2_NUMWORD * 2] = {
0 };
unsigned char hash[SM2_NUMWORD] = {
0 };
big C1x, C1y, x2, y2;
epoint* C1, * S, * dBC1;
C1x = mirvar(0)