openssl实践-SM2国密算法签名
Openssl自1.1.1版本以后,提供了对SM2国密算法的支持。
签名算法基本流程
- 对数据进行摘要
- 使用私钥对摘要进行加密运算(即签名)
准备私钥
跟据非对称算法的原来,签名用的是私钥,所以签名前必须先准备私钥。私钥的获取有几种方式
生成公私钥
EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_sm2);
int ec_ret = EC_KEY_generate_key(ec_key);
首先创建一个ec_key, 然后用EC_KEY_generate_key
生成密钥对。
从ec_key中提取私钥
BIGNUM* pvk = EC_KEY_get0_private_key(ec_key);
从ec_key中提取公钥
EC_POINT* point = EC_KEY_get0_public_key(ec_key);
可以看到私钥和公钥的类型并不相同,一个是BIGNUM
,一个是EC_POINT
从PEM文件读入私钥
如果私钥是PEM文件,可以用PEM_read_bio_PrivateKey
读取,例如
pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
函数手册,参考https://www.openssl.org/docs/man1.1.1/man3/PEM_read_bio_PrivateKey.html
从原始密钥读取私钥
入股原始的密钥只包含密钥,例如,SM2的私钥是一个32字节的串,
74F3D6BCC82D29819BC9D9445210B3C581373715E3D728A54580B675C3CD6620
可以直接将这串密钥赋值给openssl的EC_KEY
pvk_bn = BN_bin2bn(pvk, CB_SM2_SECRETKEY_BYTES, NULL);
ec_key = EC_KEY_new_by_curve_name(NID_sm2);
group = EC_KEY_get0_group(ec_key);
EC_KEY_set_private_key(ec_key, pvk_bn)
也可以直接使用openssl提供的方法EVP_PKEY_new_raw_private_key
,不过该方法只支持下面几种算法:
- EVP_PKEY_X25519
- EVP_PKEY_ED25519
- EVP_PKEY_X448
- EVP_PKEY_ED448
这个函数的参考在这里 https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_get_raw_private_key.html
SM2私钥签名
设置pkey
EVP_PKEY* pkey = EVP_PKEY_new();
设置pkey和ec_key的关联
EVP_PKEY_set1_EC_KEY(pkey, ec_key)
设置type为EVP_PKEY_SM2
,表示要采用SM2算法进行后面的签名。
EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2);
设置摘要上下文,签名过程会自动计算消息摘要
EVP_MD_CTX* mctx = EVP_MD_CTX_new();
EVP_PKEY_CTX* sctx = EVP_PKEY_CTX_new(pkey, NULL);
设置id,根据SM2的国密规范,签名要带id
EVP_PKEY_CTX_set1_id(sctx, (const uint8_t *)id, strlen(id));
EVP_MD_CTX_set_pkey_ctx(mctx, sctx);
进行签名,国密算法采用SM3摘要
EVP_DigestSignInit(mctx, NULL, EVP_sm3(), NULL, pkey);
EVP_DigestSignUpdate(mctx, data, data_len);
EVP_DigestSignFinal(mctx, sig, &siglen);
sig
保存用户签名,签名的结果采用DER编码。下面是一个签名结果的例子
3045022100BB43CFF29D25CEFC01B0E1318725DC19FDD26C794B920CEEE8E16548055CD53402201925E8434F63DB7C489EDFB2B1B27ED160A4B94BEF1F626683C2B959D554CC56
本文结束。