编写 My_GenKeyPair,SM2Sig,SM2VerifySig函数
时间: 2023-06-23 17:09:55 浏览: 110
以下是基于Python实现的My_GenKeyPair,SM2Sig和SM2VerifySig函数:
```python
from gmssl import sm2, func
def My_GenKeyPair():
# 生成SM2密钥对
pri_key = sm2.gen_private_key()
pub_key = sm2.get_public_key(pri_key)
# 将私钥和公钥返回
return pri_key, pub_key
def SM2Sig(pri_key, msg):
# 将消息转换为byte类型
msg = msg.encode()
# 使用私钥进行签名
sig = sm2.sign(msg, pri_key)
# 将签名返回
return sig
def SM2VerifySig(pub_key, msg, sig):
# 将消息转换为byte类型
msg = msg.encode()
# 验证签名
result = sm2.verify(msg, sig, pub_key)
# 返回验证结果
return result
```
其中,My_GenKeyPair函数用于生成SM2密钥对,SM2Sig函数用于对消息进行签名,SM2VerifySig函数用于验证签名。在实际应用中,需要使用生成的密钥对对消息进行加密和解密,这里只提供了签名和验证签名的实现。
相关问题
使用visual studio调用 My_GenKeyPair 产生非对称密钥对; 调用 SM2Sig 进行签名,pbUserID=NULL; 再调用 SM2VerifySig 验证签名并详细编写My_GenKeyPair,SM2Sig,SM2VerifySig函数代码
下面是使用 Visual Studio 编写 My_GenKeyPair、SM2Sig 和 SM2VerifySig 函数的代码。
My_GenKeyPair 函数:
```c++
#include <openssl/ec.h>
#include <openssl/obj_mac.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#define KEY_LENGTH 1024
int My_GenKeyPair(char *pubkeyfile, char *privkeyfile)
{
int ret = 0;
RSA *r = NULL;
BIGNUM *bne = NULL;
BIO *bp_public = NULL, *bp_private = NULL;
int bits = KEY_LENGTH;
unsigned long e = RSA_F4;
// 生成 RSA 密钥对
bne = BN_new();
ret = BN_set_word(bne, e);
if (ret != 1) {
goto finish;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, bits, bne, NULL);
if (ret != 1) {
goto finish;
}
// 将密钥对写入文件
bp_public = BIO_new_file(pubkeyfile, "w+");
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
if (ret != 1) {
goto finish;
}
bp_private = BIO_new_file(privkeyfile, "w+");
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
if (ret != 1) {
goto finish;
}
finish:
if (r) {
RSA_free(r);
}
if (bne) {
BN_free(bne);
}
if (bp_public) {
BIO_free_all(bp_public);
}
if (bp_private) {
BIO_free_all(bp_private);
}
return ret;
}
```
SM2Sig 函数:
```c++
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sm2.h>
int SM2Sig(const unsigned char *msg, size_t msglen, const char *privkeyfile, unsigned char *sig, size_t *siglen)
{
int ret = 0;
EC_KEY *ec_key = NULL;
EVP_MD_CTX *md_ctx = NULL;
unsigned char dgst[32];
size_t dgstlen;
const EVP_MD *md;
BIGNUM *k = NULL;
EC_POINT *P = NULL;
// 读取私钥
ec_key = EC_KEY_new_by_curve_name(NID_sm2);
if (!ec_key) {
goto finish;
}
FILE *fp = fopen(privkeyfile, "r");
if (!fp) {
goto finish;
}
PEM_read_ECPrivateKey(fp, &ec_key, NULL, NULL);
fclose(fp);
fp = NULL;
// 计算消息摘要
md = EVP_sm3();
md_ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(md_ctx, md, NULL);
EVP_DigestUpdate(md_ctx, msg, msglen);
EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen);
EVP_MD_CTX_free(md_ctx);
md_ctx = NULL;
// 生成随机数 k
k = BN_new();
ret = BN_rand_range(k, EC_GROUP_order(EC_KEY_get0_group(ec_key)));
if (ret != 1) {
goto finish;
}
// 计算椭圆曲线点 P = [k]G
P = EC_POINT_new(EC_KEY_get0_group(ec_key));
ret = EC_POINT_mul(EC_KEY_get0_group(ec_key), P, k, NULL, NULL, NULL);
if (ret != 1) {
goto finish;
}
// 计算 r = (e + x1) mod n
BIGNUM *r = BN_new();
const EC_POINT *pubkey = EC_KEY_get0_public_key(ec_key);
EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec_key), pubkey, r, NULL, NULL);
BN_add(r, r, dgst);
BN_mod(r, r, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL);
// 计算 s = ((1 + dA)^-1 * (k - r * dA)) mod n
BIGNUM *s = BN_new();
BIGNUM *dA = BN_new();
const BIGNUM *privkey = EC_KEY_get0_private_key(ec_key);
BN_copy(dA, privkey);
BN_mod_add(dA, dA, EC_GROUP_order(EC_KEY_get0_group(ec_key)), EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL);
BN_add_word(dA, 1);
BN_mod_inverse(dA, dA, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL);
BN_mul(s, r, privkey, NULL);
BN_sub(s, k, s);
BN_mod_mul(s, s, dA, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL);
// 将 r 和 s 拼接成签名数据
unsigned char *p = sig;
*p++ = 0x30;
p++; // 后面填充长度
unsigned char *rpos = p;
*p++ = 0x02;
if (BN_num_bits(r) % 8 == 0) {
*p++ = BN_num_bits(r) / 8;
} else {
*p++ = BN_num_bits(r) / 8 + 1;
}
BN_bn2bin(r, p);
p += *rpos + 1;
unsigned char *spos = p;
*p++ = 0x02;
if (BN_num_bits(s) % 8 == 0) {
*p++ = BN_num_bits(s) / 8;
} else {
*p++ = BN_num_bits(s) / 8 + 1;
}
BN_bn2bin(s, p);
p += *spos + 1;
// 填充签名数据长度
*spos += 2;
*rpos += 2;
*siglen = p - sig;
finish:
if (ec_key) {
EC_KEY_free(ec_key);
}
if (md_ctx) {
EVP_MD_CTX_free(md_ctx);
}
if (k) {
BN_free(k);
}
if (P) {
EC_POINT_free(P);
}
if (r) {
BN_free(r);
}
if (s) {
BN_free(s);
}
return ret;
}
```
SM2VerifySig 函数:
```c++
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/sm2.h>
int SM2VerifySig(const unsigned char *msg, size_t msglen, const char *pubkeyfile, const unsigned char *sig, size_t siglen)
{
int ret = 0;
EC_KEY *ec_key = NULL;
EVP_MD_CTX *md_ctx = NULL;
unsigned char dgst[32];
size_t dgstlen;
const EVP_MD *md;
BIGNUM *r = NULL, *s = NULL;
EC_POINT *P = NULL;
// 读取公钥
ec_key = EC_KEY_new_by_curve_name(NID_sm2);
if (!ec_key) {
goto finish;
}
FILE *fp = fopen(pubkeyfile, "r");
if (!fp) {
goto finish;
}
PEM_read_EC_PUBKEY(fp, &ec_key, NULL, NULL);
fclose(fp);
fp = NULL;
// 解析签名数据
unsigned char *p = (unsigned char *)sig;
if (*p++ != 0x30) {
goto finish;
}
size_t len = *p++;
if (len > siglen - 2) {
goto finish;
}
if (*p++ != 0x02) {
goto finish;
}
size_t rlen = *p++;
if (rlen > len - 3) {
goto finish;
}
r = BN_new();
BN_bin2bn(p, rlen, r);
p += rlen;
len -= rlen + 2;
if (*p++ != 0x02) {
goto finish;
}
size_t slen = *p++;
if (slen != len) {
goto finish;
}
s = BN_new();
BN_bin2bn(p, slen, s);
// 计算消息摘要
md = EVP_sm3();
md_ctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(md_ctx, md, NULL);
EVP_DigestUpdate(md_ctx, msg, msglen);
EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen);
EVP_MD_CTX_free(md_ctx);
md_ctx = NULL;
// 计算椭圆曲线点 P = [s]G + [r]PA
P = EC_POINT_new(EC_KEY_get0_group(ec_key));
EC_POINT *PA = EC_POINT_dup(EC_KEY_get0_public_key(ec_key), EC_KEY_get0_group(ec_key));
ret = EC_POINT_mul(EC_KEY_get0_group(ec_key), P, s, PA, r, NULL);
if (ret != 1) {
goto finish;
}
// 计算 e = H(M)
BIGNUM *e = BN_new();
BN_bin2bn(dgst, sizeof(dgst), e);
// 计算 t = (r + x1) mod n
BIGNUM *t = BN_new();
const EC_POINT *pubkey = EC_KEY_get0_public_key(ec_key);
EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec_key), pubkey, t, NULL, NULL);
BN_add(t, t, r);
BN_mod(t, t, EC_GROUP_order(EC_KEY_get0_group(ec_key)), NULL);
// 验证签名是否正确
ret = BN_cmp(t, e) == 0;
finish:
if (ec_key) {
EC_KEY_free(ec_key);
}
if (md_ctx) {
EVP_MD_CTX_free(md_ctx);
}
if (r) {
BN_free(r);
}
if (s) {
BN_free(s);
}
if (P) {
EC_POINT_free(P);
}
return ret;
}
```
这些函数使用 OpenSSL 库实现了生成非对称密钥对、SM2 签名和验证签名的功能。在编写程序时,需要将 OpenSSL 库链接到程序中。
详细编写代码实现使用visual studio调用 My_GenKeyPair 产生非对称密钥对; 调用 SM2Sig 进行签名,pbUserID=NULL; 再调用 SM2VerifySig 验证签名
以下是使用Visual Studio编写的示例代码:
```c++
#include "stdafx.h"
#include <iostream>
#include "MyCrypto.h" // 包含自定义的加密函数头文件
int main()
{
// 产生非对称密钥对
std::string strPriKey;
std::string strPubKey;
My_GenKeyPair(strPriKey, strPubKey);
// 显示生成的密钥对
std::cout << "私钥:" << strPriKey << std::endl;
std::cout << "公钥:" << strPubKey << std::endl;
// 要签名的明文
std::string strPlainText = "Hello, World!";
// 对明文进行签名
std::string strSignature = SM2Sig(strPlainText, strPriKey, NULL);
// 显示签名结果
std::cout << "签名结果:" << strSignature << std::endl;
// 验证签名
bool bVerify = SM2VerifySig(strPlainText, strSignature, strPubKey, NULL);
// 显示验证结果
if (bVerify)
{
std::cout << "签名验证成功!" << std::endl;
}
else
{
std::cout << "签名验证失败!" << std::endl;
}
return 0;
}
```
需要注意的是,上述代码中的 `stdafx.h` 文件是 Visual Studio 自动生成的预编译头文件,如果你的项目中没有该文件,可以将 `#include "stdafx.h"` 删除,并在项目属性中禁用预编译头文件。另外,`MyCrypto.h` 文件是自定义的加密函数头文件,需要根据实际情况进行修改。
阅读全文