关于SM2签名算法的实现

使用SM2签名算法时发现采购的USBKEY竟然没有实现相关的SKF接口,无奈只能通过其他方式自己实现。

查阅相关标准文档后发现,国密标准的SM2签名算法,并不是简单的将明文通过SM3算法Hash,再将Hash结果通过SM2算法使用私钥进行签名。

Hash这块比较复杂,要经过两次SM3算法进行Hash。
中间还有Za参与运算。

在这里插入图片描述

第一次Hash其实只是对Za的Hash,Za里面甚至包含了公钥信息(Xa,Ya),一些预定义的值(即曲线参数),详见附件A.2。得到Za的Hash结果后,与明文进行拼接,拼接之后的数据再进行一次Hash,将最后一次Hash的结果送入SM2算法进行签名。

示例代码如下:

 unsigned char Pubkey[64]; 
 memcpy(Pubkey, ((char*)&(key_pv.XCoordinate)) + 32, 32); 
 memcpy(Pubkey + 32, ((char*)&(key_pv.YCoordinate)) + 32, 32); 

 unsigned char id[] = { 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38 }; 
 unsigned char a[] = { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC }; 
 unsigned char b[] = { 0x28,0xE9,0xFA,0x9E,0x9D,0x9F,0x5E,0x34,0x4D,0x5A,0x9E,0x4B,0xCF,0x65,0x09,0xA7,0xF3,0x97,0x89,0xF5,0x15,0xAB,0x8F,0x92,0xDD,0xBC,0xBD,0x41,0x4D,0x94,0x0E,0x93 }; 
 unsigned char xg[] = { 0x32,0xC4,0xAE,0x2C,0x1F,0x19,0x81,0x19,0x5F,0x99,0x04,0x46,0x6A,0x39,0xC9,0x94,0x8F,0xE3,0x0B,0xBF,0xF2,0x66,0x0B,0xE1,0x71,0x5A,0x45,0x89,0x33,0x4C,0x74,0xC7 }; 
 unsigned char yg[] = { 0xBC,0x37,0x36,0xA2,0xF4,0xF6,0x77,0x9C,0x59,0xBD,0xCE,0xE3,0x6B,0x69,0x21,0x53,0xD0,0xA9,0x87,0x7C,0xC6,0x2A,0x47,0x40,0x02,0xDF,0x32,0xE5,0x21,0x39,0xF0,0xA0 }; 
 unsigned char sum[1024];   //这个就是Za 
 unsigned char predata[32];  //这个是Za Hash后的值

 memset(sum, 0, 1024); 
 memset(sum + 1, 128, 1); 
 memcpy(sum + 2, id, 16); 
 memcpy(sum + 2 + 16, a, 32); 
 memcpy(sum + 2 + 16 + 32, b, 32); 
 memcpy(sum + 2 + 16 + 32 + 32, xg, 32); 
 memcpy(sum + 2 + 16 + 32 + 32 + 32, yg, 32); 
 memcpy(sum + 2 + 16 + 32 + 32 + 32 + 32, Pubkey, 64); 

 rv = usb_key_Function_table.SKF_DigestInit_(hDev, SGB_SM3, NULL, NULL, 0, &hHash); 
 if (rv != SAR_OK) { 
  printf("first SKF_DigestInit error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 pulHashLen = sizeof(predata); 
 rv = usb_key_Function_table.SKF_Digest_(hHash, sum, 64 + 2 + 16 + 32 + 32 + 32 + 32, predata, &pulHashLen); 
 if (rv != SAR_OK) { 
  printf("first SKF_Digest_ error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 rv = usb_key_Function_table.SKF_DigestInit_(hDev, SGB_SM3, NULL, NULL, 0, &hHash); 
 if (rv != SAR_OK) { 
  printf("second SKF_DigestInit error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 rv = usb_key_Function_table.SKF_DigestUpdate_(hHash, predata, sizeof(predata)); 
 if (rv != SAR_OK) { 
  printf("second SKF_Digest_update error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 rv = usb_key_Function_table.SKF_DigestUpdate_(hHash, pbData, ulDataLen); 
 if (rv != SAR_OK) { 
  printf("second SKF_Digest_update error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 pulHashLen = sizeof(pbHashData); 
 rv = usb_key_Function_table.SKF_DigestFinal_(hHash, pbHashData, &pulHashLen); 
 if (rv != SAR_OK) { 
  printf("second SKF_Digest_final error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 rv = usb_key_Function_table.SKF_ECCSignData_(hContainer, pbHashData, pulHashLen, pSignature); 
 if (rv != SAR_OK) { 
  printf("SKF_ECCSignData error,rv=%x\n", rv); 
  usb_key_Function_table.SKF_CloseApplication_(hApplication); 
  usb_key_Function_table.SKF_DisConnectDev_(hDev); 
  return rv; 
 } 

 
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SM2是一种国密算法,是一种基于椭圆曲线密码体制的数字签名算法,是中国政府推荐的公钥算法。Java 8及以上版本的标准库已经支持SM2算法,您可以使用Java自带的API来实现SM2签名算法。 Java中SM2算法实现位于java.security包下,具体可以通过下面的代码进行调用: ```java import java.security.*; import java.security.spec.*; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; public class SM2Demo { static { Security.addProvider(new BouncyCastleProvider()); } public static void main(String[] args) throws Exception { String plainText = "Hello World"; // 生成密钥对 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); kpg.initialize(new ECGenParameterSpec("sm2p256v1"), new SecureRandom()); KeyPair kp = kpg.generateKeyPair(); // 签名 Signature signature = Signature.getInstance("SM3withSM2", "BC"); signature.initSign(kp.getPrivate(), new SecureRandom()); signature.update(plainText.getBytes()); byte[] sign = signature.sign(); System.out.println("signature: " + Hex.toHexString(sign)); // 验证签名 Signature signature2 = Signature.getInstance("SM3withSM2", "BC"); signature2.initVerify(kp.getPublic()); signature2.update(plainText.getBytes()); boolean verified = signature2.verify(sign); System.out.println("signature verified: " + verified); } } ``` 在上面的代码中,首先通过`KeyPairGenerator`生成SM2密钥对,然后使用`Signature`类进行签名和验证操作。其中,`BC`表示使用BouncyCastle作为提供方,`sm2p256v1`表示使用SM2算法中的椭圆曲线参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值