使用SM2算法进行密钥交换的代码(BC包装)

3 篇文章 0 订阅
1 篇文章 0 订阅

使用SM2算法进行密钥交换的代码(BC包装)

SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。

SM2密钥交换的优点

  1. 密钥更短
  2. 速度更快
  3. 更加安全

说明如下
BouncyCastleProvider bcp = new BouncyCastleProvider();
Security.addProvider(bcp);
需要在工程里面引用BC库。到http://www.bouncycastle.org/ 下载bcprov-ext-jdk15on-165.jar
在eclipse亲测可用。
把下面的两个文件完全复制下来,文件名已经包含在文件头。
存成两个java文件。
直接就可以执行了。
用SM2 做密钥交换虽然可以,但经过这个测试后,本人感觉SM2密钥交换比DH麻烦太多了!商用环境还是需要提高便利性,让大多数程序员去了解算法的椭圆曲线细节不太现实。
如果有致力于商密算法研究,特别是BC优化方面的人, 建议对此进行优化,把算法的细节尽量全部包装在库中。

代码如下:

/***
 * xuyanbai  2020.6.6 文件名 SM2Coder_Ag.java
 */
package xu.edu.testSM2_Agree;
import java.math.BigInteger;

import java.security.SecureRandom;

import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.agreement.SM2KeyExchange;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithID;
import org.bouncycastle.crypto.params.SM2KeyExchangePrivateParameters;
import org.bouncycastle.crypto.params.SM2KeyExchangePublicParameters;

import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;

import org.bouncycastle.util.Strings;

import org.bouncycastle.util.test.TestRandomBigInteger;


public class SM2Coder_Ag {
    //xuyanbai add it for curve use
	//come from GB T 32918.3-2016 and BC 
    static BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); //素数域
    static BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); //曲线系数a
    static BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); //曲线系数b
    static BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); //生成元G的阶数
    static BigInteger SM2_ECC_H = ECConstants.ONE;                                  //余因子为1
    static BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); //生成元x坐标
    static BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); 生成元x坐标


		//获取椭圆曲线
	private static ECDomainParameters domainParams=null;
    private static void getcurve()
    {
    	if(domainParams !=null)return;
    	 ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H);

         ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY);
         domainParams = new ECDomainParameters(curve, g, SM2_ECC_N);
         return ;
    }
	/**
	 * 初始化甲方密钥
	 * 
	 * @return Map 甲方密钥Map
	 * @throws Exception
	 */
	public static Map<String, Object> initKeyA() throws Exception {

		// 构造曲线
		getcurve();
		// 实例化密钥对生成器
		ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
		
        //A用户私钥6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE
		ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE", 16));
		// 初始化密钥对生成器
		keyPairGenerator.init(aKeyGenParams);
		// 生成密钥对
//		KeyPair keyPair = keyPairGenerator.generateKeyPair();
		AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair();
		// 甲方公钥
		//PublicKey publicKey = (PublicKey) keyPair.getPublic();
		ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic();
		// 甲方私钥
		//PrivateKey privateKey = (PrivateKey) keyPair.getPrivate();
		ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate();
		
		//ra随机数
        //ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563", 16));
		SecureRandom random= new SecureRandom();
		ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, random);
        keyPairGenerator.init(aeKeyGenParams);
      
        AsymmetricCipherKeyPair aeKp = keyPairGenerator.generateKeyPair();

        ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.getPublic();
        ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.getPrivate();
		// 将密钥对存储在Map中
		Map<String, Object> keyMap = new HashMap<String, Object>(4);

		//keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put("aPub", aPub);
		//keyMap.put(PRIVATE_KEY, privateKey);
		keyMap.put("aPriv", aPriv);
		keyMap.put("aePub",aePub);
		keyMap.put("aePriv",aePriv);
		
		return keyMap;
	}

	/**
	 * 初始化乙方密钥
	 * 
	 * @param key
	 *            甲方公钥
	 * @return Map 乙方密钥Map
	 * @throws Exception
	 */
	public static Map<String, Object> initKeyB() throws Exception {

		 //rb ,乙方
		ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53", 16));
		// 初始化算法参数生成器

		// 实例化密钥对儿生成器
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
		// 初始化密钥对儿生成器
		 keyPairGenerator.init(bKeyGenParams);
		// 生成密钥对儿
		 AsymmetricCipherKeyPair bKp = keyPairGenerator.generateKeyPair();
		 //获取B用户的公私钥
	    ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.getPublic();
	    ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.getPrivate();
	    //获取be的参数,rb随机
	    SecureRandom random= new SecureRandom();
	    //ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80", 16));
	    ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, random);	
        keyPairGenerator.init(beKeyGenParams);

        AsymmetricCipherKeyPair beKp = keyPairGenerator.generateKeyPair();

        ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.getPublic();
        ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.getPrivate();

		// 封装密钥
		Map<String, Object> map = new HashMap<String, Object>(4);

		//map.put(PUBLIC_KEY, publicKey);
		map.put("bPub", bPub);
		//map.put(PRIVATE_KEY, privateKey);
		map.put("bPriv", bPriv);
		map.put("bePub", bePub);
		map.put("bePriv", bePriv);
		return map;

	}
/***
 * 
 * @param aPriv
 * @param aePriv
 * @param bPub
 * @param bePub
 * @return 协商后的密钥
 * @throws Exception
 */
	public static byte[] KeyExchangeA(ECPrivateKeyParameters aPriv,ECPrivateKeyParameters aePriv,ECPublicKeyParameters bPub,ECPublicKeyParameters bePub) throws Exception {
		
		SM2KeyExchange exch = new SM2KeyExchange();
		
        exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.toByteArray("ALICE123@YAHOO.COM")));

        byte[] k1 = exch.calculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.toByteArray("BILL456@YAHOO.COM")));
		//共享密钥是55b0ac62a6b927ba23703832c853ded4
       // isTrue("key 1 wrong", Arrays.areEqual(Hex.decode("55b0ac62a6b927ba23703832c853ded4"), k1));

		return k1;
	}

	/****
	 * 
	 * @param bPriv
	 * @param bePriv
	 * @param aPub
	 * @param aePub
	 * @return 返回协商后的密钥
	 * @throws Exception
	 */
	public static byte[] KeyExchangeB(ECPrivateKeyParameters bPriv,ECPrivateKeyParameters bePriv,ECPublicKeyParameters aPub,ECPublicKeyParameters aePub) throws Exception {

		SM2KeyExchange exch = new SM2KeyExchange();

	        exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.toByteArray("BILL456@YAHOO.COM")));

	        byte[] k2 = exch.calculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.toByteArray("ALICE123@YAHOO.COM")));

	  //      isTrue("key 2 wrong", Arrays.areEqual(Hex.decode("55b0ac62a6b927ba23703832c853ded4"), k2));
		return k2;
	}

	
	/**
	 * 取得私钥
	 * 
	 * @param keyMap
	 *            密钥Map
	 * @return byte[] 私钥
	 * @throws Exception
	 */
	public static ECPrivateKeyParameters getPrivateKey(String str,Map<String, Object> keyMap )
			throws Exception {

		ECPrivateKeyParameters key = (ECPrivateKeyParameters) keyMap.get(str);
		return key;
	}

	/**
	 * 取得公钥
	 * 
	 * @param keyMap
	 *            密钥Map
	 * @return byte[] 公钥
	 * @throws Exception
	 */
	public static ECPublicKeyParameters getPublicKey(String str,Map<String, Object> keyMap )
			throws Exception {

		ECPublicKeyParameters key = (ECPublicKeyParameters) keyMap.get(str);

		return key;
	}
}

   下面的文件是用前面的包装类进行测试 的文件:
/***
 * xuyanbai  2020.6.6 文件名:SM2Coder_AgTest.java
 */
package xu.edu.testSM2_Agree;

import java.security.Security;
import java.util.Map;

import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class SM2Coder_AgTest {


	public final void test() throws Exception {

		// 生成甲方密钥对儿
		Map<String, Object> keyMap1 = SM2Coder_Ag.initKeyA();
	 // 生成乙方密钥对儿
		Map<String, Object> keyMap2 = SM2Coder_Ag.initKeyB();
		//甲方生成的密钥
		ECPrivateKeyParameters aPriv = SM2Coder_Ag.getPrivateKey("aPriv", keyMap1);
		ECPrivateKeyParameters aePriv = SM2Coder_Ag.getPrivateKey("aePriv", keyMap1);
		
		ECPublicKeyParameters aPub = SM2Coder_Ag.getPublicKey("aPub", keyMap1);
		ECPublicKeyParameters aePub = SM2Coder_Ag.getPublicKey("aePub", keyMap1);
		
	
		//乙方生成的密钥
		ECPrivateKeyParameters bPriv = SM2Coder_Ag.getPrivateKey("bPriv", keyMap2);
		ECPrivateKeyParameters bePriv = SM2Coder_Ag.getPrivateKey("bePriv", keyMap2);
	
		ECPublicKeyParameters bPub = SM2Coder_Ag.getPublicKey("bPub", keyMap2);
		ECPublicKeyParameters bePub = SM2Coder_Ag.getPublicKey("bePub", keyMap2);
		//开始协商		
		byte[] mykeyA = SM2Coder_Ag.KeyExchangeA(aPriv, aePriv, bPub, bePub);
		byte[] mykeyB = SM2Coder_Ag.KeyExchangeB(bPriv, bePriv, aPub, aePub);
		
		//输出结果
		System.out.println("甲方协商结果:\n" + Base64.toBase64String(mykeyA));
		System.out.println("乙方协商结果:\n" + Base64.toBase64String(mykeyB));

	
	}


	public static void main(String[] args) throws Exception {
		//初始化BC库
		 BouncyCastleProvider bcp = new BouncyCastleProvider();
		 Security.addProvider(bcp);

		 SM2Coder_AgTest a =new SM2Coder_AgTest();
   		a.test();
	}
}

执行结果类似如下:(每次协商均为不同的密钥值)
甲方协商结果:
ywR8rVvf8dqKt/B2ovPlXw==
乙方协商结果:
ywR8rVvf8dqKt/B2ovPlXw==

SM2是中国的国密算法,全称为“安全多方信息基础”(Secure Multi-party Information Base)算法之一,主要用于数字签名和密钥交换Java中实现SM2加密算法需要使用专门的库,如BCryptor或中国国密算法Java实现。 以下是一个简化的Java代码示例,展示了SM2的基本用法,包括密钥生成、签名和验证,但请注意实际使用时你需要导入相应的库: ```java import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; public class SM2Example { static { Security.addProvider(new BouncyCastleProvider()); } // 导入SM2相关的密钥对 private static KeyPairGenerator keyGen = KeyPairGenerator.getInstance("SM2", "BC"); private static KeyPair keyPair; public static void main(String[] args) { try { // 生成密钥对 keyGen.initialize(2048); // 随机数长度,可以根据需要调整 keyPair = keyGen.generateKeyPair(); // 使用公钥进行签名 SecureRandom random = new SecureRandom(); byte[] message = "Hello, SM2!".getBytes(); Signature signature = Signature.getInstance("SM2withRSA", "BC"); signature.initSign(keyPair.getPrivate(), random); signature.update(message); byte[] signatureBytes = signature.sign(); // 使用公钥验证签名 signature.initVerify(keyPair.getPublic()); signature.update(message); boolean isVerified = signature.verify(signatureBytes); System.out.println("Signature verified: " + isVerified); // 也可以将密钥和签名转换为十六进制字符串展示 String privateKeyHex = Hex.toHexString(keyPair.getPrivate().getEncoded()); String publicKeyHex = Hex.toHexString(keyPair.getPublic().getEncoded()); String signatureHex = Hex.toHexString(signatureBytes); System.out.println("Private Key (hex): " + privateKeyHex); System.out.println("Public Key (hex): " + publicKeyHex); System.out.println("Signature (hex): " + signatureHex); } catch (Exception e) { e.printStackTrace(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值