|
package cn.edu.nuc.article.util; |
|
|
|
import cn.hutool.core.io.FileUtil; |
|
import cn.hutool.core.io.IoUtil; |
|
import org.bouncycastle.jce.provider.BouncyCastleProvider; |
|
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; |
|
|
|
import javax.crypto.Cipher; |
|
import javax.crypto.CipherInputStream; |
|
import javax.crypto.CipherOutputStream; |
|
import javax.crypto.NoSuchPaddingException; |
|
import javax.crypto.spec.IvParameterSpec; |
|
import javax.crypto.spec.SecretKeySpec; |
|
import java.io.*; |
|
import java.nio.charset.StandardCharsets; |
|
import java.nio.file.Files; |
|
import java.nio.file.Paths; |
|
import java.security.*; |
|
import java.util.Arrays; |
|
import java.util.Random; |
|
|
|
public class SM4Tools { |
|
private static final String name="SM4"; //算法名字 |
|
private static final String transformation="SM4/CBC/PKCS5Padding"; //加密模式以及短快填充方式 |
|
private static final String Default_iv="0123456789abcdef"; //加密使用的初始向量 |
|
|
|
/** |
|
* 加载指定文件,对其进行加密,并将加密结果写入指定输出文件中 |
|
* @param inputFile 要加密的输入文件路径 |
|
* @param outputFile 加密后的输出文件路径 |
|
* @param key 加密所需的密钥 |
|
* @throws Exception 如果文件读取、加密或写入时出现错误,则抛出异常 |
|
*/ |
|
public static void encodeFile(String inputFile, String outputFile, String key) throws Exception { |
|
// 读取输入文件中的所有字节 |
|
byte [] inputBytes = Files.readAllBytes(Paths.get(inputFile)); |
|
// 对输入字节数组进行加密 |
|
byte [] encodeByte = encode(inputBytes, key.getBytes(StandardCharsets.UTF_8)); |
|
// 将加密后的字节数组写入指定输出文件中 |
|
Files.write(Paths.get(outputFile),encodeByte); |
|
System.out.println("File encoded successfully."); |
|
} |
|
/** |
|
* 使用指定的加密算法和密钥对给定的字节数组进行加密 |
|
* @param inputByte 要加密的字节数组 |
|
* @param key 加密所需的密钥 |
|
* @return 加密后的字节数组 |
|
* @throws Exception 如果加密时发生错误,则抛出异常 |
|
*/ |
|
public static byte [] encode(byte [] inputByte, byte [] key) throws Exception { |
|
// 获取加密实例 |
|
Cipher c = Cipher.getInstance(transformation); |
|
// 根据密钥的字节数组创建 SecretKeySpec |
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key, name); |
|
// 创建 IvParameterSpec 对象,使用默认向量和字符集 |
|
IvParameterSpec ivParameterSpec = new IvParameterSpec(Default_iv.getBytes(StandardCharsets.UTF_8)); |
|
// 初始化加密实例 |
|
c.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); |
|
// 返回加密后的字节数组 |
|
return c.doFinal(inputByte); |
|
} |
|
|
|
public static void decodeFile(String inputFilePath, String outputFilePath, String key) throws Exception { |
|
byte[] inputBytes = Files.readAllBytes(Paths.get(inputFilePath)); |
|
byte[] decodeBytes = decode(inputBytes, key.getBytes(StandardCharsets.UTF_8)); |
|
Files.write(Paths.get(outputFilePath), decodeBytes); |
|
System.out.println("File decode successfully."); |
|
} |
|
|
|
|
|
|
|
public static byte[] decode(byte[] inputBytes, byte[] key) throws Exception { |
|
Cipher cipher = Cipher.getInstance(transformation); |
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key, name); |
|
IvParameterSpec ivParameterSpec = new IvParameterSpec(Default_iv.getBytes(StandardCharsets.UTF_8)); |
|
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); |
|
return cipher.doFinal(inputBytes); |
|
} |
|
|
|
public static String generateRandomString(int length) { |
|
Random random = new Random(); |
|
StringBuffer string = new StringBuffer(); |
|
|
|
for (int i = 0; i < length; i++) { |
|
// 生成随机字符(可以根据需要调整范围) |
|
int randomChar = random.nextInt(91); |
|
if (randomChar >= 48 && randomChar <= 57 || // 数字0-9 |
|
randomChar >= 65 && randomChar <= 90 || // 大写字母A-Z |
|
randomChar >= 97 && randomChar <= 122) { // 小写字母a-z |
|
string.append((char) randomChar); |
|
} else { |
|
i--; // 重新生成当前位置的字符 |
|
} |
|
} |
|
|
|
return string.toString(); |
|
} |
|
|
|
public static void main(String[] args) throws Exception { |
|
Security.addProvider(new BouncyCastleProvider()); |
|
String inputFile="D:\\data\\test01.docx"; //需要加密的文件 |
|
String enFile="D:\\data\\test01Encode.docx"; //加密后的文件 |
|
String deFile="D:\\data\\test01Decode.docx"; //解密后的文件 |
|
//String key="0123456789ABCDEF"; //加密密钥,注意必须是128bits,即16个字节 |
|
String key= generateRandomString(16) ; |
|
System.out.println(key); |
|
encodeFile(inputFile,enFile,key); |
|
decodeFile(enFile,deFile,key); |
|
|
|
|
|
} |
|
|
|
} |