解决对接JAVA SM2加密遇到的坑

遇到有接口需要使用国密的SM2算法,对方使用的是JAVA,我们使用的是go,原以为都是标准算法不会有什么大问题,结果巨坑无法..

对方使用的加密模块,SM2.java和SM2KeyPairs.java,不知道最初是谁开发的,网上貌似很多都是这个版本的实现,但是和go的交互总是有问题,用这个java模块加密的,go里面怎么也无法正确解密。仔细核对之后发现,这个java模块有几个地方并不符合GB/T32891的标准。

SM2加密的流程

SM2使用的椭圆曲线基点记为G,私钥为整数d, 公钥为P = dG.,这里K、G为椭圆曲线上的点,d为正整数

选择随机整数k,计算 C1 = kG, C4 = kP

以点C4的X/Y两坐标为参数,计算一组字节流T,与明文进行异或运算,结果为C2

已C1和明文组合,用SM3算法计算哈希值C3

将C1、C2、C3组合为加密后的密文

这里只要得到C4,便能进行解密,而C4 = kP = kdP = dkP = d(kC) = dC1。而C1是密文的一部分,所以有了私钥d便可以进行解密。

这里的P、G、C1、C4是椭圆曲线上的点,点的乘法只具有几何意义上,并非2X3=6的算术运算。

SM2 java模块与标准差异

1. 加密密文的组合

加密后的密文,标准为C1 || C3 || C2,C3位SM3哈系值,而这个库中结果为 C1 || C2 || C3。

2. Java BigInteger的最高位为1时编码错误

Java中,BigInteger的最高位为1时,toByteArray()得到的字节数组会多一位,在前面多了一个为0的字节,应该是要表示为正数。导致运算结果和其他语言的不一致。

3. 计算T时的差异

计算T时,需要用点C4的X坐标和Y坐标组合进行,这个库里直接调用bouncycastle库里,ECPoint类的getEncoded()的方法,得到的结果是在字节流里加了一个字节(0x4),实际是不需要的,导致计算的字节流T有差异

4. 取点的X/Y坐标时没有正则化

java的bouncycastle库里,在椭圆曲线的计算中,使用了X/Y/Z三个坐标,而其他的实现可能是没有Z坐标的,所以调用点的坐标的时候,应该调用normalize()方法正则化后使用,这时Z坐标是1。

而在这个库中,并没有进行正则化的操作,导致加密结果无法与其他程序进行交互,除非对方也使用的bouncycastle库,可实现方式与其类似。

补充知识:SM2数字签名算法java实现

给出我的SM2数字签名算法代码Java实现,所属文件SM2Signer.java

@Override
public BigInteger[] generateSignature(byte[] message) {
  ECDomainParameters ec = key.getParameters();
  BigInteger n = ec.getN(); //阶n
  ECPoint G = ec.getG();  //基点G
  BigInteger r, s;
  // 获取私钥d
  BigInteger d = ((ECPrivateKeyParameters)key).getD();

  ECMultiplier basePointMultiplier = createBasePointMultiplier();
  // 初始化随机数生成器
  if (kCalculator.isDeterministic()) {
    kCalculator.init(n, d, message);
  } else {
    kCalculator.init(n, random);
  }

  do { // 计算s
    BigInteger k;
    BigInteger e;
    BigInteger tmp;
    BigInteger tmp2;
    do { // 计算r,参照GM/T 0003.2-2012 6.1
      k = kCalculator.nextK();

      ECPoint p = basePointMultiplier.multiply(G, k).normalize();

      e = org.bouncycastle.util.BigIntegers.fromUnsignedByteArray(message);
      // r = (e + x) mod n
      r = p.getAffineXCoord().toBigInteger().add(e).mod(n);

    } while (r.equals(ZERO) || r.add(k).equals(n));

    // tmp = (1+d).inverse
    tmp = d.add(ONE).modInverse(n);
    // tmp2 = k - r*d
    tmp2 = k.subtract(r.multiply(d));
    s = tmp.multiply(tmp2).mod(n);

  } while (s.equals(ZERO));

  return new BigInteger[] {r,s};
}

以上这篇解决对接JAVA SM2加密遇到的坑就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java实现md5和base64加密解密的示例代码

    import java.io.IOException; import java.security.MessageDigest; import sun.misc.BASE64Encoder; import sun.misc.BASE64Decoder; public class MD5Util { /** * MD5加密 */ public static String md5Encryption(String str) { MessageDigest md5 = null; try { md5 =

  • Kettle中使用JavaScrip调用jar包对文件内容进行MD5加密的操作方法

    Kettle中使用JavaScript调用jar包对文件内容进行MD5加密.本文主要知识点: JavaScript调用jar包对文件内容进行MD5加密,返回加密md5值 Kettle实现对文件内容的加密,返回加密md5值 2.使用方法 1)下载jar包 http://xiazai.jb51.net/202009/yuanma/filemd5hash_jb51.rar 2)将jar包导入Kettle的lib目录下 3)重启Kettle Spoon.bat,使得kettle加载到新加入的jar包,下

  • Java如何实现密码加密

    在查询时,我们如果要对用户的登录信息进行加密,通常会将其密码进行加密. 1) 可以借助spring框架工具类DigestUtils 2) 也可以使用shiro框架来实现 //保存用户自身信息 //1构建一个盐值对象 String salt=UUID.randomUUID().toString();//随机字符串 //2对密码进行盐值加密(加密算法MD5-特点:不可逆,相同内容加密结果也相同) //2.1加密方式1(借助spring框架工具类DigestUtils) //String newPas

  • java RSAUtils 加密工具类操作

    1.RSA加密算法是一种非对称加密算法.在公开密钥加密和电子商业中RSA被广泛使用.RSA公开密钥密码体制.所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种"由已知加密密钥推导出解密密钥在计算上是不可行的"密码体制.在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的.加密算法E和解密算法D也都是公开的.虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK. 2.本工具类涉及到BASE64编码,所以先展示出BA

  • Java使用Cipher类实现加密的过程详解

    一.先看一个简单加密,解密实现 1.1 加密 /** * content: 加密内容 * slatKey: 加密的盐,16位字符串 * vectorKey: 加密的向量,16位字符串 */ public String encrypt(String content, String slatKey, String vectorKey) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

  • Java实现RSA加密工具类

    公钥加密算法,也就是 非对称加密算法,这种算法加密和解密的密码不一样,一个是公钥,另一个是私钥: 公钥和私钥成对出现 公开的密钥叫公钥,只有自己知道的叫私钥 用公钥加密的数据只有对应的私钥可以解密 用私钥加密的数据只有对应的公钥可以解密 如果可以用公钥解密,则必然是对应的私钥加的密 如果可以用私钥解密,则必然是对应的公钥加的密 公钥和私钥是相对的,两者本身并没有规定哪一个必须是公钥或私钥. 代码如下 package com.cxy.template.controller.keyTools; im

  • 解决对接JAVA SM2加密遇到的坑

    遇到有接口需要使用国密的SM2算法,对方使用的是JAVA,我们使用的是go,原以为都是标准算法不会有什么大问题,结果巨坑无法.. 对方使用的加密模块,SM2.java和SM2KeyPairs.java,不知道最初是谁开发的,网上貌似很多都是这个版本的实现,但是和go的交互总是有问题,用这个java模块加密的,go里面怎么也无法正确解密.仔细核对之后发现,这个java模块有几个地方并不符合GB/T32891的标准. SM2加密的流程 SM2使用的椭圆曲线基点记为G,私钥为整数d, 公钥为P = d

  • 解决JAVA非对称加密不同系统加密结果不一致的问题

    最近在做一个项目,需要用到非对称加密,但是出现一个很诡异的情况,本地开发环境是Windows环境,测试环境是Linux环境,出现一个问题, 那就是本地环境与开发环境同一个私钥字符串加密加密同一个信息,得到的加密结果不一样. 经过查询网络得知,这是由于填充的规则不同导致. 原来的加密的部分代码 byte[] keyBytes = Base64.decodeBase64(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedK

  • Java字符串split方法的坑及解决

    目录 Java字符串split方法的坑 Java字符串split方法的探究 总结 Java字符串split方法的坑 先来看几行简单的Java代码,如下: System.out.println("1,2".split(",").length); System.out.println("1,2,".split(",").length); System.out.println("".split(",&q

  • 详解Java 集合类 List 的那些坑

    现在的一些高级编程语言都会提供各种开箱即用的数据结构的实现,像 Java 编程语言的集合框架中就提供了各种实现,集合类包含 Map 和 Collection 两个大类,其中 Collection 下面的 List 列表是我们经常使用的集合类之一,很多的业务代码都离不开它,今天就来看看 List 列表的一些坑. 第一个坑:Arrays.asList 方法返回的 List 不支持增加.删除操作 例如我们执行以下代码: List<String> strings = Arrays.asList(&qu

  • Java中Objects.equals踩坑记录

    目录 前言 1. 案发现场 2. 判断相等的方法 2.1 使用==号 2.2 使用equals方法 3. 空指针异常 4. Objects.equals的作用 5. Objects.equals的坑 总结 前言 最近review别人代码的时候,发现有个同事,在某个业务场景下,使用Objects.equals方法判断两个值相等时,返回了跟预期不一致的结果,引起了我的兴趣. 原本以为判断结果会返回true的,但实际上返回了false. 记得很早之前,我使用Objects.equals方法也踩过类似的

  • SpringBoot 集成 Jasypt 对数据库加密以及踩坑的记录分享

    前言 密码安全是非常重要的,因此我们在代码中往往需要对密码进行加密,以此保证密码的安全 加依赖 <!-- jasypt --> <dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.3</version> </depe

  • 详解如何在Java中加密和解密zip文件

    目录 依赖 压缩一个文件 压缩多个文件 压缩一个目录 创建一个分割的压缩文件 提取所有文件 提取单个文件 总结 依赖 让我们先把 zip4j 依赖关系添加到我们的 pom.xml 文件中. <dependency>     <groupId>net.lingala.zip4j</groupId>     <artifactId>zip4j</artifactId>     <version>2.9.0</version>

  • Java RSA加密解密实现方法分析【附BASE64 jar包下载】

    本文实例讲述了Java RSA加密解密实现方法.分享给大家供大家参考,具体如下: 该工具类中用到了BASE64,需要借助第三方类库:javabase64-1.3.1.jar javabase64-1.3.1.jar 本站下载地址. 注意: RSA加密明文最大长度117字节,解密要求密文最大长度为128字节,所以在加密和解密的过程中需要分块进行. RSA加密对明文的长度是有限制的,如果加密数据过大会抛出如下异常: Exception in thread "main" javax.cryp

  • Java SHA-256加密的两种实现方法详解

    本文实例讲述了Java SHA-256加密的两种实现方法.分享给大家供大家参考,具体如下: 最近在做注册的一个功能,密码要进行加密,一开始想用MD5加密,但是听说被破解了已经,于是想玩玩SHA-256加密.学习了下,总结两种方法供后面参考: 1.利用Apache的工具类实现加密: maven: <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifac

  • 解决出现 java.lang.ExceptionInInitializerError错误问题

    解决出现 java.lang.ExceptionInInitializerError错误问题 今天启动一个项目... 在启动的时候报错... 查了半天错误信息 一直是说hibernate缓存管理出错.. 最后查看启动时候的log 发现在程序中报Java.lang.ExceptionInInitializerError 查看原因 最后是因为自己修改了静态常量是系统启动的时候自动获取properties值 结果获取错误 导致其在代码编译的时候造成出错 错误代码: public static fina

随机推荐