使用SM2算法进行密钥交换的代码(BC包装)
使用SM2算法进行密钥交换的代码(BC包装)
SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。
SM2密钥交换的优点
- 密钥更短 ;
- 速度更快 ;
- 更加安全;
说明如下
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); //曲线系数astatic BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); //曲线系数bstatic BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); //生成元G的阶数static BigInteger SM2_ECC_H = ECConstants.ONE; //余因子为1static 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用户私钥6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEEECKeyGenerationParameters 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==
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
