How to encrypt and decrypt file in Android?

113,278

Solution 1

Use a CipherOutputStream or CipherInputStream with a Cipher and your FileInputStream / FileOutputStream.

I would suggest something like Cipher.getInstance("AES/CBC/PKCS5Padding") for creating the Cipher class. CBC mode is secure and does not have the vulnerabilities of ECB mode for non-random plaintexts. It should be present in any generic cryptographic library, ensuring high compatibility.

Don't forget to use a Initialization Vector (IV) generated by a secure random generator if you want to encrypt multiple files with the same key. You can prefix the plain IV at the start of the ciphertext. It is always exactly one block (16 bytes) in size.

If you want to use a password, please make sure you do use a good key derivation mechanism (look up password based encryption or password based key derivation). PBKDF2 is the most commonly used Password Based Key Derivation scheme and it is present in most Java runtimes, including Android. Note that SHA-1 is a bit outdated hash function, but it should be fine in PBKDF2, and does currently present the most compatible option.

Always specify the character encoding when encoding/decoding strings, or you'll be in trouble when the platform encoding differs from the previous one. In other words, don't use String.getBytes() but use String.getBytes(StandardCharsets.UTF_8).

To make it more secure, please add cryptographic integrity and authenticity by adding a secure checksum (MAC or HMAC) over the ciphertext and IV, preferably using a different key. Without an authentication tag the ciphertext may be changed in such a way that the change cannot be detected.

Be warned that CipherInputStream may not report BadPaddingException, this includes BadPaddingException generated for authenticated ciphers such as GCM. This would make the streams incompatible and insecure for these kind of authenticated ciphers.

Solution 2

I had a similar problem and for encrypt/decrypt i came up with this solution:

public static byte[] generateKey(String password) throws Exception
{
    byte[] keyStart = password.getBytes("UTF-8");

    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
    sr.setSeed(keyStart);
    kgen.init(128, sr);
    SecretKey skey = kgen.generateKey();
    return skey.getEncoded();
}

public static byte[] encodeFile(byte[] key, byte[] fileData) throws Exception
{

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(fileData);

    return encrypted;
}

public static byte[] decodeFile(byte[] key, byte[] fileData) throws Exception
{
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);

    byte[] decrypted = cipher.doFinal(fileData);

    return decrypted;
}

To save a encrypted file to sd do:

File file = new File(Environment.getExternalStorageDirectory() + File.separator + "your_folder_on_sd", "file_name");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
byte[] yourKey = generateKey("password");
byte[] filesBytes = encodeFile(yourKey, yourByteArrayContainigDataToEncrypt);
bos.write(fileBytes);
bos.flush();
bos.close();

To decode a file use:

byte[] yourKey = generateKey("password");
byte[] decodedData = decodeFile(yourKey, bytesOfYourFile);

For reading in a file to a byte Array there a different way out there. A Example: http://examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/

Share:
113,278
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I want to encrypt file and store it in SD card. I want to decrypt that encrypted file and store it in SD card again. I have tried to encrypt file by opening it as file stream and encrypt it but it is not working. I want some idea on how to do this.

  • abhy
    abhy about 11 years
    +1 for "Always specify the character encoding when encoding/decoding strings" :)
  • Maarten Bodewes
    Maarten Bodewes about 11 years
    @abhy From Java 7 onward you can use the StandardCharsets feature for your convenience. Obviously a static import of StandardCharsets may be useful as well.
  • abhy
    abhy about 11 years
    Thanks for updating. I really appreciate.
  • minhaz1
    minhaz1 almost 11 years
    I attempted to use this solution, but if I encrypt the file from the Android device I am unable to decrypt the file from my computer. It seems that the key that is generated isn't consistent. Do you know of a solution to that?
  • ZeroTek
    ZeroTek almost 11 years
    I already experienced some issus with this solution myself. It seems that different devices, android versions (and a computer of course) are creating different keys due to different versions of the underlying algorithm. My solution was to add the Charset and the Provider for SecureRandom. This solved my problems and should now work on all devices. I edited my Answer.
  • Piovezan
    Piovezan over 10 years
    Further reading on SecureRandom not working among different devices: stackoverflow.com/questions/13433529/…
  • Hamid
    Hamid over 10 years
    I'm assuming "IV" stands for "Initialisation Vector", you should say so at least once, perhaps the first time it's mentioned, for those who don't know. Also, it'd be nice to have links explaining why that particular configuration of Cipher is desirable.
  • Maarten Bodewes
    Maarten Bodewes over 10 years
    @Hamid OK, changed the text a bit, I did not expect this rather general advice to get so popular :)
  • Hamid
    Hamid about 10 years
    @owlstead Thanks for the tweaks, looks good now. I'm surprised you only have 7 upvotes considering 28k+ views right now. Just to clarify for those who arent sure, use a different, random IV for EACH message, never re-use the same IV for multiple messages. Patterns == Vulnerabilities.
  • Schiavini
    Schiavini about 10 years
    Great post. It might be a good idea to explain why the checksum would be important.
  • Kartheek Sarabu
    Kartheek Sarabu about 10 years
    what is yourByteArrayContainigDataToEncrypt in the code above
  • Maarten Bodewes
    Maarten Bodewes almost 10 years
    This is a copy of Android snippets, and it uses the same, incorrect method of deriving the key. Use this and you may loose your data.
  • ZeroTek
    ZeroTek almost 10 years
    yourByteArrayContainigDataToEncrypt is the Data of your file you want to encrypt sored in an byte[] array. Refer to the link inside my post on how to read a file into a byte array. But: owlstead is right this solution can cause some trouble. Use ChiperOutputStream instead as mentioned above.
  • ZeroTek
    ZeroTek over 9 years
    Use this solution instead of mine. This is the correct answer and should be markt.
  • Pedro Teran
    Pedro Teran about 9 years
    @MaartenBodewes I'm almost new on concpets of cyphering to decrypt or encyprt a file. Could you point us to the right direction of how to cypher a file. were I can find good lectures about it?
  • Ayaz Alifov
    Ayaz Alifov about 8 years
    @MaartenBodewes, please argument your statement, why do you think it is incorrect method of deriving the key? How can it be improved?
  • Maarten Bodewes
    Maarten Bodewes about 8 years
    This uses a random number generator to derive keys. This RNG does not need to rely only on the seed and the exact algorithm isn't specified. Instead lookup correct use of PBKDF2 or similar.
  • Jack
    Jack about 7 years
    Crypto has now been depreciated in android N - android-developers.googleblog.com/2016/06/…
  • Sagar
    Sagar almost 5 years
    Is it okay to directly return the key in bytes[], instead of going through all of the computations of the generateKey() method? @MaartenBodewes and everyone.
  • Maarten Bodewes
    Maarten Bodewes almost 5 years
    No, you'd use a password based key derivation function such as PBKDF2 to derive a key from a password (although, for encryption, the use of passwords should really be avoided altogether). You could also think of a way to decrypt an RSA asymmetric key with the password instead, and use that for decryption. Then you can just directly encrypt with the public key. Strange, overlooked your comment in my inbox, it seems.
  • MrinmoyMk
    MrinmoyMk about 4 years
    The decrypted file is having 0 bytes
  • Naroju
    Naroju almost 3 years
    @MaartenBodewes can you check my question? stackoverflow.com/questions/68690602/…