As files in android assets can be easily hacked by converting .apk to .zip. I have some propitiatory model which I need to use in android application. I am working on how to encrypt the assets of the application. ( I will use firebase for retreiving the key for decryption to make it more secure )
I am pretty successful in encrypting and decrypting images (png and jpg) using cipher library in android.
Following is the code which I used for the purpose.
String fake = "sadhkja6";
byte[] encodedKey = Base64.decode(fake, Base64.DEFAULT);
yourKey= new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), id);
bitmap = Bitmap.createScaledBitmap(bitmap, 500,500, true);
byte[] output = getBytes(bitmap);
byte[] output = getBytesFile();
saveFile(output);
public static byte[] encodeFile(SecretKey yourKey, byte[] fileData)
throws Exception {
byte[] encrypted = null;
byte[] data = yourKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(data, 0, data.length,
algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
new byte[cipher.getBlockSize()]));
encrypted = cipher.doFinal(fileData);
return encrypted;
}
public byte[] getBytes(Bitmap bitmap){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress( Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();
return byteArray;
}
public static byte[] encodeFile(SecretKey yourKey, byte[] fileData)
throws Exception {
byte[] encrypted = null;
byte[] data = yourKey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(data, 0, data.length,
algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
new byte[cipher.getBlockSize()]));
encrypted = cipher.doFinal(fileData);
return encrypted;
}
void saveFile(byte[] array) {
String decrypted_file = "encypted.png";
try {
File file = new File(Environment.getExternalStorageDirectory()
+ File.separator, decrypted_file);
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(file));
yourKey = generateKey();
byte[] filesBytes = encodeFile(yourKey, array);
bos.write(filesBytes);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
But when I use the same code for encyrpting tensorflow models, the model is not successfully decompiled resulting in app crash. Most probably because we are loading the model in bytes which may cause problems.
Please tell me how can I use the cyphering technique for securing my tensorflow model. Thank you very much.
Related
I am implementing encryption/decryption to my files. code is given below. I can't find out the problem.
Am I missing anything? I need to implement 128 bit AES Encryption.
Is there anything wrong?
It end up with error
"javax.crypto.BadPaddingException: error:1e06b065:Cipher functions:EVP_DecryptFinal_ex:BAD_DECRYPT"
Please help me.
private static byte[] encodeFile(byte[] yourKey, byte[] fileData)
throws Exception {
byte[] encrypted = null;
SecretKeySpec skeySpec = new SecretKeySpec(yourKey, 0, yourKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(fileData);
return encrypted;
}
private static byte[] generateKey() throws NoSuchAlgorithmException {
byte[] keyStart = "This is my key".getBytes();
String id = "dummypass";
int iterationCount = 1000;
int saltLength = 32;
int keyLength = 128;
SecureRandom random = new SecureRandom();
byte[] salt = Arrays.copyOf(keyStart,saltLength);
random.nextBytes(salt);
KeySpec keySpec = new PBEKeySpec(id.toCharArray(), salt,
iterationCount, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = new byte[0];
try {
keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
SecretKey key = new SecretKeySpec(keyBytes, "AES");
return key.getEncoded();
}
private static byte[] decodeFile(byte[] yourKey, byte[] encryptedData)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(yourKey, 0, yourKey.length,
"AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encryptedData);
return decrypted;
}
public static void Encrypt(byte[] bytesToEncrypt, File target) {
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(target));
byte[] key = generateKey();
byte[] encryptedBytes = encodeFile(key, bytesToEncrypt);
bos.write(encryptedBytes);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] DecryptFile(byte[] bytesToDecrypt) {
byte[] decodedData = new byte[0];
try {
byte[] key = generateKey();
decodedData = decodeFile(key, bytesToDecrypt);
} catch (Exception e) {
e.printStackTrace();
}
return decodedData;
}
Verify that key is the same in both Encrypt and DecryptFile.
Since both call generateKey and generateKey calls SecureRandom nextBytes the keys are going to be different.
You need to save the encryption key for use during decryption.
Till kitkat, encryption/decryption is working good but in lollipop it decrypts only partial data.
I don't have problem with encryption because I encrypted a file with lollipop and decrypts it with kitkat it works fine but not vice versa.
Here is the code.
Encryption code
Encrypt(BufferedInputStream is, File destfile, String passcode) {
bis = is;
try {
fos = new FileOutputStream(destfile);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dest = new BufferedOutputStream(fos, 1024);
this.passcode = passcode;
}
static void encrypt() throws IOException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException {
// Length is 16 byte
SecretKeySpec sks = new SecretKeySpec(passcode.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[1024];
while ((b = bis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
bis.close();
}
Decryption code
public Decrypt(String path, String pathcode) {
// TODO Auto-generated constructor stub
filepath = path;
try {
fis = new FileInputStream(new File(path));
this.passcode = pathcode;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static String decrypt() throws IOException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException {
SecretKeySpec sks = new SecretKeySpec(passcode.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int size = fis.available();
byte[] resdata = new byte[size];
cis.read(resdata, 0, size);
String newres = new String(resdata, "UTF-8").trim();
//write("decrypted_file.xhtml",newres);
if(fis!=null)
{
fis.close();
}
if(cis!=null)
cis.close();
return newres;
}
What's the problem in this code? Do I need to do anything more?
available() doesn't necessarily return the length of the entire stream, just the estimated number of bytes that can be read without blocking. So, use a ByteArrayOutputStream to store the bytes and then covert to a byte array:
CipherInputStream cis = new CipherInputStream(fis, cipher);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int bytesRead;
byte[] data = new byte[1024];
while ((bytesRead = cis.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, bytesRead);
}
buffer.flush();
byte[] resdata = buffer.toByteArray();
String newres = new String(resdata, "UTF-8").trim();
I've never worked with encryption before. Actually I know nothing about encryption. I have a file encrypted with openssl tool using params:
openssl aes-256-cbc -nosalt -in fileIn -out fileOUT -p -k KEY
I need to decrypt it into memory but I don't know how. Can anyone provide me the code related to encryption?
Here's class I have written to decrypt a string encoded with params above (if I remmeber it correct):
public class CipherUtils {
public static byte[] getKey(String password, byte[] salt) {
try {
byte[] passwordSalt = EncodingUtils.getAsciiBytes(password);
passwordSalt = concatenateByteArrays(passwordSalt, salt);
byte[] hash1 = getHashForHash(null, passwordSalt);
byte[] hash2 = getHashForHash(hash1, passwordSalt);
byte[] key = concatenateByteArrays(hash1, hash2);
return key;
} catch (Exception e) {
return null;
}
}
public static byte[] getIV(String password, byte[] salt) {
try {
byte[] passwordSalt = EncodingUtils.getAsciiBytes(password);
passwordSalt = concatenateByteArrays(passwordSalt, salt);
byte[] hash1 = getHashForHash(null, passwordSalt);
byte[] hash2 = getHashForHash(hash1, passwordSalt);
byte[] hash3 = getHashForHash(hash2, passwordSalt);
return hash3;
} catch (Exception e) {
return null;
}
}
private static byte[] getHashForHash(byte[] hash, byte[] passwordSalt) {
try {
byte[] hashMaterial = concatenateByteArrays(hash, passwordSalt);
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(hashMaterial);
} catch (Exception e) {
return null;
}
}
private static byte[] concatenateByteArrays(byte[] a, byte[] b) {
if (a == null)
return b;
if (b == null)
return a;
byte[] result = new byte[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
}
Salt is an empty bytearray in this case. It uses apache-commons-compress.jar.
Here's usage example:
byte[] key = CipherUtils.getKey(password, null);
byte[] IV = CipherUtils.getIV(password, null);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
new IvParameterSpec(IV));
cis = new CipherInputStream(is, cipher);
Where is is an InputStream of encrypted data.
this may helps you
public 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("yourkey".getBytes(), "AES");
// Create cipher
Cipher cipher = Cipher.getInstance("AES/CBC");
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();
}
Decrypt
public void decrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream("data/encrypted");
FileOutputStream fos = new FileOutputStream("data/decrypted");
SecretKeySpec sks = new SecretKeySpec("yourkey".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC");
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();
}
I'm new to android. I'm doing an application which can download an encrypted png image file to sd card then displaying it after decryption. But I notice that I'm getting "javax.crypto.IllegalBlockSizeException: last block incomplete in decryption image decryption" when decrypting that downloaded image. Then I found that downloaded image size is 0KB (Original - 150KB). Then I downloaded my encrypted image from browser and checked. I'm getting the original image size. I'm sure there is something wrong in my image downloading class. But I cant figure it out. Please help me. Thanks in advance.
Image downloading AsyncTask Class
public class DownloadImagesTask extends AsyncTask<String, Void, Bitmap>
{
private String fileName;
#Override
protected Bitmap doInBackground(String... urls)
{
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
return download_Image(urls[0]);
}
#Override
protected void onPostExecute(Bitmap result)
{
storeImage(result);
}
private Bitmap download_Image(String url)
{
Bitmap bm = null;
File file = new File(url);
fileName = file.getName();
try
{
URL aURL = new URL(url);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
bis.close();
is.close();
}
catch (OutOfMemoryError e)
{
Log.e("Hub", "Error getting the image from server : " + e.getMessage().toString());
}
catch (IOException e)
{
Log.e("Hub", "Error getting the image from server : " + e.getMessage().toString());
}
return bm;
}
public void storeImage(Bitmap bm)
{
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
String extStorageDirectory = CommonUtils.getDataFromPreferences("metaPath", "");
Log.d("extStorageDirectory", extStorageDirectory);
OutputStream outStream = null;
File wallpaperDirectory = new File(extStorageDirectory);
if (!wallpaperDirectory.exists())
{
wallpaperDirectory.mkdirs();
}
File outputFile = new File(wallpaperDirectory, fileName);
if (!outputFile.exists() || outputFile.length() == 0)
{
try
{
outStream = new FileOutputStream(outputFile);
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
try
{
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
outStream.flush();
outStream.close();
Log.d("ScratchActivtiy", "Image Saved");
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
(All images were encrypted by me. And I hosted them in a Server. There is no issue in ancryption or decryption. I tested them. All are working fine.)
CryptClass
public class CryptClass
{
public byte[] encrypt(String seed, byte[] cleartext) throws Exception
{
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext);
// return toHex(result);
return result;
}
public byte[] decrypt(String seed, byte[] encrypted) throws Exception
{
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = encrypted;
byte[] result = decrypt(rawKey, enc);
return result;
}
//done
private byte[] getRawKey(byte[] seed) throws Exception
{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private 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;
}
private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception
{
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
}
If I understand correctly you are downloading the image first
BufferedInputStream bis = new BufferedInputStream(is);
bm = BitmapFactory.decodeStream(bis);
Then saving it to a file with PNG compression:
bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
And AFTER that doing your decryption on the file, right?
I think you might want to decrypt the bytes prior to saving them as a png, or maybe even prior to using the decodeStream. Otherwise you are decrypting the encrypted bytes that decode stream and PNG compression messed with.
Try skipping all of the BitmapFactory stuff and just save the initial file as-is, and then run your decryption. In your AsyncTask:
String saveFilePath = <path to the temporary encrypted file>;
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
int bytesRead = -1;
byte[] buffer = new byte[4096];
while ((bytesRead = is.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
Then run your decryption stuff on the saved file
I have done an encryption using the AES but iam not able to do the decryption Iam gettin an javax.crypto.IllegalBlockSizeException: last block incomplete in decryption.....I cant trace out where is the problem.I appreciate any help.
try {
in = new FileInputStream("/sdcard/Pic 1.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
File f=new File("/sdcard/Pic 1.txt");
buf = new byte[(int) f.length()+2];
try {
in.read(buf);
} catch (IOException e) {
e.printStackTrace();
}
try {
decryptedData = decrypt(key, buf);
decryptedimage = BitmapFactory.decodeByteArray(
decryptedData, 0, decryptedData.length);
loadedimage.setImageBitmap(decryptedimage);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void Encription(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
b = baos.toByteArray();
try {
keyStart = ".....".getBytes();
kgen = KeyGenerator.getInstance("AES");
sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
skey = kgen.generateKey();
key = skey.getEncoded();
encryptedData = encrypt(key, b);
encryptedimage = BitmapFactory.decodeByteArray(encryptedData, 0,
encryptedData.length);
out = new FileOutputStream("/sdcard/"+"Pic "+i+".txt");
out.write(encryptedData, 0, encryptedData.length);
out.close();
} catch (Exception e) {
}
i++;
}
private 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;
}
private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
long start=System.currentTimeMillis()/1000l;
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
02-19 08:27:06.972: W/System.err(12742): javax.crypto.IllegalBlockSizeException: last block incomplete in decryption