Jos*_* C. 5 java encryption android aes
我正在开发一个文件加密/解密应用程序.我正在使用一个简单的.txt文件进行测试.当我从应用程序中选择文件并选择加密时,整个文件数据都会被加密.但是,当我解密时,只有部分文件数据被解密.由于某种原因,前16个字节/字符不会被解密.
test_file.txt内容: "This sentence is used to check file encryption/decryption results."
加密结果: "¾mÁSTÐÿT:Y„"O¤]ÞPÕµß~ëqrÈb×ßq²¨†ldµJ,O|56\e^-’@þûÝû"
解密结果: "£ÿÒÜÑàh]VÄþ„- used to check file encryption/decryption results."
logcat中没有任何错误.
我究竟做错了什么?
加密文件的方法:
public void encryptFile(String password, String filePath) {
byte[] encryptedFileData = null;
byte[] fileData = null;
try {
fileData = readFile(filePath);//method provided below
// 64 bit salt for testing only
byte[] salt = "goodsalt".getBytes("UTF-8");
SecretKey key = generateKey(password.toCharArray(), salt);//method provided below
byte[] keyData = key.getEncoded();
SecretKeySpec sKeySpec = new SecretKeySpec(keyData, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
encryptedFileData = cipher.doFinal(fileData);
saveData(encryptedFileData, filePath);//method provided below
}
catch (Exception e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
读取文件内容的方法:
public byte[] readFile(String filePath) {
byte[] fileData;
File file = new File(filePath);
int size = (int) file.length();
fileData = new byte[size];
try {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file));
inputStream.read(fileData);
inputStream.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return fileData;
}
Run Code Online (Sandbox Code Playgroud)
生成密钥的方法:
private SecretKey generateKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase computation time. You
// should select a value that causes computation to take >100ms.
final int iterations = 1000;
// Generate a 256-bit key
final int outputKeyLength = 256;
SecretKeyFactory secretKeyFactory;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// Use compatibility key factory -- only uses lower 8-bits of passphrase chars
secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1And8bit");
}
else {
// Traditional key factory. Will use lower 8-bits of passphrase chars on
// older Android versions (API level 18 and lower) and all available bits
// on KitKat and newer (API level 19 and higher).
secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
}
KeySpec keySpec = new PBEKeySpec(password, salt, iterations, outputKeyLength);
return secretKeyFactory.generateSecret(keySpec);
}
Run Code Online (Sandbox Code Playgroud)
将加密/解密数据保存到文件的方法:
private void saveData(byte[] newFileData, String filePath) {
File file = new File(filePath);
try {
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
outputStream.write(newFileData);
outputStream.flush();
outputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
解密文件的方法:
public void decryptFile(String password, String filePath) {
byte[] decryptedFileData = null;
byte[] fileData = null;
try {
fileData = readFile(filePath);
byte[] salt = "goodsalt".getBytes("UTF-8");//generateSalt();
SecretKey key = generateKey(password.toCharArray(), salt);
byte[] keyData = key.getEncoded();
SecretKeySpec sKeySpec = new SecretKeySpec(keyData, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
decryptedFileData = cipher.doFinal(fileData);
saveData(decryptedFileData, filePath);
}
catch (Exception e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
这行代码加密文件:
//simple password for testing only
encryptor.encryptFile("password", "storage/emulated/0/Download/test_file.txt");
Run Code Online (Sandbox Code Playgroud)
该行解密文件:
encryptor.decryptFile("password", "storage/emulated/0/Download/test_file.txt");
Run Code Online (Sandbox Code Playgroud)
编辑:感谢DarkSquirrel42和Oncaphillis.你们真棒!
将这行代码添加到加密和解密函数中解决了我的问题.
//note: the initialization vector (IV) must be 16 bytes in this case
//so, if a user password is being used to create it, measures must
//be taken to ensure proper IV length; random iv is best and should be
//stored, possibly alongside the encrypted data
IvParameterSpec ivSpec = new IvParameterSpec(password.getBytes("UTF-8"));
Run Code Online (Sandbox Code Playgroud)
然后,
cipher.init(Cipher.XXXXXXX_MODE, sKeySpec, ivSpec);
Run Code Online (Sandbox Code Playgroud)
你的问题与密码的操作模式有关... cbc或密码块链接模式
一般来说,CBC很简单......无论你以前的加密块输出是什么,在加密之前将xor放到当前输入上
对于第一个块,我们显然有一个问题...没有先前的块...因此我们引入了一个叫做IV的东西...一个初始化向量...一个随机字节的块集...
现在......你可以想象,当你想要解密时,你将需要相同的IV ...
既然你没有保存,AES实现每次都会给你一个随机的...
因此,您没有解密块1的所有信息...这是AES的情况下的前16个字节...
在处理CBC模式数据时,总是一个很好的选择,只需在您的cypertext输出中添加使用过的IV ...... IV应该是随机的......这不是秘密......
| 归档时间: |
|
| 查看次数: |
1948 次 |
| 最近记录: |