• 14
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

name Punditsdkoslkdosdkoskdo

How to encrypt file from SD card using AES in Android?

I want to encrypt image from the sd card and store it again in SD card again using AES. The main idea is the application browse an image, then encrypt it when I push a button, then store it in sd card. so my image would be secure.

I already succeed do string encryption using AES from this tutorial http://www.androidsnippets.com/encryptdecrypt-strings, but I don't have idea how to do this with an image, not string.

This is how I do it with a string:

public static String encrypt(String seed, String cleartext) throws Exception  
{
    byte[] rawKey = getRawKey(seed.getBytes());
    byte[] result = encrypt(rawKey, cleartext.getBytes()); 
    return toHex(result);
}

private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception 
{
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(clear);
    return encrypted;
}

Can anyone help me give example code how to encrypt an image with AES?

maybe it must using I/O file stream but I don't have an idea how to implement with this code.

      • 2
    • Don't use that snippet. It's one of the worst out there. I tried to contact the authors & website, but I could not get in. Terrible example.
    • @user1421273 if i encrypt image files then can i share those image files after decryption directly or may i need to save decrypted image files on sdcard and then share it from app ?
      • 2
    • @MaartenBodewes I'm seeing you say this code snippet is not secure and safe, I got it, thanks. But why don't you write more secure and simple example instead of commenting?

If you take user input for the password make sure to read this answer.

You should take a look at: CipherInputStream and CipherOutputStream. They are used to encrypt and decrypt byte streams.

I have a file named cleartext. The file contains:

Hi, I'm a clear text.
How are you?
That's awesome!

Now, you have an encrypt() function:

static void encrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
    // Here you read the cleartext.
    FileInputStream fis = new FileInputStream("data/cleartext");
    // This stream write the encrypted text. This stream will be wrapped by another stream.
    FileOutputStream fos = new FileOutputStream("data/encrypted");

    // Length is 16 byte
    // Careful when taking user input!!! https://stackoverflow.com/a/3452620/1188357
    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
    // Create cipher
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, sks);
    // Wrap the output stream
    CipherOutputStream cos = new CipherOutputStream(fos, cipher);
    // Write bytes
    int b;
    byte[] d = new byte[8];
    while((b = fis.read(d)) != -1) {
        cos.write(d, 0, b);
    }
    // Flush and close streams.
    cos.flush();
    cos.close();
    fis.close();
}

After you execute this function, there should be a file names encrypted. The file contains the encrypted characters.

For decryption you have the decrypt function:

static void decrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
    FileInputStream fis = new FileInputStream("data/encrypted");

    FileOutputStream fos = new FileOutputStream("data/decrypted");
    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, sks);
    CipherInputStream cis = new CipherInputStream(fis, cipher);
    int b;
    byte[] d = new byte[8];
    while((b = cis.read(d)) != -1) {
        fos.write(d, 0, b);
    }
    fos.flush();
    fos.close();
    cis.close();
}

After the execution of decrypt, there should be a file named decrypted. This file contains the free text.

You write you're a "noob" but depending on the use-case of encryption you could do a lot of harm if you're not doing it the right way. Know your tools!

Usage of CipherOutputStream Oracle documentation:

SecretKeySpec skeySpec = new SecretKeySpec(y.getBytes(), "AES");

FileInputStream fis;
FileOutputStream fos;
CipherOutputStream cos;
// File you are reading from
fis = new FileInputStream("/tmp/a.txt");
// File output
fos = new FileOutputStream("/tmp/b.txt");

// Here the file is encrypted. The cipher1 has to be created.
// Key Length should be 128, 192 or 256 bit => i.e. 16 byte
SecretKeySpec skeySpec = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES"); 
Cipher cipher1 = Cipher.getInstance("AES");  
cipher1.init(Cipher.ENCRYPT_MODE, skeySpec);
cos = new CipherOutputStream(fos, cipher1);
// Here you read from the file in fis and write to cos.
byte[] b = new byte[8];
int i = fis.read(b);
while (i != -1) {
    cos.write(b, 0, i);
    i = fis.read(b);
}
cos.flush();

Thus, the encryption should work. When you reverse the process, you should be able to read the decrypted bytes.

  • 66
Reply Report
      • 1
    • When we decrypt the file, wouldn't it be somewhere on the SD card? Isn't it unsafe? What if someone wants on his app should be able to read the file?
      • 1
    • thank for posting such a nice answer.But is it possible to check file ("MyDifficultPassw" ) password before decryption ??? I am getting exception if using wrong password after decryption,so it will take too much time to know.Is there is anyway to verify password quickly without decryption before???...Thanks
      • 2
    • edited: i try to edit permission (android.permission.WRITE_EXTERNAL_STORAGE) in android manifest and the encryption/decryption works. Thank you Kiril :)

Starting android 10, there have been huge storage restrictions, so DocumentFile is going to be common compared to File class. So I am also providing answer using Uri.

fun Activity.encrypt(curLocUri: Uri, newLocUri: Uri, password: String, salt: String) : Boolean{
    // opening file input/outputStreams
    val fis = contentResolver.openInputStream(curLocUri) ?: return false
    val fos = contentResolver.openOutputStream(newLocUri) ?: return false

    try {
        var key: ByteArray = ("$salt$password").toByteArray(Charsets.UTF_8)
        val sha: MessageDigest = MessageDigest.getInstance("SHA-1")
        key = sha.digest(key)
        key = key.copyOf(16)
        val sks = SecretKeySpec(key, "AES")
        val cipher: Cipher = Cipher.getInstance("AES")
        cipher.init(Cipher.ENCRYPT_MODE, sks)
        val cos = CipherOutputStream(fos, cipher)
        var b: Int
        val d = ByteArray(8)
        while (fis.read(d).also { b = it } != -1) {
            cos.write(d, 0, b)
        }
        cos.flush()
        cos.close()
        return true
    } catch (e: Throwable){
        fis.close()
        fos.close()
        return false
    }
}

fun Activity.decrypt(curLocUri: Uri, newLocUri: Uri, password: String, salt: String): Boolean {
    // opening file input/outputStreams
    val fis = contentResolver.openInputStream(curLocUri) ?: return false
    val fos = contentResolver.openOutputStream(newLocUri) ?: return false

    try {
        var key: ByteArray = ("$salt$password").toByteArray(Charsets.UTF_8)
        val sha = MessageDigest.getInstance("SHA-1")
        key = sha.digest(key)
        key = Arrays.copyOf(key, 16)
        val sks = SecretKeySpec(key, "AES")
        val cipher = Cipher.getInstance("AES")
        cipher.init(Cipher.DECRYPT_MODE, sks)
        val cis = CipherInputStream(fis, cipher)
        var b: Int
        val d = ByteArray(8)
        while (cis.read(d).also { b = it } != -1) {
            fos.write(d, 0, b)
        }
        fos.flush()
        fos.close()
        cis.close()
        return true
    } catch (e: Throwable){
        fos.flush()
        fos.close()
        return false
    }
}

Here Uri s are the one received from file picker from onActivityResult.

For examples, you can find it here

  • 0
Reply Report