I am working on file encryption / decryption. I am using a simple .txt file for testing. When I select a file from the application and select for encryption, all file data is encrypted. However, when I decrypt only part of the files, the data is decrypted. For some reason, the first 16 bytes / characters are not decrypted.
Contents of test_file.txt: "This sentence is used to check file encryption/decryption results."
encryption result: "¾mÁSTÐÿT:Y„"O¤]ÞPÕµß~ëqrÈb×ßq²¨†ldµJ,O|56\e^-'@þûÝû"
decryption result: "£ÿÒÜÑàh]VÄþ„- used to check file encryption/decryption results."
There are no errors in logcat.
What am I doing wrong?
File Encryption Method:
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(); } }
The way to read the contents of a 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; }
Secret key generation method:
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); }
The way to save encrypted / decrypted data to a 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(); } }
File decryption method:
public void decryptFile(String password, String filePath) { byte[] decryptedFileData = null; byte[] fileData = null; try { fileData = readFile(filePath); byte[] salt = "goodsalt".getBytes("UTF-8");
This line of code encrypts the file:
//simple password for testing only encryptor.encryptFile("password", "storage/emulated/0/Download/test_file.txt");
This line decodes the file:
encryptor.decryptFile("password", "storage/emulated/0/Download/test_file.txt");
Edit : thanks to DarkSquirrel42 and Oncaphillis. You guys are awesome!
Adding this line of code to encrypt and decrypt functions solved my problem.
//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"));
and then
cipher.init(Cipher.XXXXXXX_MODE, sKeySpec, ivSpec);