I have developed a main app, now I need to develop a second app which is identical to the first but only perform 70% of the functionality. I have modularized the main app's functionality but now I want to be able to turn them on/off base on a configuration file. The values in this configuration file need to be accessible within the context of Activities and Services. A lot of people suggested using SharedPrefences, but I don't need end user to modify this. It's only meant for developer to configure these settings. What's the best approach for this?
Now in android data can be stored in these ways
Now you don’t want to store configuration in shared preference, So i would suggest you to go in 2 ways
Create a SQLite database that is accessible by both apps OR
Create a file that stores the configuration data and is accessible by both apps
Whatever the method that you choose to store the data encrypt it using some encryption algorithm like this
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;
}
private static 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;
}
And invoke them like this:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos); // bm is the bitmap object
byte[] b = baos.toByteArray();
byte[] keyStart = "this is a key".getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
// encrypt
byte[] encryptedData = encrypt(key,b);
// decrypt
byte[] decryptedData = decrypt(key,encryptedData);
Now you can use the key to access these values and user would not be able to understand you configuration information
or you can use a web service to save data onto the server and your both apps can use that web service to get the configuration, It wont work offline though :(
Related
i'm working on Android application which requires to create secure channel between the app and the server(.NET), the first step is we creating shared secret, the app generates key pair (EC) and sends the public key to the server, then the server creates its own key pair and send the public key to the app and save the shared secret created based on app's public and server private keys and the server send back to the app its own public, salt and iv, then the app perform key agreement, the result is that both the android app and the server have string created based on public-private keys.
Later when the android app want to send some encrypted message to the server, i take the generated secret, salt and iv and creates secret key to be able use Cipher to encrypt the message.
The problem is even though the app and the server have exact the same shred secret, salt and iv for some reason android generates different SecretKey than the server (we checked in debug mode to see that the shared secret salt and iv are same).
Here is the code i use to create secret key:
byte[] sharedSecretBytes = Base64.decode(sharedSecretBase64, Base64.DEFAULT);
byte[] ivBytes = Base64.decode(ivBase64, Base64.DEFAULT);
byte[] saltBytes = Base64.decode(saltBase64, Base64.DEFAULT);
String sharedSecret = new String(sharedSecretBytes, "UTF-8");
//i tried to use different encoding, no luck.
//String sharedSecretAscii = new String(sharedSecretBytes, "ASCII");
char[] charArray = sharedSecret .toCharArray();
PBEKeySpec keySpec = new PBEKeySpec(charArray, saltBytes, 1000, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
//here the keyBytes are not the same as generated in the server.
byte[] keyBytes = key.getEncoded();
//i saw in some tutorial somene do this, not sure why because we can provide the key as is to the cipher,
//the problem is that both not working.
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(logNumber.getBytes("UTF-8"));
String asString = Base64.encodeToString(encrypted, Base64.NO_WRAP);
I also made try to pub hard-coded shared secret as "123abc" in both android and server side and actually it worked so my only guess is that the problem coming from converting the sharedSecrte.toCharArray(), if the sharedSecret contains weird characters can lead java generating bad secret key?
Also we working on iOS app that make exactly same process and have no issue to generate correct keys.
In the end the only thing that worked as expected was to use Bouncy Castle library
What i done is :
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
generator.init(sharedSecretBytes, saltBytes, 1000);
byte[] dk = ((KeyParameter) generator.generateDerivedParameters(256)).getKey();
SecretKeySpec secretKeySpec = new SecretKeySpec(dk, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(logNumber.getBytes("UTF-8"));
Still don't understand why native java.security makes trouble .
I am googling and testing solution for a while and so far no success. There is always some problem with it. Following code is "working" (meaning do not show any error while it is running) on Android Kitkat and higher, but decrypted files are not readable. Why?
final static byte[] iv = new byte[16];//ADDED
final static int buffer = 102400;
final static String encryptionType = "AES/CFB8/NoPadding";//CHANGED TO DIFFERENT TYPE
static void encrypt(String password, File fileInput, File fileOutput) throws Exception {
IvParameterSpec ivParams = new IvParameterSpec(iv);//ADDED
FileInputStream fis = new FileInputStream(fileInput);
FileOutputStream fos = new FileOutputStream(fileOutput);
SecretKeySpec sks = new SecretKeySpec(password.getBytes("UTF-8"), encryptionType);
Cipher cipher = Cipher.getInstance(encryptionType);
//cipher.init(Cipher.ENCRYPT_MODE, sks);REPLACED
cipher.init(Cipher.ENCRYPT_MODE, sks, ivParams);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[buffer];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
cos.flush();
cos.close();
fis.close();
}
static void decrypt(String password, File fileInput, File fileOutput) throws Exception {
IvParameterSpec ivParams = new IvParameterSpec(iv);//ADDED
FileInputStream fis = new FileInputStream(fileInput);
FileOutputStream fos = new FileOutputStream(fileOutput);
SecretKeySpec sks = new SecretKeySpec(password.getBytes("UTF-8"), encryptionType);
Cipher cipher = Cipher.getInstance(encryptionType);
//cipher.init(Cipher.ENCRYPT_MODE, sks);REPLACED
cipher.init(Cipher.DECRYPT_MODE, sks, ivParams);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[buffer];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
}
EDIT: After I changed type to "AES/CFB8/NoPadding", it seems to be ok, there is no error in process, but decrypted file is not readable.
The problem in the decrypt method is caused by this line:
cipher.init(Cipher.ENCRYPT_MODE, sks);
the mode needs to Cipher.DECRYPT_MODE, so the line should be
cipher.init(Cipher.DECRYPT_MODE, sks);
Other issues are the use of the long obsolete DESede algorithm, the lack of any IV generation and handling, the absence of a good password-based key derivation algorithm, and the lack of any MAC on the ciphertext. Correctly using AES GCM mode with proper nonce generation and handling, and use of PBKDF2 (which is available on Android and Oracle Java) would represent significant improvements.
You don't supply an IV, so one is generated for you automatically. You must find a way to transmit this IV to the recipient. Typically the IV/Nonce is prepending to the ciphertext and stripped off by the recipient in order to decrypt the data. CipherInputStream/CipherOutputStream does not do this for you, so you must do it on your own.
I finally solve this problem by using shorter password. I am not sure why, but on Android 7 and 8, there is no problem with long password, but same password on Android 4.4 leads to crazy errors and brake encryption.
How to do AES Decryption in android, without writing decrypted file in SDcard storage, directly use into android application? or if any other way to do file encryption for offline data storage?
I used AES in android once, this is the method that I use to encrypt:
public static byte[] encryptAES(SecretKey key, byte[] clear) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
this is the decrypting method:
public static byte[] decryptAES(SecretKey key, byte[] encrypted) {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
The following method generates a random key for AES:
public SecretKey newAESKey() {
try {
String s_key = new BigInteger(130, random).toString(32);
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(s_key.getBytes());
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
return skey;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
So first I generate a random AES key and then encrypt and decrypt bytes of what you want, in my case I used for String data.
SecretKey key = newAESkey();
....
String params = "....";
byte[] encrypted_params = encryptAES(key, params.getBytes());
I once used AES encryption and decryption on video files. I encrypted and decrypted it on the fly and ran it on the media player.
This is the library I used.
http://libeasy.alwaysdata.net/network/#server
It actually first sends the encrypted file to the local server, decrypts it and sends it back. I used that incoming stream to play.
By local server I mean, it creates a local HTTP server in the android system.
You will find many examples for this on SO.
If you use IOCipher or SQLCipher, you can stream files directly out of them, so that eliminates the need to decrypt to the SD Card or elsewhere. They both use AES256 encryption and have been audited to some degree.
There are easy to add any Android app. IOCipher is the same API as java.io.* and SQLCipher is the same API and android.database.*, so they are both really easy to use. For storing files, you can make an virtual encrypted disk using IOCipher. For encrypted database storage, use SQLCipher for Android. The CacheWord library makes it easy to manage the user password for that encrypted storage.
Here's how to add them via gradle:
compile 'net.zetetic:android-database-sqlcipher:3.3.1-2#aar'
compile 'info.guardianproject.cacheword:cachewordlib:0.1'
compile 'info.guardianproject.iocipher:IOCipher:0.3'
I have an Android app that encrypts data using AES with ECB and ZeroBytePadding. Everything works fine in that environment: encrypted data gets decrypted in Android without a problem, as follows:
public static String encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return android.util.Base64.encodeToString(encrypted, android.util.Base64.NO_WRAP);
}
public static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
However, I recently decided to decrypt the data in a Web app and when I tried to use the same decrypt() method, Cipher.getInstance("AES/ECB/ZeroBytePadding") threw an exception:
java.security.NoSuchAlgorithmException: Cannot find any provider supporting
AES/ECB/ZeroBytePadding
I assume that some Android library is providing a suitable cipher provider that is missing from javax.crypto.Cipher. Has anyone else had this problem or know what I can do about it? Changing the cipher padding to PKCS5PADDING is not an option, due to the many messages that are already encrypted with the earlier options.
Actually there is really not such an algorithm. Look at official java docs here http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
hi guys is there any simple way to encrypt and decrypt the images across platforms like decrypting the image in android encrypted in the iPhone and vise-versa.
Thanks in Advance..
You can use 56 bit DES encryption. It is supported both in iphone and android. You cannot use RSA because image may be larger than 127 byte. Two years before when I was trying with AES 128 bit encryption. I found there was limitation of using AES 128 bit encryption and put it in market place. So avoid AES also. java supprots AES. Hence nadorid also supports DES
AES encryption is the best way encrypt a file in android or in IOS.In android I have tried encryption.This link will help you to do in android .The below code will help tou to encrypt a byte array with the key in android.
encryptionKey will be your password
public static byte[] encrypt(byte[] key, byte[] data) throws Exception
{
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(data);
return encrypted;
}
/**
* DEcrypt byte array with given Key using AES Algorithm
* Key can be generated using <Code>getKey()</Code>
* #param key Key that Is used for decrypting data
* #param data Data passed to decrypt
* #return decrypted data
* */
public static byte[] decrypt1(byte[] key, byte[] encrypted) throws Exception
{
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
/**
* get the Key for encryption this can be used for while decrypting and encrypting too.
* */
public static byte[] getKey() throws Exception
{
byte[] keyStart = EncrypteDecrypte.encryptionKey.getBytes();
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
return key;
}