推荐一个大神的人工智能教程!http://blog.csdn.net/jiangjunshow
【摘要】
本文主要讲解“国密加密算法”SM系列的Java实现方法,不涉及具体的算法剖析,在网络上找到的java实现方法比较少,切在跨语言加密解密上会存在一些问题,所以整理此文志之。
源码下载地址http://download.csdn.net/detail/ererfei/9474502 需要C#实现SM系列算法源码的可以评论留邮箱地址,看到后发送
1.SM2 & SM3
由于SM2算法中需要使用SM3摘要算法,所以把他们放在一起
项目目录结构如下:
首先要下载一个jar包——bcprov-jdk.jar,可以到maven库中下载最新版http://central.maven.org/maven2/org/bouncycastle/并将该jar包引入项目的classpath。实现代码如下(每个工具类都有Main可以运行测试):
a. SM2主类
【SM2.java】
-
package com.mlq.sm;
-
-
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;
-
public
final BigInteger ecc_a;
-
public
final BigInteger ecc_b;
-
public
final BigInteger ecc_n;
-
public
final BigInteger ecc_gx;
-
public
final BigInteger ecc_gy;
-
public
final ECCurve ecc_curve;
-
public
final ECPoint ecc_point_g;
-
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_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);
-
}
-
}
b. SM2工具类
【SM2Utils.java】
-
package com.mlq.sm;
-
-
import java.io.IOException;
-
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;
-
-
public
class SM2Utils
-
{
-
//生成随机秘钥对
-
public static void generateKeyPair(){
-
SM2 sm2 = SM2.Instance();
-
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();
-
-
System.out.println(
"公钥: " + Util.byteToHex(publicKey.getEncoded()));
-
System.out.println(
"私钥: " + Util.byteToHex(privateKey.toByteArray()));
-
}
-
-
//数据加密
-
public static String encrypt(byte[] publicKey, byte[] data) throws IOException
-
{
-
if (publicKey ==
null || publicKey.length ==
0)
-
{
-
return
null;
-
}
-
-
if (data ==
null || data.length ==
0)
-
{
-
return
null;
-
}
-
-
byte[] source =
new
byte[data.length];
-
System.arraycopy(data,
0, source,
0, data.length);
-
-
Cipher cipher =
new Cipher();
-
SM2 sm2 = SM2.Instance();
-
ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
-
-
ECPoint c1 = cipher.Init_enc(sm2, userKey);
-
cipher.Encrypt(source);
-
byte[] c3 =
new
byte[
32];
-
cipher.Dofinal(c3);
-
-
// System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
-
// System.out.println("C2 " + Util.byteToHex(source));
-
// System.out.println("C3 " + Util.byteToHex(c3));
-
//C1 C2 C3拼装成加密字串
-
return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);
-
-
}
-
-
//数据解密
-
public
static
byte[] decrypt(
byte[] privateKey,
byte[] encryptedData)
throws IOException
-
{
-
if (privateKey ==
null || privateKey.length ==
0)
-
{
-
return
null;
-
}
-
-
if (encryptedData ==
null || encryptedData.length ==
0)
-
{
-
return
null;
-
}
-
//加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
-
String data = Util.byteToHex(encryptedData);
-
/***分解加密字串
-
* (C1 = C1标志位2位 + C1实体部分128位 = 130)
-
* (C3 = C3实体部分64位 = 64)
-
* (C2 = encryptedData.length * 2 - C1长度 - C2长度)
-
*/
-
byte[] c1Bytes = Util.hexToByte(data.substring(
0,
130));
-
int c2Len = encryptedData.length -
97;
-
byte[] c2 = Util.hexToByte(data.substring(
130,
130 +
2 * c2Len));
-
byte[] c3 = Util.hexToByte(data.substring(
130 +
2 * c2Len,
194 +
2 * c2Len));
-
-
SM2 sm2 = SM2.Instance();
-
BigInteger userD =
new BigInteger(
1, privateKey);
-
-
//通过C1实体字节来生成ECPoint
-
ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
-
Cipher cipher =
new Cipher();
-
cipher.Init_dec(userD, c1);
-
cipher.Decrypt(c2);
-
cipher.Dofinal(c3);
-
-
//返回解密结果
-
return c2;
-
}
-
-
public static void main(String[] args) throws Exception
-
{
-
//生成密钥对
-
generateKeyPair();
-
-
String plainText =
"ererfeiisgod";
-
byte[] sourceData = plainText.getBytes();
-
-
//下面的秘钥可以使用generateKeyPair()生成的秘钥内容
-
// 国密规范正式私钥
-
String prik =
"3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94";
-
// 国密规范正式公钥
-
String pubk =
"04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A";
-
-
System.out.println(
"加密: ");
-
String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);
-
System.out.println(cipherText);
-
System.out.println(
"解密: ");
-
plainText =
new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText)));
-
System.out.println(plainText);
-
-
}
-
}
c. SM3主类
【SM3.java】
-
package com.mlq.sm;
-
-
public
class SM3
-
{
-