代码中实现了电码本ECB模式和密文分组连接CBC模式,SM3.java和SM4.java为算法实现类,utils的都是根据实现类写的工具,可以根据需要调用杂凑算法SM3的杂凑功能获得杂凑值。
SM4.java中
sm4_crypt_ecb(SM4_Context ctx, byte[] input) ECB模式加解密方法,根据密钥判断加解密功能
sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) CBC模式加解密方法,根据密钥判断加解密功能
加密解密通过如下方法:
sm4_setkey_enc(SM4_Context ctx, byte[] key) 设置加密密钥调用上述方法,实现加密
sm4_setkey_dec(SM4_Context ctx, byte[] key) 设置解密密钥调用上述方法,实现解密
需要导入的包为bcprov-jdk16 我用的版本是bcprov-jdk16-1.46
maven中配置依赖:
-
<dependency>
-
<groupId>org.bouncycastle</groupId>
-
<artifactId></artifactId>
-
<version>1.46</version>
-
</dependency>
package中class目录如下:
chiper.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;
-
public class Cipher {
-
private int ct;
-
private ECPoint p2;
-
private SM3Digest sm3keybase;
-
private SM3Digest sm3c3;
-
private byte key[];
-
private byte keyOff;
-
public Cipher()
-
{
-
this.ct = 1;
-
this.key = new byte[32];
-
this.keyOff = 0;
-
}
-
private void Reset()
-
{
-
this.sm3keybase = new SM3Digest();
-
this.sm3c3 = new SM3Digest();
-
byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());
-
this.sm3keybase.update(p, 0, p.length);
-
this.sm3c3.update(p, 0, p.length);
-
p = Util.byteConvert32Bytes(p2.getY().toBigInteger());
-
this.sm3keybase.update(p, 0, p.length);
-
this.ct = 1;
-
NextKey();
-
}
-
private void NextKey()
-
{
-
SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
-
sm3keycur.update((byte) (ct >> 24 & 0xff));
-
sm3keycur.update((byte) (ct >> 16 & 0xff));
-
sm3keycur.update((byte) (ct >> 8 & 0xff));
-
sm3keycur.update((byte) (ct & 0xff));
-
sm3keycur.doFinal(key, 0);
-
this.keyOff = 0;
-
this.ct++;
-
}
-
public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
-
{
-
AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
-
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
-
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
-
BigInteger k = ecpriv.getD();
-
ECPoint c1 = ecpub.getQ();
-
this.p2 = userKey.multiply(k);
-
Reset();
-
return c1;
-
}
-
public void Encrypt(byte data[])
-
{
-
this.sm3c3.update(data, 0, data.length);
-
for (int i = 0; i < data.length; i++)
-
{
-
if (keyOff == key.length)
-
{
-
NextKey();
-
}
-
data[i] ^= key[keyOff++];
-
}
-
}
-
public void Init_dec(BigInteger userD, ECPoint c1)
-
{
-
this.p2 = c1.multiply(userD);
-
Reset();
-
}
-
public void Decrypt(byte data[])
-
{
-
for (int i = 0; i < data.length; i++)
-
{
-
if (keyOff == key.length)
-
{
-
NextKey();
-
}
-
data[i] ^= key[keyOff++];
-
}
-
this.sm3c3.update(data, 0, data.length);
-
}
-
public void Dofinal(byte c3[])
-
{
-
byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());
-
this.sm3c3.update(p, 0, p.length);
-
this.sm3c3.doFinal(c3, 0);
-
Reset();
-
}
-
}
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;
-
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);
-
}
-
}
SM2Utils.java
-
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);
-
}
-
}
SM3.java
-
public class SM3 {
-
public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
-
0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,
-
(byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,
-
(byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,
-
(byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,
-
0x4e };
-
public static int[] Tj = new int[64];
-
static
-
{
-
for (int i = 0; i < 16; i++)
-
{
-
Tj[i] = 0x79cc4519;
-
}
-
for (int i = 16; i < 64; i++)
-
{
-
Tj[i] = 0x7a879d8a;
-
}
-
}
-
public static byte[] CF(byte[] V, byte[] B)
-
{
-
int[] v, b;
-
v = convert(V);
-
b = convert(B);
-
return convert(CF(v, b));
-
}
-
private static int[] convert(byte[] arr)
-
{
-
int[] out = new int[arr.length / 4];
-
byte[] tmp = new byte[4];
-
for (int i = 0; i < arr.length; i += 4)
-
{
-
System.arraycopy(arr, i, tmp, 0, 4);
-
out[i / 4] = bigEndianByteToInt(tmp);
-
}
-
return out;
-
}
-
private static byte[] convert(int[] arr)
-
{
-
byte[] out = new byte[arr.length * 4];
-
byte[] tmp = null;
-
for (int i = 0; i < arr.length; i++)
-
{
-
tmp = bigEndianIntToByte(arr[i]);
-
System.arraycopy