Sto lavorando su un'app di crittografia/decrittografia dei file. Sto usando un semplice file .txt per il test. Quando seleziono il file dall'app e scelgo di crittografarlo, l'intero file viene crittografato. Tuttavia, quando decritto solo una parte dei dati del file viene decifrato. Per qualche motivo i primi 16 byte/caratteri non vengono decifrati.android cipher non decrittografa i primi 16 byte/caratteri di dati crittografati
contenuti test_file.txt: "This sentence is used to check file encryption/decryption results."
risultato crittografia: "¾mÁSTÐÿT:Y„"O¤]ÞPÕµß~ëqrÈb×ßq²¨†ldµJ,O|56\e^-’@þûÝû"
risultato decrittazione: "£ÿÒÜÑàh]VÄþ„- used to check file encryption/decryption results."
Non ci sono errori nel logcat.
Cosa sto sbagliando?
metodo per crittografare il file:
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();
}
}
metodo per leggere il contenuto del file:
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;
}
metodo per generare la chiave segreta:
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);
}
Metodo di salvare dati crittografati/decodificato il file:
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();
}
}
metodo per decodificare il file:
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();
}
}
Questa riga di codice codifica il file:
//simple password for testing only
encryptor.encryptFile("password", "storage/emulated/0/Download/test_file.txt");
Questa linea decodifica il file di:
encryptor.decryptFile("password", "storage/emulated/0/Download/test_file.txt");
Edit: Grazie a DarkSquirrel42 e Oncaphillis. Voi ragazzi siete fantastici!
L'aggiunta di questa riga di codice alle funzioni di crittografia e decrittografia ha risolto il problema.
//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"));
e poi,
cipher.init(Cipher.XXXXXXX_MODE, sKeySpec, ivSpec);
Non utilizzare un IV prevedibile, ma generarne uno casuale e anteporre il testo cifrato. –