需求:
对给定的一串字符串进行加密解密,先用如下方式进行尝试
//密钥
private static final String encryptionKey = "SecretKey9970408";
//加解密算法/工作模式/填充方式
private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
private static byte[] encrypt(String plainText) throws Exception {
SecretKeySpec key = new SecretKeySpec(EncryptUtils.encryptionKey.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance(EncryptUtils.ALGORITHM_STR);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
}
问题:
给定的字符串有时只是改动一小部分,比如100个字符串,只改动最后2个,这导致生成的加密后字符串也是,前面大段相同的,只有一小部分不同,这样容易被看出规律。
解决:
思路是每次需要加密的字符串都可能只改动一小部分,就抓住这改动的小部分,放大扰动。
具体的做法是:计算待加密字符串每个字符的char值并求和,再将求到的和除以10并取余得到偏移量,将原字符串的每个字符的char值加上这个偏移量得到一个新的字符串,再将新的字符串按上面的方式再进行加密。以此来实现待加密字符串只改动了一小点,生成的加密后字符串改动很多,最终达到难找出规律的目的。
package lcfc.cloud.common.utils;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class EncryptUtils {
//生成偏移量
private static int calcOffset(String s) {
int sum = 0;
for (int i = 0; i < s.length(); i++) {
sum += s.charAt(i);
}
return sum % 10;
}
//加上偏移量
private static String addOffset(String plaintext, int offset) {
// 将字符串转换为字符数组
char[] charArray = plaintext.toCharArray();
// 对每个字符进行偏移
for (int i = 0; i < charArray.length; i++) {
charArray[i] = (char)(charArray[i] + offset);
}
// 将字符数组转换回字符串
return offset + ";" + new String(charArray);
}
//减去偏移量
private static String minusOffset(String ciphertext, int offset) {
ciphertext = ciphertext.substring(2);
// 将字符串转换为字符数组
char[] charArray = ciphertext.toCharArray();
// 对每个字符进行偏移
for (int i = 0; i < charArray.length; i++) {
charArray[i] = (char)(charArray[i] - offset);
}
// 将字符数组转换回字符串
return new String(charArray);
}
//密钥
private static final String encryptionKey = "SecretKey9970408";
//加解密算法/工作模式/填充方式
private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
private static byte[] encrypt(String plainText) throws Exception {
SecretKeySpec key = new SecretKeySpec(EncryptUtils.encryptionKey.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance(EncryptUtils.ALGORITHM_STR);
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
}
private static String decrypt(byte[] cipherText) throws Exception {
SecretKeySpec key = new SecretKeySpec(EncryptUtils.encryptionKey.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(cipherText), StandardCharsets.UTF_8);
}
// 加密 AES+偏移量
public static String encryptWithOffset(String plainText) throws Exception {
int offset = calcOffset(plainText);
String addCode = addOffset(plainText, offset);
byte[] cipherText = encrypt(addCode);
return Base64.getEncoder().encodeToString(cipherText);
}
// 解密 AES-偏移量
public static String decryptWithOffset(String cipherText) throws Exception {
byte[] cipherTextB = Base64.getDecoder().decode(cipherText);
String decryptedText = decrypt(cipherTextB);
return minusOffset(decryptedText, Integer.parseInt(decryptedText.substring(0,1)));
}
//调试用
public static void main(String[] args) throws Exception {
String content = "ABC;" +
"1420930972299227138,1420930972299227138,1420930972299227138,1420930972299227138,1420930972299227138," +
"1420930972299227138,1420930972299227138,1420930972299227138,1420930972299227138,1420930972299227138" +
"|M12;" +
System.currentTimeMillis();
int offset = calcOffset(content);
System.out.println("偏移量:" + offset);
System.out.println("原始字符串:" + content);
String addCode = addOffset(content, offset);
System.out.println("偏移后原始字符串:" + addCode);
byte[] cipherText = encrypt(addCode);
System.out.println("加密后字符串: " + Base64.getEncoder().encodeToString(cipherText));
String decryptedText = decrypt(cipherText);
System.out.println("解密后字符串: " + decryptedText);
String decode = minusOffset(decryptedText, Integer.parseInt(decryptedText.substring(0,1)));
System.out.println("偏移后解密字符串:" + decode);
}
}