代码中实现了电码本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;

这篇博客详细介绍了如何在Java中实现国密算法,包括SM2、SM3和SM4。提供了ECB(电码本)和CBC(密文分组连接)两种加密模式的具体方法,如SM4_crypt_ecb和SM4_crypt_cbc。加密解密功能通过设置加密密钥sm4_setkey_enc和解密密钥sm4_setkey_dec来实现。文章还提及依赖于bcprov-jdk16-1.46库,并给出了Maven的配置依赖以及相关类的目录结构。
5512

被折叠的 条评论
为什么被折叠?



