使用基于密码的加密查看此 AES-128 CBC 示例
Review of this AES-128 CBC example with password-based encryption
我需要一些帮助来验证以下代码片段 Java 使用 CBC、PKCS5Padding 和 IV 进行 AES 加密。
我测试了代码,能够加密和解密。我有一些疑问,如下所述。
- 密码应该存储在哪里作为一个好的约定?
- appending/retrieving加盐和IV字节到密文的方式可以吗?
- 非常感谢任何其他评论,谢谢!
public class Encryption {
private static int iterations = 65536;
private static int keySize = 128;
private static char[] password = "password".toCharArray();
private static String algorithm= "PBKDF2WithHmacSHA1";
private static final String SEPARATOR = "~";
public static void main(String []args) throws Exception {
String filePath = "test.xml";
String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
String encrMesg = encrypt(fileContent);
System.out.println("Encrypted: " + encrypt(encrMesg));
System.out.println("Decrypted: " + decrypt(encrMesg));
}
public static String encrypt(String plaintext) throws Exception {
byte[] saltBytes = getSalt().getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
PBEKeySpec spec = new PBEKeySpec(password, saltBytes, iterations, keySize);
SecretKey secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretSpec);
AlgorithmParameters params = cipher.getParameters();
byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] cipherText = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(ivBytes)+SEPARATOR+DatatypeConverter.printBase64Binary(saltBytes)
+SEPARATOR+DatatypeConverter.printBase64Binary(cipherText);
}
public static String decrypt(String encryptedText) throws Exception {
System.out.println(encryptedText);
String[] encryptedArr = encryptedText.split(SEPARATOR);
byte[] ivBytes = DatatypeConverter.parseBase64Binary(new String(encryptedArr[0]));
byte[] salt = DatatypeConverter.parseBase64Binary(new String(encryptedArr[1]));
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedArr[2]));
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keySize);
SecretKey secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return new String(salt);
}
}
查询
Where should the password be stored as a good convention?
对称密钥最好存放在保险库中。否则他们应该进入密钥库,但是您会遇到保护密钥库密码的问题。
Is the way of appending/retrieving Salt and IV bytes to the Cipher
text is fine?
盐应生成:
SecureRandom random = SecureRandom.getInstanceStrong();
否则您使用的是较弱的熵池(即 linux 中的 /dev/urandom)来生成您的安全号码,这会导致更容易被破解的弱密钥。
Any other comments highly appreciated, thanks!
在处理字符串转换时,您应该始终使用相同的编码,即 .getBytes("UTF-8")
以避免出现问题。例如,在转换盐时不使用它。
我需要一些帮助来验证以下代码片段 Java 使用 CBC、PKCS5Padding 和 IV 进行 AES 加密。
我测试了代码,能够加密和解密。我有一些疑问,如下所述。
- 密码应该存储在哪里作为一个好的约定?
- appending/retrieving加盐和IV字节到密文的方式可以吗?
- 非常感谢任何其他评论,谢谢!
public class Encryption {
private static int iterations = 65536;
private static int keySize = 128;
private static char[] password = "password".toCharArray();
private static String algorithm= "PBKDF2WithHmacSHA1";
private static final String SEPARATOR = "~";
public static void main(String []args) throws Exception {
String filePath = "test.xml";
String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
String encrMesg = encrypt(fileContent);
System.out.println("Encrypted: " + encrypt(encrMesg));
System.out.println("Decrypted: " + decrypt(encrMesg));
}
public static String encrypt(String plaintext) throws Exception {
byte[] saltBytes = getSalt().getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
PBEKeySpec spec = new PBEKeySpec(password, saltBytes, iterations, keySize);
SecretKey secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretSpec);
AlgorithmParameters params = cipher.getParameters();
byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] cipherText = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(ivBytes)+SEPARATOR+DatatypeConverter.printBase64Binary(saltBytes)
+SEPARATOR+DatatypeConverter.printBase64Binary(cipherText);
}
public static String decrypt(String encryptedText) throws Exception {
System.out.println(encryptedText);
String[] encryptedArr = encryptedText.split(SEPARATOR);
byte[] ivBytes = DatatypeConverter.parseBase64Binary(new String(encryptedArr[0]));
byte[] salt = DatatypeConverter.parseBase64Binary(new String(encryptedArr[1]));
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedArr[2]));
SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keySize);
SecretKey secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return new String(salt);
}
}
查询
Where should the password be stored as a good convention?
对称密钥最好存放在保险库中。否则他们应该进入密钥库,但是您会遇到保护密钥库密码的问题。
Is the way of appending/retrieving Salt and IV bytes to the Cipher text is fine?
盐应生成:
SecureRandom random = SecureRandom.getInstanceStrong();
否则您使用的是较弱的熵池(即 linux 中的 /dev/urandom)来生成您的安全号码,这会导致更容易被破解的弱密钥。
Any other comments highly appreciated, thanks!
在处理字符串转换时,您应该始终使用相同的编码,即 .getBytes("UTF-8")
以避免出现问题。例如,在转换盐时不使用它。