SM2 加解密 一文理清

1. 给一个私钥的der文件。  

通过命令查看公私钥数据。

F:\project\simkey\now\>gmssl ec -inform der -in anca_ec_keypri.der -text
Using configuration from C:\Program Files\Common Files\SSL/openssl.cnf
read EC key
Private-Key: (256 bit)
priv:
    90:8d:22:29:03:f2:8d:bf:45:20:ff:57:77:d4:a1:
    cb:57:09:6b:99:45:51:62:bd:2b:d7:d3:60:b1:c1:
    fe:c2
pub:
    04:f8:40:b0:90:5c:da:84:bd:c3:01:c7:a9:d5:c3:
    68:fb:b0:4d:76:1b:3a:7f:2b:7b:df:5c:46:3d:8a:
    b7:83:25:16:b9:c9:df:4b:ab:53:58:c7:f0:be:e5:
    cd:4e:70:af:c6:8b:66:56:68:83:9b:cc:a2:8a:54:
    2c:6d:32:a8:a8
ASN1 OID: sm2p256v1
NIST CURVE: SM2
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIJCNIikD8o2/RSD/V3fUoctXCWuZRVFivSvX02Cxwf7CoAoGCCqBHM9V
AYItoUQDQgAE+ECwkFzahL3DAcep1cNo+7BNdhs6fyt731xGPYq3gyUWucnfS6tT
WMfwvuXNTnCvxotmVmiDm8yiilQsbTKoqA==
-----END EC PRIVATE KEY-----

公钥格式
公钥有两大种表示,通常是压缩或未压缩
1.未压缩公钥
通常以前缀04开头,后跟两个256位数字;一个用于点的x坐标,另一个用于点的y坐标。前缀04用于区分未压缩的公共密钥和以02或03开头的压缩公共密钥
即04||x||y

2.压缩公钥
y2 mod p =(x3 + 7)mod p
因为方程式的左侧是y2,所以y的解是平方根,它可以具有正值或负值。所得的y坐标可以在x轴之上或之下。因为该曲线是对称的,所以它在x轴上像镜子一样反射。因此,我们必须存储y的符号(正数或负数);因为每个选项代表一个不同的点和一个不同的公钥。在素数为p的有限域上用二进制算术计算椭圆曲线时,y坐标为偶数或奇数,对应于前面所述的正/负号。所以为了区分y的两个可能值,如果y为偶数,则存储压缩的公钥,前缀为02,如果奇数为03,则允许软件从x坐标正确推断出y坐标,然后解压缩指向该点的完整坐标的公钥。
 

2.  代码计算 31 加密数据

以下是der格式的公私钥和加密后数据。私钥包含公钥数据内容。

2022-12-29 14:39:38.806 17771-17771/com.zdxlz.safdemo D/MainActivity: onBtnEccPubKeyEncClick: 公钥:3059301306072A8648CE3D020106082A811CCF5501822D03420004F840B0905CDA84BDC301C7A9D5C368FBB04D761B3A7F2B7BDF5C463D8AB7832516B9C9DF4BAB5358C7F0BEE5CD4E70AFC68B665668839BCCA28A542C6D32A8A8
    私钥:30770201010420908D222903F28DBF4520FF5777D4A1CB57096B99455162BD2BD7D360B1C1FEC2A00A06082A811CCF5501822DA14403420004F840B0905CDA84BDC301C7A9D5C368FBB04D761B3A7F2B7BDF5C463D8AB7832516B9C9DF4BAB5358C7F0BEE5CD4E70AFC68B665668839BCCA28A542C6D32A8A8
2022-12-29 14:39:38.818 17771-17771/com.zdxlz.safdemo D/MainActivity: 加密后数据:3069022074B9BFD6D42AE771DB9789163905B7FADF2CD6852C54C89B4640A0364E27FDCC022011EFEA1D1A71DFA9B1C7ED54215A0CB1DDB9E2942B65C4715EBC91100C49E0FF042059FF842174AB4CF82F1454C4A2E7673BDD97539D8805B579CEBEA202298E701A0401F8
 

der解析得到实际的 C1 C2 C3. 

SM2非对称加密的结果由C1,C2,C3三部分组成。其中C1是根据生成的随机数计算出的椭圆曲线点,C2是密文数据,C3是SM3的摘要值。最开始的国密标准的结果是按C1,C2,C3顺序存放的,新标准的是按C1,C3,C2顺序存放的,因此我们这边在做SM2加密时新增了密文数据顺序设置,用以兼容之前的SM2算法加密。

30690220
74B9BFD6D42AE771DB9789163905B7FADF2CD6852C54C89B4640A0364E27FDCC    XCoordinate
0220
11EFEA1D1A71DFA9B1C7ED54215A0CB1DDB9E2942B65C4715EBC91100C49E0FF    YCoordinate
0420
59FF842174AB4CF82F1454C4A2E7673BDD97539D8805B579CEBEA202298E701A    HASH
0401
F8                                                                  ciphertext

sm2 加密后结构体:

gmssl3.0如下:

typedef struct {
   SM2_POINT point;
   uint8_t hash[32];
   uint8_t ciphertext_size;
   uint8_t ciphertext[SM2_MAX_PLAINTEXT_SIZE];
} SM2_CIPHERTEXT;
typedef struct {
   uint8_t x[32];
   uint8_t y[32];
} SM2_POINT;

最终输出了der格式,因此数据长度不是原数据加96.

96 = 32 (X)  + 32 (Y) + 32 (HASH) ;

加密后数据长度和加密前一致。 只是后多出上面的96字节数据。

 3. 在线工具:

SM2加解密 (goto327.top)  优先使用

SM2加密 SM2解密 - 个人工具小站 (javalang.cn)

在线SM2国密加密/解密—LZL在线工具 (lzltool.com)

使用工具解密成功:

注:

从以上加解密算法流程看。  加密存在一个随机数,因此每次加密计算的结果都不一样。 解密需要使用C1 C3 C2 三个数据才可以解密成功。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一些关于 JavaScript 和 Java 中 SM2 加解密的基本信息。 JavaScript 中的 SM2 加解密可以使用 jsrsasign 库进行实现。以下是一个简单的示例代码: ```javascript // 密钥对生成 var ec = new KJUR.crypto.ECDSA({'curve': 'sm2'}); var keypair = ec.generateKeyPairHex(); // 加密 var pubKey = keypair.ecpubhex; var plainText = 'hello world'; var cipher = KJUR.crypto.Cipher.encrypt(pubKey, plainText, 'SM2'); // 解密 var privKey = keypair.ecprvhex; var decrypted = KJUR.crypto.Cipher.decrypt(privKey, cipher, 'SM2'); console.log(decrypted); ``` Java 中的 SM2 加解密可以使用 Bouncy Castle 库进行实现。以下是一个简单的示例代码: ```java // 密钥对生成 ECNamedCurveParameterSpec sm2Spec = ECNamedCurveTable.getParameterSpec("sm2p256v1"); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); kpg.initialize(sm2Spec, new SecureRandom()); KeyPair keyPair = kpg.generateKeyPair(); // 加密 Cipher cipher = Cipher.getInstance("SM2", new BouncyCastleProvider()); cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); byte[] plainText = "hello world".getBytes(); byte[] cipherText = cipher.doFinal(plainText); // 解密 cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); byte[] decrypted = cipher.doFinal(cipherText); System.out.println(new String(decrypted)); ``` 需要注意的是,JavaScript 和 Java 中的 SM2 加解密算法的实现细节可能有所不同,需要根据具体需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值