加密机网联对账文件解密问题-加密机不支持网联对账大文件SM4解密-使用SM4软加解密方法解密网联对账文件
在处理解密网联的对账文件过程中发现由于我们的加密机中未实现SM4大文件加解密方法,其中最大支持长度为< 4K = 4095 - 16(密钥长度) = 4079。所有对于网联大文件加解密我使用了bc.2.57版本实现了大文件的软加密和解密
- 直接上代码如下:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* SM2加4解密工具类
*/
public class SM4Helper {
/**
* 网联对应的SM4算法
*/
public static final String ALGORITHM_NAME = "SM4/ECB/PKCS5Padding";
/**
* 加密文件缓冲区长度
*/
private static final int ENCRYPT_FILE_BUFF_LENGTH = 512;
/** BC provider */
public static final BouncyCastleProvider BCProvider = new BouncyCastleProvider();
static {
Security.addProvider(BCProvider);
}
/**
* 加密文件 【支持大文件加解密】
*
* @param srcFile 源明文文件
* @param outFile 输出的密文文件
* @param key 密钥
* @throws Exception
*/
public static void encryptFile(String srcFile, String outFile, String key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME, BCProvider);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("ISO8859-1"), ALGORITHM_NAME));
byte[] buffData = new byte[ENCRYPT_FILE_BUFF_LENGTH];
int count = 0;
FileInputStream reader = new FileInputStream(srcFile);
FileOutputStream writer = new FileOutputStream(outFile);
try {
while ((count = reader.read(buffData, 0, buffData.length)) > 0) {
byte[] cipherData;
if (count == ENCRYPT_FILE_BUFF_LENGTH) {
cipherData = cipher.update(buffData); //读取缓冲数据持续计算
} else {
byte[] plainData = new byte[count];
System.arraycopy(buffData, 0, plainData, 0, plainData.length);
cipherData = cipher.doFinal(plainData);
}
writer.write(cipherData, 0, cipherData.length);
writer.flush();
}
}
catch (Exception err) {
throw err;
}
finally{
writer.close();
reader.close();
}
}
/**
* 解密文件 【支持大文件加解密】
*
* @param srcFile 源密文文件
* @param outFile 输出原文文件
* @param key 密钥 长度16个字符
* @return
* @throws Exception
*/
public static void decryptFile(String srcFile, String outFile, String key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME, BCProvider);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("ISO8859-1"), ALGORITHM_NAME));
// 缓存长度
int buffLength = ENCRYPT_FILE_BUFF_LENGTH ;
byte[] buffData = new byte[buffLength];
int count = 0;
FileInputStream reader = new FileInputStream(srcFile);
FileOutputStream writer = new FileOutputStream(outFile);
try {
while ((count = reader.read(buffData, 0, buffData.length)) > 0) {
byte[] plainData;
if (count == buffLength) {
plainData = cipher.update(buffData); //读取缓冲数据持续计算
} else {
byte[] cipherData = new byte[count];
System.arraycopy(buffData, 0, cipherData, 0, cipherData.length);
plainData = cipher.doFinal(cipherData);
}
writer.write(plainData, 0, plainData.length);
writer.flush();
}
}
catch (Exception err) {
throw err;
}
finally{
writer.close();
reader.close();
}
}
}
- 结语
大文件计算的关键点在于解决大文件加载的性能,所以采用读取流的形式加载到缓冲区,
再使用cipher.update(buffData);
//读取缓冲数据持续计算
最后再使用cipher.doFinal(cipherData);
完成计算
面writer.flush();
控制写入文件的频率,可以根据缓冲区大小来设置writer.flush();的调用,可根据自身实际情况来。