forked from rongchao/epmet-cloud-rizhao
5 changed files with 294 additions and 23 deletions
@ -0,0 +1,184 @@ |
|||||
|
package com.epmet.commons.tools.utils.api.yt; |
||||
|
|
||||
|
|
||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
||||
|
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; |
||||
|
|
||||
|
import javax.crypto.Cipher; |
||||
|
import javax.crypto.KeyGenerator; |
||||
|
import javax.crypto.spec.SecretKeySpec; |
||||
|
import java.security.*; |
||||
|
import java.util.Arrays; |
||||
|
|
||||
|
/** |
||||
|
* sm4加密算法工具类 |
||||
|
* |
||||
|
* @explain sm4加密、解密与加密结果验证 可逆算法 |
||||
|
* @Autor:jingyao |
||||
|
*/ |
||||
|
public class TestMs4 { |
||||
|
static { |
||||
|
Security.addProvider(new BouncyCastleProvider()); |
||||
|
} |
||||
|
|
||||
|
private static final String ENCODING = "UTF-8"; |
||||
|
public static final String ALGORITHM_NAME = "SM4"; |
||||
|
// 加密算法/分组加密模式/分组填充方式
|
||||
|
// PKCS5Padding-以8个字节为一组进行分组加密
|
||||
|
// 定义分组加密模式使用:PKCS5Padding
|
||||
|
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding"; |
||||
|
// 128-32位16进制;256-64位16进制
|
||||
|
public static final int DEFAULT_KEY_SIZE = 128; |
||||
|
|
||||
|
/** |
||||
|
* 生成ECB暗号 |
||||
|
* |
||||
|
* @param algorithmName 算法名称 |
||||
|
* @param mode 模式 |
||||
|
* @param key |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
* @explain ECB模式(电子密码本模式:Electronic codebook) |
||||
|
*/ |
||||
|
private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception { |
||||
|
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); |
||||
|
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); |
||||
|
cipher.init(mode, sm4Key); |
||||
|
return cipher; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 自动生成密钥 |
||||
|
* |
||||
|
* @return |
||||
|
* @throws NoSuchAlgorithmException |
||||
|
* @throws NoSuchProviderException |
||||
|
* @explain |
||||
|
*/ |
||||
|
public static byte[] generateKey() throws Exception { |
||||
|
return generateKey(DEFAULT_KEY_SIZE); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
//加密******************************************
|
||||
|
|
||||
|
/** |
||||
|
* @param keySize |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
* @explain 系统产生秘钥 |
||||
|
*/ |
||||
|
public static byte[] generateKey(int keySize) throws Exception { |
||||
|
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); |
||||
|
kg.init(keySize, new SecureRandom()); |
||||
|
return kg.generateKey().getEncoded(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* sm4加密 |
||||
|
* |
||||
|
* @param hexKey 16进制密钥(忽略大小写) |
||||
|
* @param paramStr 待加密字符串 |
||||
|
* @return 返回16进制的加密字符串 |
||||
|
* @throws Exception |
||||
|
* @explain 加密模式:ECB 密文长度不固定,会随着被加密字符串长度的变化而变化 |
||||
|
*/ |
||||
|
public static String encryptEcb(String hexKey, String paramStr) throws Exception { |
||||
|
String cipherText = ""; |
||||
|
// 16进制字符串-->byte[]
|
||||
|
byte[] keyData = ByteUtils.fromHexString(hexKey); |
||||
|
// String-->byte[]
|
||||
|
byte[] srcData = paramStr.getBytes(ENCODING); |
||||
|
// 加密后的数组
|
||||
|
byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); |
||||
|
// byte[]-->hexString
|
||||
|
cipherText = ByteUtils.toHexString(cipherArray); |
||||
|
return cipherText; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 加密模式之Ecb |
||||
|
* |
||||
|
* @param key |
||||
|
* @param data |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
*/ |
||||
|
public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception { |
||||
|
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);//声称Ecb暗号,通过第二个参数判断加密还是解密
|
||||
|
return cipher.doFinal(data); |
||||
|
} |
||||
|
|
||||
|
//解密****************************************
|
||||
|
|
||||
|
/** |
||||
|
* sm4解密 |
||||
|
* |
||||
|
* @param hexKey 16进制密钥 |
||||
|
* @param cipherText 16进制的加密字符串(忽略大小写) |
||||
|
* @return 解密后的字符串 |
||||
|
* @throws Exception |
||||
|
* @explain 解密模式:采用ECB |
||||
|
*/ |
||||
|
public static String decryptEcb(String hexKey, String cipherText) throws Exception { |
||||
|
// 用于接收解密后的字符串
|
||||
|
String decryptStr = ""; |
||||
|
// hexString-->byte[]
|
||||
|
byte[] keyData = ByteUtils.fromHexString(hexKey); |
||||
|
// hexString-->byte[]
|
||||
|
byte[] cipherData = ByteUtils.fromHexString(cipherText); |
||||
|
// 解密
|
||||
|
byte[] srcData = decrypt_Ecb_Padding(keyData, cipherData); |
||||
|
// byte[]-->String
|
||||
|
decryptStr = new String(srcData, ENCODING); |
||||
|
return decryptStr; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 解密 |
||||
|
* |
||||
|
* @param key |
||||
|
* @param cipherText |
||||
|
* @return |
||||
|
* @throws Exception |
||||
|
* @explain |
||||
|
*/ |
||||
|
public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { |
||||
|
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);//生成Ecb暗号,通过第二个参数判断加密还是解密
|
||||
|
return cipher.doFinal(cipherText); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 校验加密前后的字符串是否为同一数据 |
||||
|
* |
||||
|
* @param hexKey 16进制密钥(忽略大小写) |
||||
|
* @param cipherText 16进制加密后的字符串 |
||||
|
* @param paramStr 加密前的字符串 |
||||
|
* @return 是否为同一数据 |
||||
|
* @throws Exception |
||||
|
* @explain |
||||
|
*/ |
||||
|
public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception { |
||||
|
// 用于接收校验结果
|
||||
|
boolean flag = false; |
||||
|
// hexString-->byte[]
|
||||
|
byte[] keyData = ByteUtils.fromHexString(hexKey); |
||||
|
// 将16进制字符串转换成数组
|
||||
|
byte[] cipherData = ByteUtils.fromHexString(cipherText); |
||||
|
// 解密
|
||||
|
byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData); |
||||
|
// 将原字符串转换成byte[]
|
||||
|
byte[] srcData = paramStr.getBytes(ENCODING); |
||||
|
// 判断2个数组是否一致
|
||||
|
flag = Arrays.equals(decryptData, srcData); |
||||
|
return flag; |
||||
|
} |
||||
|
|
||||
|
public static void main(String[] args) throws Exception { |
||||
|
String text = "5d22ea44c7599a48f0d4446b1b7fbb4bb8353922df437d39c3a38549c0f2549cbd021ada00a8be83027ae06203c3daea2eedc5bd0875c7e509c7049045c5349577f2c21bcec328a5ea0bf341191e5bdba978566dddd16f1cf1928ff5cbd826dd33289fb45a8a04585f1f24ab04f59426371a5a0a0f2ee3e7b00d2bdfba7810524ce4c33130eda077546fa4c4191d0117f7a44e1cadac6c69a7d437653be1f958a459e0f025d471e09ab4636c38013032948ffb0827040ed6f3436be090f545186928a7b0b2bfc65782452606607ce8555ba130caacad73998da704428a07276a2699889c9872eebba5de8b72cdbe88705483293b00ab3ecb3aa57d283a4ecab40b71bc0a10e9ec626f07b2293255349fb2270d37e81c5c3d0de0b0f0706ed1872f60f039ce2e51effc39aef9747d67457e072cf3170a9c19589c1bab1a7d9d80"; |
||||
|
String s = TestMs4.decryptEcb("dbcff4c9f4774e6cb56080f279149d59", text); |
||||
|
System.out.println(s); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
Loading…
Reference in new issue