0

I'm using sqlcipher to store data from my app and I'm having trouble firstly, generating a secret key and secondly storing in keystore.

Btw, needs to be without user interaction like described in android docs

Here is how I'm attempting to generate the secret,

KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey key = keyGen.generateKey();

Here, is where I'm setting up the sqldatabase

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(databaseFile, "password_string", null);

So the question, how do I use the secret in the password string? As at the moment, I can only get the secret as a byte array.

Kaigo
  • 1,267
  • 2
  • 14
  • 33

2 Answers2

1

Please find below utilities for using AES to encrypt/decrypt. You can use the secret key to encrypt/decrypt your password. However, I will not recommend this, since you have to store your secret key also and the problem is still there, how can you save your secret key securely? In this case, a common practice is to using a hash function: SHA-256, MD5... to hash your password and store it. Later, when you want to check whether users enter a correct password, just hash whatever they enter and compare with the value you stored.

private static int BLOCKS = 128;

  public static byte[] encryptAES(String seed, String cleartext)
      throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes("UTF8"));
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    return cipher.doFinal(cleartext.getBytes("UTF8"));
  }

  public static byte[] decryptAES(String seed, byte[] data) throws Exception {
    byte[] rawKey = getRawKey(seed.getBytes("UTF8"));
    SecretKeySpec skeySpec = new SecretKeySpec(rawKey, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    return cipher.doFinal(data);
  }

  private static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    sr.setSeed(seed);
    kgen.init(BLOCKS, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
  }
Victor Cao
  • 54
  • 2
  • Forgot to mention, I am storing in keystore. So I can use `byte[] raw = skey.getEncoded();` to get the raw secret and pass that to sqlcipher. Thanks – Kaigo Mar 28 '18 at 09:23
0

This is my way to generate random and quasi secure password:

fun generatePassword(): String{
     val androidId = Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)

     val passPassphraseBase = "${BuildConfig.APPLICATION_ID}_$androidId:"

     val random = SecureRandom()
     val salt = ByteArray(32)
     random.nextBytes(salt)

     val passPhrase = passPassphraseBase.toByteArray() + salt

     val pass = Base64.encodeToString(passPhrase, Base64.NO_WRAP)

     return pass
} 

You can ask what for I need Application ID and Android ID. Just to increase entropy (and maybe length) of our password.

Then I store this password encrypted in shared preferences. I encrypt all shared preferences keys and values with keystore RSA algorithm.

After all we end up with generated symmetric encryption password encrypted with asymmetric algorithm.

All of this is just a white-box cryptography where we have our key and encrypted data stored in one place.

We can increase security if we add some external source for at least part of our password. For that we can use:

  • something from our backend
  • user input or biometric
Artur Latoszewski
  • 735
  • 1
  • 10
  • 21