在我的应用程序中,我希望通过加密来存储一些安全数据。当用户希望我需要通过解密来向他显示它。 这工作正常。 但问题是我需要为每条消息存储加密消息和初始化向量。这个初始化向量是在加密时生成的,我必须在解密时使用它来获取原始消息。
因此,如果用户存储1000条消息,我需要存储这1000条加密消息和相应的1000条初始化向量。我想避免为每条消息存储初始化向量。
请告诉我使用初始化矢量进行AES-256加密的方法。
以下是我的加密和解密代码
/*
* This method will do the AES-256 encryption.
*/
private byte[] encrypt(char[] raw, String cardno) {
// This raw is some unique key like password.
SecretKeyFactory factory = null;
SecretKey tmp = null;
Cipher cipher = null;
byte[] ciphertext = null;
AlgorithmParameters params = null;
try {
factory = SecretKeyFactory.getInstance("PBEWITHSHA-256AND256BITAES-CBC-BC");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
KeySpec spec = new PBEKeySpec(raw, mSalt, 1024, 256);
try {
if (factory != null)
tmp = factory.generateSecret(spec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
if (tmp != null)
mSecret = new SecretKeySpec(tmp.getEncoded(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
if (cipher != null)
cipher.init(Cipher.ENCRYPT_MODE, mSecret);
} catch (InvalidKeyException e) {
e.printStackTrace();
}
if (cipher != null)
params = cipher.getParameters();
try {
mIV = params.getParameterSpec(IvParameterSpec.class).getIV();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
}
try {
ciphertext = cipher.doFinal(cardno.getBytes("UTF-8"));
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ciphertext;
}
/*
* This will decrypt the encrypted data based on provided key
*/
private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
//This raw is initialization vector generated while encrypting
Cipher cipher = null;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE, mSecret, new IvParameterSpec(raw));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
try {
decrypted = cipher.doFinal(encrypted);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return decrypted;
}
答案 0 :(得分:5)
更好的方法是在您保存的每个加密消息的开头添加初始化向量。由于填充已经可以在消息中添加一些字节,因此对于用例而言这应该不重要。
不要忘记,对于特定的块密码,IV总是具有固定的大小:块大小,您可以使用Java中的cipher.getBlockSize()
来检索。检索IV后,您只需使用cipher.doFinal(buf, offset, length)
代替cipher.doFinal(buf)
。
如果你真的不想存储IV,你可以从完整路径名(绝对路径,或从某个根,如果需要)计算IV,并在其上执行SHA-256等散列。只要路径是唯一的,SHA-256应该相对接近已知但随机的IV,这是最安全的。当然,如果你重命名/移动文件......
请注意,您试图仅保护自己大约16KB的初始化向量(1000 x 16,即块大小)。那不是很多。
答案 1 :(得分:2)
为了安全起见,您必须为每条消息使用初始化向量(和唯一的向量)。没有办法解决它。