I am new to android. I am trying to learn and work on it. Can some one help me with the following issue.
I have some fields to be encrypted and uploaded to a DB using android.
The fields which should be encrypted are DOB, Email id, Phone number and some other numeric values.
Now I am doing some formal encryption by substitution.
Can some one help me with an example to do some standard form of encryption.
There are a lot of encryption libraries out there, but it depends on which language you are using. For Java, take a look here: http://www.androidsnippets.com/encryptdecrypt-strings.
Or use Google and search for
android +encryption +library +<your programming language>
The biggest challenge I believe is what encryption to use and how to keep the secret key safe. It doesn't matter what data you want to encrypt or where you want to store it. The key has to remain a secret. And you need to be able to use the exact same key to get the data decrypted.
You can 't store the key together with the data itself. Even not within the protected app resources. Some alternatives:
Getting the key from a service
Get the key (in a secure way) from a remote service. This adds the challenge to protect that communication channel but if possible it might be a valid approach.
The below code example can be used with a key retrieved elsewhere. Just check the encrypt and decrypt parts of the code.
Using a Password derived Key
Another option is using secret input from the user (aka password) to generate a key. The method that generates the key will always return the same key for each unique password. Hence you can recover the key if the user enters the password.
Ideally this password is never stored and always prompted for on each encryption/decryption need. This also relies on a proper password choice from the user.
A code example that shows key generation, encryption and decryption of some sample data. Note how we don't use the default settings for the key generation.
package com.example.android.secure;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class EncryptionManager {
// we should get a password from the user
String password = "...";
String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
// Important not to rely on default here !!!! use CBC instead of ECB
String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
int NUM_OF_ITERATIONS = 1000;
int KEY_SIZE = 256;
// generated on first run
byte[] salt = "abababababababababa bab".getBytes();
byte[] iv = "1234567890abcdef".getBytes();
// This is the value to be encrypted.
String clearText = "...";
byte[] encryptedText;
byte[] decryptedText;
public void exampleCodeNoRealMethod() {
try {
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, NUM_OF_ITERATIONS, KEY_SIZE);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(PBE_ALGORITHM);
SecretKey tempKey = keyFactory.generateSecret(pbeKeySpec);
SecretKey secretKey = new SecretKeySpec(tempKey.getEncoded(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher encCipher = Cipher.getInstance(CIPHER_ALGORITHM);
encCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
Cipher decCipher = Cipher.getInstance(CIPHER_ALGORITHM);
decCipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
encryptedText = encCipher.doFinal(clearText.getBytes());
decryptedText = decCipher.doFinal(encryptedText);
String sameAsClearText = new String(decryptedText);
} catch (Exception e) {
// TODO handle this exception
}
}
}
Using the Android KeyStore
This is a new feature only available on the latest Android devices. More information can be found on this blog post. I added a snippet from there:
public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
final int iterations = 1000;
// Generate a 256-bit key
final int outputKeyLength = 256;
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey;
}
Related
I have android application which has payment gateway and another services.Iam using AES Model to encrypt and decrypt data between the app and the server.Iam using KEY and IV constants which stored in android class. My problem is how to encrypt these constants ( IV and Key) in the android application to prevent any attacker to make decompile for the APK file and show these constants.
You have to Encrypt the Key with a RSA Public Key and only the Server knows the privatekey for this public key and can decrypt it.
You decrypt the AES Key with the private key on the serverside and use the decrypted AES Key to decrypt your original message.
//Edit
This is an example for the Java Code in Android Studio. My RSA Public key is stored in the shared preferences.
When the app is installed it makes a call to a Server, where a RSA Key pair is produced, both keys are saved in a Database and the Public Key is sent to the Device and saved in the shared preferences. Whenever something Needs to be Encrypted the stored Public Key is created and used for Encryption and only the Server knows the private key.
byte[] ENCRYPTED_AES_KEY_IN_BYTE = null;
String ENCRYPTED_AES_KEY;
cipher = null;
cipher = Cipher.getInstance("RSA/NONE/OAEPwithSHA-1andMGF1Padding");
// Get the shared preferences where the public key is stored
// SharedPreferences preferences = getApplicationContext().getSharedPreferences(preferences,Context.MODE_PRIVATE);
// get the Publickey stored as string in the shared preferences
String stringkey = preferences.getString(PUBLICKEY,"");
// create a public RSA Key from the stored key
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(stringkey,Base64.DEFAULT));
KeyFactory keyFactory;
PublicKey key =null;
keyFactory = KeyFactory.getInstance("RSA");
key = keyFactory.generatePublic(spec);
//Encrypt the AES key with the RSA public key
cipher.init(Cipher.ENCRYPT_MODE, key);
ENCRYPTED_AES_KEY_IN_BYTES = AES_KEY.getEncoded();
ENCRYPTED_AES_KEY_IN_BYTE = cipher.doFinal(ENCRYPTED_AES_KEY_IN_BYTE);
ENCRYPTED_AES_KEY = Base64.encodeToString(ENCRYPTED_AES_KEY_IN_BYTE,Base64.DEFAULT);
//ENCRYPTED_AES_KEY is now the Encrypted AES Key as string
// EDIT #2
Create a RSA KEY pair at the server
$rsa = new Crypt_RSA();
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS8);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
extract($rsa->createKey());
$publickey = str_replace("-----BEGIN PUBLIC KEY-----\r\n","",$publickey);
$publickey = str_replace("-----END PUBLIC KEY-----","",$publickey);
$privatekey = str_replace("-----BEGIN PRIVATE KEY-----\r\n","",$privatekey);
$privatekey = str_replace( "-----END PRIVATE KEY-----","",$privatekey);
the privatekey is saved to a Database and the Publickey is sent to the Client to Encrypt data.
To Decrypt the Data on the Serverside again
$rsa = new Crypt_RSA();
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS8);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setEncryptionMode( CRYPT_RSA_ENCRYPTION_OAEP);
$IV = base64_decode($IV);
$AESkey = base64_decode($AESkey);
$rsa->loadKey($privatekey);
$AESkey = $rsa->decrypt($AESkey);
// replace empty spaces with a + , this is something which can happen when you use a http request
$encrypteddata = str_replace(" ", "+", $encrypteddata);
$encrypteddata = base64_decode($encrypteddata);
$method = "AES-256-CBC";
$decrypteddata = openssl_decrypt($encrypteddata, $method, $AESkey, OPENSSL_RAW_DATA,$IV);
In this Code is not included how you store the privatekey in a Database and how you get it back from the Database.
I am working on mobile product. We are using the data in xml document. In order to keep our data secure we need an encryption algorithm(but we don't want the existing algorithm to import)
Can u give me some steps to encrypt the data.(if code example is most welcome).
To be more secure, you have to do with your own secret key. Try to use this code
KeyStore ks = KeyStore.getInstance();
// get the names of all keys created by our app
String[] keyNames = ks.saw("");
// store a symmetric key in the keystore
SecretKey key = Crypto.generateKey();
boolean success = ks.put("secretKey1", key.getEncoded());
// check if operation succeeded and get error code if not
if (!success) {
int errorCode = ks.getLastError();
throw new RuntimeException("Keystore error: " + errorCode);
}
// get a key from the keystore
byte[] keyBytes = ks.get("secretKey1");
SecretKey key = new SecretKeySpec(keyBytes, "AES");
// delete a key
boolean success = ks.delete("secretKey1");
If you want to develop your own encryption scheme, be prepared to embark on a research project. You can use any of standard encryption algorithms like AES/DES etc, with your private keys that are sufficiently long and difficult to crack.
public string PassEncrypt(string Password)
{
// Encrypting the password entered by User
// ======================================================
MD5 md5 = new MD5CryptoServiceProvider();
md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(Password));
byte[] result = md5.Hash;
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < result.Length; i++)
{
strBuilder.Append(result[i].ToString("x2"));
}
return strBuilder.ToString();
// ======================================================
}
OR
You may refer on this links :
developer.motorala.com
codereview.stackexchange.com
android snippets
java-tips.org
I'm using a custom subclass of SharedPreferences to encrypt my saved settings in the app, similar to what's being done in the second response here: What is the most appropriate way to store user settings in Android application
The number of preferences I have to save is growing. Before I was just using a custom view to update these preferences but that is going to become cumbersome and I want to use PreferenceActivity or PreferenceFragment instead. Problem is, it does not seem that there is a way to have either of those classes access my data using my subclass, meaning that the data it pulls from the default preferences file is going to be gibberish as it wasn't decrypted.
I've found that some people have created custom implementations of Preference that encrypt the data there, but I'd prefer not to do that as the data is already being encrypted/decrypted in my SharedPreferences subclass and I'd like to keep it that way. I've also been looking over the source code of PreferenceActivity and PreferenceManager and I'm not sure the best way to approach this.
Has anyone else had any luck accomplishing something like this and have any suggestions as to where I might start?
I think by keeping your encryption in the SharedPrefs subclass that you already have, you limit the modularity and the separation of concerns.
So I would suggest reconsidering sub-classing the preference classes themselves (such as CheckBoxPreference) and perform your calculation there.
Ideally you could also use some type of composition or a static utility so that while you might have to subclass each type of preference you use, you can use a single place to perform the encryption/decryption calculations. This would also allow you more flexibility in the future if you need to encrypt or decrypt some other data or if the API changes.
For sub-classing maybe you could do this:
So for example:
class ListPreferenceCrypt extends ListPreference
{
ListPreferenceCrypt (Context context, AttributeSet attrs) {
super ( context, attrs );
}
ListPreferenceCrypt (Context context) {
super ( context );
}
#Override
public void setValue( String value )
{
//encrypt value
String encryptedVal = MyCryptUtil.encrypt(value);
super.setValue ( encryptedVal );
}
#Override
public String getValue( String key )
{
//decrypt value
String decryptedValue = MyCryptUtil.decrypt(super.getValue ( key ));
return decryptedValue;
}
}
NOTE the above is psuedo-code, there would be different methods to override
And your XML might look like this:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="#string/inline_preferences">
<com.example.myprefs.ListPreferenceCrypt
android:key="listcrypt_preference"
android:title="#string/title_listcrypt_preference"
android:summary="#string/summary_listcrypt_preference" />
</PreferenceCategory>
</PreferenceScreen>
EDIT
Caveats/Decompiling
As I thought about this more, I realized one of the caveats is that this method is not particularly difficult to bypass when decompiling an APK. This does give the full class names of overriden classes in the layouts (though that can be avoided by not using XML)
However, I don't think this is significantly less secure than sub-classing SharedPreferences. That too, is susceptible to decompiling. Ultimately, if you want stronger security, you should consider alternative storage methods. Perhaps OAuth or the AccountManager as suggested in your linked post.
How about this:
Store a byte[16] in a .SO. If you do not use a .SO then make one just for that purpose.
Use that byte array to crypt a new byte[16] then Base64 encode the result. Hardcode that in your class file.
Now that you've setup the keys let me explain:
Yes, potentially one could peek into the .SO and find the byte array ergo your key. But with the cyphered key2 being base64 encoded, he would need to decode it and reverse the encryption with the said key to extract key2 bytes. So far this only involves dissassembling the app.
When you want to store encrypted data, first do a AES pass with key1, then a AES/CBC/Padding5 pass with Key2 and an IV*
You can safely Base64 encode the IV and save it like that in your /data/data folder if you'd like to change the IV every time a new password is stored.
With these two steps disassembling the app is no longer the only thing required, as it's now required to also take control of your runtime to get to the crypted data. Which you have to say is pretty sufficient for a stored password.
Then you could simply store that into SharedPreferences :) That way if your SharedPreferences get compromised, the data is still locked away. I don't think subclassing it is really the right approach but since you already wrote your class - oh well.
Here's some code to further illustrate what I mean
//use to encrypt key
public static byte[] encryptA(byte[] value) throws GeneralSecurityException, IOException
{
SecretKeySpec sks = getSecretKeySpec(true);
System.err.println("encrypt():\t" + sks.toString());
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, sks, cipher.getParameters());
byte[] encrypted = cipher.doFinal(value);
return encrypted;
}
//use to encrypt data
public static byte[] encrypt2(byte[] value) throws GeneralSecurityException, IOException
{
SecretKeySpec key1 = getSecretKeySpec(true);
System.err.println("encrypt():\t" + key1.toString());
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key1, cipher.getParameters());
byte[] encrypted = cipher.doFinal(value);
SecretKeySpec key2 = getSecretKeySpec(false);
System.err.println("encrypt():\t" + key2.toString());
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key2, new IvParameterSpec(getIV()));
byte[] encrypted2 = cipher.doFinal(encrypted);
return encrypted2;//Base64Coder.encode(encrypted2);
}
//use to decrypt data
public static byte[] decrypt2(byte[] message, boolean A) throws GeneralSecurityException, IOException
{
SecretKeySpec key1 = getSecretKeySpec(false);
System.err.println("decrypt():\t" + key1.toString());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key1, new IvParameterSpec(getIV()));
byte[] decrypted = cipher.doFinal(message);
SecretKeySpec key2 = getSecretKeySpec(true);
System.err.println("decrypt():\t" + key2.toString());
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key2);
byte[] decrypted2 = cipher.doFinal(decrypted);
return decrypted2;
}
//use to decrypt key
public static byte[] decryptKey(String message, byte[] key) throws GeneralSecurityException
{
SecretKeySpec sks = new SecretKeySpec(key, ALGORITHM);
System.err.println("decryptKey()");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks);
byte[] decrypted = cipher.doFinal(Base64Coder.decode(message));
return decrypted;
}
//method for fetching keys
private static SecretKeySpec getSecretKeySpec(boolean fromSO) throws NoSuchAlgorithmException, IOException, GeneralSecurityException
{
return new SecretKeySpec(fromSO ? getKeyBytesFromSO() : getKeyBytesFromAssets(), "AES");
}
What do you think?
I realize it might be off topic since you're asking about using your own SharedPreferences but I'm giving you a working solution to the problem of storing sensitive data :)
I'm developing an Android app which based on a web-server. Users, who installed the app, should register on web, so they can login. When someone try to login I verify their information with API.
So I'm curious about persisting and encryption processes. Should I encrypt the values or just put them all to SharedPreferences? If encryption is needed what's the efficient way?
And last but not least, Is SharedPreferences enough in terms of security?
Thanks.
Encryption is easy, but the real question is with what key? If you hardcode the key in the app, or derive it from some known value, anyone with access to the device can easily decrypt those values. What you are achieving is merely obfuscation. Since Android doesn't have a public API to the system keystore, there is not much else you can do if you need to save the actual password. Unless of course you make the user input a password each time they start the app, which kind of defeats the purpose.
If you control both the server and the client, another approach is to use some form of token-based authentication and only save the token. Since tokens can expire and be revoked, the damage by someone getting hold of your token is much less, than exposing an actual password (which may be used on other sites as well).
Of course you should encrypt user settings like login, password or maybe email. I prefer SharedPreferences for storing, and yes it's enough in terms of security.
I've found this two method on StackOverflow, it's fair enough:
protected String encrypt( String value ) {
try {
final byte[] bytes = value!=null ? value.getBytes(UTF8) : new byte[0];
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.System.ANDROID_ID).getBytes(UTF8), 20));
return new String(Base64.encode(pbeCipher.doFinal(bytes), Base64.NO_WRAP),UTF8);
} catch( Exception e ) {
throw new RuntimeException(e);
}
}
protected String decrypt(String value){
try {
final byte[] bytes = value!=null ? Base64.decode(value,Base64.DEFAULT) : new byte[0];
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(SEKRIT));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(Settings.Secure.getString(context.getContentResolver(),Settings.System.ANDROID_ID).getBytes(UTF8), 20));
return new String(pbeCipher.doFinal(bytes),UTF8);
} catch( Exception e) {
throw new RuntimeException(e);
}
}
Couldn't find link, if I found, I'll edit my answer.
Edit: I found the source, you may have a look at all discussion on here.
i'm looking very hard for a possibility to encrypt my sqlite database on Android devices, but I was't able to find a satisfying solution.
I need something like a libary to reference, in order to have a "on the fly" encryption/decryption of my database, while using the normal sqlite functions.
I don't want to encrypt data before storing.
I don't want to encrypt the whole databasefile, in order to decrypt it before using.
I know about the following projects:
SEE
wxSQLite
SQLCipher
SQLiteCrypt
Botan
But I can't find any working example for this stuff.
Btw, I'm absolutly willing to purchase a commercial build, but I have to test ist before spending a few hundred dollars.
Did anyone solve this issue for his own?
Try the SQLCipher port to Android instead of the regular SQLCipher.
litereplica supports encryption using the ChaCha cipher, faster than AES on portable devices.
There are bindings for Android.
To create and open an encrypted database we use an URI like this:
"file:/path/to/file.db?cipher=...&key=..."
If anyone is still looking:
Override SQLiteOpenHelper function as below:
void onConfigure(SQLiteDatabase db){
db.execSQL("PRAGMA key = 'secretkey'");
}
private String encrypt(String password) {
try {
SecretKeySpec keySpec = generateKey(password);
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE,keySpec);
byte[] encVal = c.doFinal(password.getBytes());
String encryptedValue = Base64.encodeToString(encVal,Base64.DEFAULT);
return encryptedValue;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private SecretKeySpec generateKey(String password) throws Exception {
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
digest.update(bytes,0,bytes.length);
byte[] key = digest.digest();
SecretKeySpec secretKeySpec = new SecretKeySpec(key,"AES");
return secretKeySpec;
}
I just used the encrypt function to encrypt the password. Here I used the user's password as a key. Therefore I don't need to keep the key inside the application. When the user wants to log in, simply encrypt the password and try to match with the encrypted password in the database and allow them to log in.