SM2密钥交换算法的java语言实现

考虑到网上大多数SM2密钥交换协议均是C语言实现,没有找到java实现的版本,所以参考了网上SM2加密算法实现的代码,自行写出了Java版本的密钥交换算法。
本文中的SM2.java SM3.java SM3Digest.java Util.java来源于CSDN博客:https://blog.csdn.net/ErErFei/article/details/50998162
本文程序均在命令行窗口运行通过。由于密钥对不断随机产生,所以运行结果和本文是不相同的。
SM2.java文件

import java.math.BigInteger;
import java.security.SecureRandom;

import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.ECFieldElement.Fp;

public class SM2 {
//测试参数
// public static final String[] ecc_param = {
// "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
// "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
// "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
// "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
// "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
// "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
// };

//正式参数  
public static String[] ecc_param = {   
    "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",  
    "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",  
    "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",  
    "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",  
    "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",  
    "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"  
};  

public static SM2 Instance()   
{  
    return new SM2();  
}  

public final BigInteger ecc_p;//素数p  
public final BigInteger ecc_a;//系数a  
public final BigInteger ecc_b;//系数b  
public final BigInteger ecc_n;//生成元G的阶n  
public final BigInteger ecc_gx;  //生成元G是椭圆曲线的一个点,该点的横坐标x
public final BigInteger ecc_gy;  //G的纵坐标
public final ECCurve ecc_curve;  //椭圆曲线
public final ECPoint ecc_point_g;  //点G
public final int ecc_w;
public final ECDomainParameters ecc_bc_spec;  
public final ECKeyPairGenerator ecc_key_pair_generator;  
public final ECFieldElement ecc_gx_fieldelement;  
public final ECFieldElement ecc_gy_fieldelement;  

public SM2()   
{  
    this.ecc_p = new BigInteger(ecc_param[0], 16);  
    this.ecc_a = new BigInteger(ecc_param[1], 16);  
    this.ecc_b = new BigInteger(ecc_param[2], 16);  
    this.ecc_n = new BigInteger(ecc_param[3], 16);  
    this.ecc_gx = new BigInteger(ecc_param[4], 16);  
    this.ecc_gy = new BigInteger(ecc_param[5], 16);  
    this.ecc_w = 127;
    this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);  
    this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);  

    this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);  //生成椭圆曲线
    this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);  

    this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);  

    ECKeyGenerationParameters ecc_ecgenparam;  
    ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());  

    this.ecc_key_pair_generator = new ECKeyPairGenerator();  
    this.ecc_key_pair_generator.init(ecc_ecgenparam);  
}  

}

SM2_Exchange.java

import java.math.BigInteger;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import ren_sm3.Util;
import ren_sm3.SM3Digest;
public class SM2_Exchange
{
private byte[] pubKey;
private byte[] priKey;
//生成密钥对
public void generateKeyPair(){
SM2 sm2 = SM2.Instance(); //生成SM2实例
AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair(); //生成公私密钥对
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate(); //从密钥对中提取私钥参数
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic(); //从密钥对中提取公钥参数
BigInteger privateKey = ecpriv.getD(); //私钥是个大整数
ECPoint publicKey = ecpub.getQ(); //公钥是个点

    pubKey = publicKey.getEncoded();  //将椭圆曲线点转化为字节数组
    priKey = privateKey.toByteArray();  //将大整数转化为字节数组
    System.out.println(Util.getHexString(priKey));
}
//获取公钥
public byte[] getPubKey()
{
    return pubKey;
}
//获取私钥
public byte[] getPriKey()
{
    return priKey;
}
/**
* 计算Z值
* @param ID  身份标识
* @param Z   存储32字节杂凑值的字节数组
*/
public void computeZ(String ID,byte[] Z)throws Exception
{
    SM3Digest sm3=new SM3Digest();
    byte[] ENTL = new byte[]{0x00,(byte)0x80};
    byte[] byte_ID = ID.getBytes("US-ASCII");//将字符串以ASCII格式编码为字节数组
    sm3.update(ENTL,0,ENTL.length);
    sm3.update(byte_ID,0,byte_ID.length);
    SM2 sm2 = SM2.Instance();
    byte[] a = Util.hexToByte(sm2.ecc_a.toString(16));//将椭圆曲线的参数a大整数格式转化为字节数组
    byte[] b = Util.hexToByte(sm2.ecc_b.toString(16));//将椭圆曲线的参数b大整数格式转化为字节数组
    sm3.update(a,0,a.length);
    sm3.update(b,0,b.length);
    byte[] gx = Util.hexToByte(sm2.ecc_gx.toString(16));//将椭圆曲线的参数gx大整数格式转化为字节数组
    byte[] gy = Util.hexToByte(sm2.ecc_gy.toString(16));//将椭圆曲线的参数gy大整数格式转化为字节数组
    sm3.update(gx,0,gx.length);
    sm3.update(gy,0,gy.length);
    sm3.update(pubKey,1,pubKey.length-1);//将公钥的横坐标和纵坐标导入缓冲区
    sm3.doFinal(Z,0);
}
public static void main(String[] args)throws Exception
{
    SM2_Exchange A = new SM2_Exchange();
    SM2_Exchange B = new SM2_Exchange();
    A.generateKeyPair();//产生A的公私钥对
    B.generateKeyPair();//产生B的公私钥对
    
    byte[] pubK_A = A.getPubKey();//获取A的公钥
    byte[] pubK_B = B.getPubKey();//获取B的公钥
    byte[] priK_A = A.getPriKey();//获取A的私钥
    byte[] priK_B = B.getPriKey();//获取B的私钥
    
    
    byte[] ZA =new byte[32];
    A.computeZ("288976@qq.com",ZA);//根据输入的标识计算ZA值
    
    byte [] ZB =new byte[32];
    B.computeZ("288975@qq.com",ZB);//根据输入的标识计算ZB值
    
    Exch A_EX = new Exch();
    Exch B_EX = new Exch();
    A_EX.Init(priK_A);//产生rA,RA,x_1,tA
    B_EX.Init(priK_B);//产生rB,RB,x_2,tB
    
    ECPoint R_A = A_EX.R1;//获取A产生的RA
    ECPoint R_B = B_EX.R1;//获取B产生的RB
    
    SM2 sm2 = new SM2();
    ECPoint pubA = sm2.ecc_curve.decodePoint(pubK_A);//将A公钥的字节数组格式转化为椭圆曲线点
    ECPoint pubB = sm2.ecc_curve.decodePoint(pubK_B);//将B公钥的字节数组格式转化为椭圆曲线点

    A_EX.computeKey(pubB,R_B,ZA,ZB);//A计算x_2,UA,KA
    B_EX.computeKey(pubA,R_A,ZA,ZB);//B计算X_1,UB,KB
}

}

Exch.java

import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import java.math.BigInteger;
import ren_sm3.SM3Digest;
import ren_sm3.Util;
import org.bouncycastle.math.ec.ECFieldElement;
import org.bouncycastle.math.ec.ECFieldElement.Fp;
public class Exch
{
private BigInteger t;
public ECPoint R1;
private byte[] ux;//椭圆曲线点U的横坐标
p

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值