[ 加密 ] AES好是好 密钥长度却是固定 但我想任意位数可否
2021-09-04 本文已影响0人
一个好汉
用户想打架篇
用户输入的口令并不能直接作为AES的密钥进行加密
用户当场暴跳如雷...
比特长度恰好是128/192/256位或者说16/24/32字节
这可如何是好呀
再加上用户输入的口令一般都有规律,
安全性远远不如安全随机数产生的随机口令
极其容易被破解
用户输入的口令,通常还需要使用PBE算法,采用随机数杂凑计算出真正的密钥,再进行加密
来人 上代码
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;
/**
* 口令加密
* 记得引入 BouncyCastle jar包
*/
public class PBEEncrypt {
public static void main(String[] args) throws Exception {
// 把BouncyCastle作为Provider添加到java.security:
Security.addProvider(new BouncyCastleProvider());
// 原文:
String message = "Hello, world!";
// 加密口令:
String password = "hello12345";
// 16 bytes随机Salt:
byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
System.out.printf("salt: %032x\n", new BigInteger(1, salt));
// 加密:
byte[] data = message.getBytes(StandardCharsets.UTF_8);
byte[] encrypted = encrypt(password, salt, data);
System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(password, salt, encrypted);
System.out.println("decrypted: " + new String(decrypted, StandardCharsets.UTF_8));
}
/**
* 加密
*/
public static byte[] encrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
// 通过 SecretKeyFactory 获取Key
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
SecretKey skey = skeyFactory.generateSecret(keySpec);
// 通过加盐 获取 AlgorithmParameterSpec 指定了循环次数1000,循环次数越多 暴力破解难度越大
PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
// Cipher 初始化
Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
cipher.init(Cipher.ENCRYPT_MODE, skey, pbeps);
// 加密 搞定
return cipher.doFinal(input);
}
// 解密:
public static byte[] decrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
SecretKey skey = skeyFactory.generateSecret(keySpec);
PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);
return cipher.doFinal(input);
}
}
来人 上结果
salt: ee160bd84def30cbbd5feb04b60b7e41
encrypted: 5S8RWNzBLXRcUOiKB6e2vA==
decrypted: Hello, world!
来人 上结论
PBEwithSHA1and128bitAES-CBC-BC 算法通过用户口令和安全的随机salt计算出Key,然后底层使用AES再进行加密
Key通过口令和安全的随机salt计算得出,大大提高了安全性