How to encrypt file from SD card using AES in Android? - 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.

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.

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

Related

How can I make pdf file readable only by my app?

Is it possible to download a PDF from server and save in format that only my application can read?
This is my working example used in my app ....hope this help you
Is it possible to download pdf from server and save
Yes i have use retrofit library to download pdf file from server you can use Volly or Loopj AsyncTask as well
After downloading pdf file you will get InputeStream object of file than encrypt that and store in app private folder (so no other application can able to use it)
public static File encryptAndSaveFileInPrivateFolder(
Context context, String albumName, InputStream inputStream, String fullFileName) {
File file = null;
try {
// Get the directory for the app's private pictures directory.
File fileDirectory = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES),""+albumName);
if (!fileDirectory.exists()) {
fileDirectory.mkdirs();
}
file = new File(fileDirectory,""+fullFileName);
if (file.exists()) {
file.delete();
}
FileOutputStream output = new FileOutputStream(file);
encrypt(inputStream,output);
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
This method encrypt your file
public static void encrypt(InputStream fis,FileOutputStream fos ) 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");
String password ="passwordProtectd";
// Length is 16 byte
byte[] inputByte = password.getBytes("UTF-8");
SecretKeySpec sks = new SecretKeySpec(inputByte, "AES");
// SecretKeySpec sks = new SecretKeySpec(password.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();
}
Than show pdf using intent
public void decryptFileAndShow(Context context,File mFile) {
try{
if (null != mFile) {
String parentPath = mFile.getAbsoluteFile().getParent();//Actual encrypted file path
File tempFile = new File(parentPath, "report.pdf"); //Created new file that decrypted format after view we will delete this
//tempFile =File.createTempFile("prefix","TestMyPDF.pdf", context.getExternalFilesDir(""));
Utilities.decrypt( new FileInputStream(mFile), new FileOutputStream(tempFile));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(tempFile), "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
context.startActivity(intent);
tempFile.deleteOnExit();
}
}catch (Exception e){
e.printStackTrace();
}
}
Last the method used for decryption
public static void decrypt(FileInputStream fis,FileOutputStream fos ) throws IOException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException {
// FileInputStream fis = new FileInputStream("data/encrypted");
// FileOutputStream fos = new FileOutputStream("data/decrypted");
String password ="passwordProtectd";
byte[] inputByte = password.getBytes("UTF-8");
SecretKeySpec sks = new SecretKeySpec(inputByte, "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();
}
Is it possible to download pdf from server.
Yes, it is possible. Download your pdf and encrypt and decrypt your file accordingly.
You can try like this using CipherOuputStream and CipherInputStream:
byte[] buf = new byte[1024];
Encryption:
public void encrypt(InputStream in, OutputStream out) {
try {
// Bytes written to out will be encrypted
out = new CipherOutputStream(out, ecipher);
// Read in the cleartext bytes and write to out to encrypt
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
}
}
Decryption:
public void decrypt(InputStream in, OutputStream out) {
try {
// Bytes read from in will be decrypted
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
}
}
If I understand your question correctly, you want your application to be the only application that reads this particular PDF files. You want to know how you can ensure that you do that.
Since your requirement is not genuine(hacky), the solution also has to be a bit hacky.
You can download the file and store it with your own custom extension (eg. file.mypdf)
Have an intent filter, that supports mimetypes matching .mypdf files
You could have the server encrypt the download and your client side app decrypt it using a public/private key pair. This would prevent anyone with a snooping proxy from observing and saving your content, but it wouldn't deter the most determined users from stealing these documents as they would eventually exist in decrypted form somewhere. To achieve that you'd probably ave to create your own PDF viewer and damage the bytes of the PDF in a way that your viewer can do, but no other viewer can recover

How can I lock a file in android?

So the scenario of my problem is in my application I am fetching some file from the internet then I put them in internal storage then when user wants to access these file User can access them through my application.
I did all the thing but I want to provide some security in my application So what I want is?
User can see my file only in my application. User unable to access them from the file manager. Don't tell me the solution to put dot
before file name or folder name I did that the problem with this
solution is when I access them by putting dot before file name the
file are again visible .
I also want that when the user open my file ,just like a pdf in pdf reader He/She restricted to save or download them through pdf
reader or another application.
Any Kind of help is appreciated by me.
You can encrypt that file so user won't be able to access them. here is the encryption method which works for me.
public void encrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
// Here you read your file.
FileInputStream fis = new FileInputStream("Path Of your file");
// This stream write the encrypted text. This stream will be wrapped by another stream.
FileOutputStream fos = new FileOutputStream("Path Of your file");
// Length is 16 byte
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();
}
Here is the method for decryption of particular file.
public void decrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream("Path Of your file");
FileOutputStream fos = new FileOutputStream("Path Of your file");
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();}
you can encrypt your files with an encryption algorithm and save them with your custom file extension then you can make an intent filter for opening them from File Manager and for more security i prefer the JNI For whole Encryption system .

Best way to store pdf files in android

IN our application we are getting byte array from server if login gets success. We are converting those byte array into PDF format and storing those files into DB which using internal memory.If files are in KB , application works properly but of files size get increase in MB then application gives out of memory error.Please tell me how to handle this scenario?How to store files into SD card to maintain security also.It should not visible to outside user.
Please do help.
Thanks,
AA.
You should take a look at:
CipherInputStream and CipherOutputStream. They are used to encrypt and decrypt byte streams.
EDIT: So here you go!
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
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.
Edit: 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.
Storing on the SD card will make the file accessible to savvy users. Storing in the db will give you errors like you mentioned. Probably the best idea would be to go to internal storage. This isn't perfect (rooted users can browse to the files), but it's probably the best option.
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal

How to lock Android folder programmatically?

I am making an Android application, and I want to prevent users from opening some folder. In that folder user can store image or video files. It would be great if I could protect that folder with password.
Which is the best way to do that?
Here is Both function for encrypt and decrypt file in Sdcard folder.
we can not lock folder but we can encrypt file using AES in Android, it may help you.
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
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();
}
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();
}
You should save this information on the internal storage. Normally other apps can't access these files. From the quideliness:
You can save files directly on the device's internal storage. By default, files saved to the internal storage are private to your application and other applications cannot access them (nor can the user). When the user uninstalls your application, these files are removed.
See the link: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
Insted of LOCK i will saggest you make folder with . like foldername -> .test
user cant see that folder here is code
File direct = new File(Environment.getExternalStorageDirectory() + "/.test");
if(!direct.exists())
{
if(direct.mkdir())
{
//directory is created;
}
}
above code is create folder with name ".test" (in SD CARD) then save your data(file, video.. whatever) in this folder user cant access it.
if you create folder in internal storage then if user clear data of your app then that folder may EMPTY!

Implement Progress bar in android

I am developing a file encryption and decryption app and to show the user a little progress bar of the file encryption and decryption. I need to implement a progress bar. How do I do that ? For the below code.
public void main(String[] args) throws Exception
{
// File to decrypt.
filename = "/file.enc";
String password = "codecodecode";
inFile = new FileInputStream(new File(Environment.getExternalStorageDirectory()+ filename));
outFile = new FileOutputStream(new File(Environment.getExternalStorageDirectory()+ filename + ".txt"));
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey passwordKey = keyFactory.generateSecret(keySpec);
// Read in the previouly stored salt and set the iteration count.
byte[] salt = new byte[8];
inFile.read(salt);
int iterations = 100;
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, iterations);
// Create the cipher and initialize it for decryption.
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
cipher.init(Cipher.DECRYPT_MODE, passwordKey, parameterSpec);
byte[] input = new byte[64];
int bytesRead;
while ((bytesRead = inFile.read(input)) != -1)
{
byte[] output = cipher.update(input, 0, bytesRead);
if (output != null)
outFile.write(output);
}
byte[] output = cipher.doFinal();
if (output != null)
outFile.write(output);
inFile.close();
outFile.flush();
outFile.close();
}
Check the tutorial on progress bars: https://developer.android.com/guide/topics/ui/dialogs.html#ShowingAProgressBar
There is also the "Example ProgressDialog with a second thread" - nice to check.
Also consider using AsyncTask for such kind of things, it has a built in support for publishing progress update events on UI thread.

Categories

Resources