实验二 电子传输系统安全-进展2
任务详情
- 上周任务完成情况(代码链接,所写文档等)
- 本周计划
上周任务完成情况
- 采用sm4对存储的公文进行加密处理,密钥随机生成,乱序存储在数据库中。其中sm4采用cbc模式,iv固定,跟随密文一起存储。解密的时候读取密文并分离密文和iv,然后解密。
- SM3加盐存储
代码
package cn.edu.nuc.article.util;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.util.encoders.Hex;
import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class SM3SaltHelper {
public static void main(String[] args) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 原始数据
byte[] data = "Hello, World!".getBytes();
// 生成随机的盐值
byte[] salt = generateSalt();
// 将原始数据与盐值拼接
byte[] dataWithSalt = concatBytes(data, salt);
// 计算SM3哈希值
byte[] hash = calculateHash(dataWithSalt);
// 将盐值和哈希值转换为十六进制字符串
String saltHex = bytesToHex(salt);
String hashHex = bytesToHex(hash);
System.out.println("Salt: " + saltHex);
System.out.println("Hash: " + hashHex);
}
public static String encrypt(String paramStr,byte[] salt){
Map<String,String> resultMap=new HashMap<>();
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 原始数据
byte[] data = paramStr.getBytes();
// 将原始数据与盐值拼接
byte[] dataWithSalt = concatBytes(data, salt);
// 计算SM3哈希值
byte[] hash = calculateHash(dataWithSalt);
// 将盐值和哈希值转换为十六进制字符串
String hashHex = bytesToHex(hash);
return hashHex;
}
public static String entryptSM3Password(String plainPassword) {
byte[] bytesSalt = generateSalt();
String sm3Password= encrypt(plainPassword,bytesSalt);
return bytesToHex(bytesSalt)+sm3Password;
}
public static byte[] generateSalt() {
byte[] salt = new byte[8];
new Random().nextBytes(salt);
return salt;
}
private static byte[] concatBytes(byte[] a, byte[] b) {
byte[] result = Arrays.copyOf(a, a.length + b.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
private static byte[] calculateHash(byte[] input) {
SM3Digest digest = new SM3Digest();
digest.update(input, 0, input.length);
byte[] result = new byte[digest.getDigestSize()];
digest.doFinal(result, 0);
return result;
}
public static String bytesToHex(byte[] bytes) {
return Hex.toHexString(bytes);
}
public static byte[] HexTobytes(String hexStr) {
return Hex.decode(hexStr);
}
}
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);
}
}
实现效果:
本周计划
- 最后调整优化代码
- 边界测试
- 增加用户数据量测试
- 验收