我有一个使用Realm加密的Android应用。设置Realm加密时,很少有用户在启动过程中收到IllegalBlockSizeException的情况。
我们使用以下功能创建密钥:
private fun getOrGenerateKey() : ByteArray {
val keyPair = getOrGenerateKeyPair()
val prefs = applicationContext.getSharedPreferences(RealmPrefs, Context.MODE_PRIVATE)
val cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding") // We need an algorithm supported on all android API levels
// Try reading the encrypted AES key from the preferences
val key = prefs.getString(RealmPrefsAES, null);
if(key == null) {
// No key was stored, generate a new byte array, encrypt then store:
val keyBytes = ByteArray(64)
SecureRandom().nextBytes(keyBytes)
cipher.init(Cipher.ENCRYPT_MODE, keyPair.public)
val encryptedBytes = cipher.doFinal(keyBytes)
prefs.edit()
.putString(RealmPrefsAES, Base64.encodeToString(encryptedBytes, Base64.URL_SAFE))
.apply()
return keyBytes;
}
cipher.init(Cipher.DECRYPT_MODE, keyPair.private)
return cipher.doFinal(Base64.decode(key.trim(), Base64.URL_SAFE))
}
@SuppressLint("InlinedApi")
private fun getOrGenerateKeyPair() : KeyPair {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null);
val keyEntry = keyStore.getEntry(RealmKeyAlias, null) as KeyStore.PrivateKeyEntry?
if(keyEntry != null) {
return KeyPair(
keyEntry.certificate.publicKey,
keyEntry.privateKey
)
}
// If we got here, there was no key and we need to generate a new one. That is done differently in the API levels:
return if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore")
kpg.initialize(KeyGenParameterSpec.Builder(
RealmKeyAlias,
KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT)
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build())
kpg.generateKeyPair()
} else {
val start = Calendar.getInstance()
val end = Calendar.getInstance()
end.add(Calendar.YEAR, 100)
@Suppress("DEPRECATION") // Deprecation handled by SDK version test
val spec = KeyPairGeneratorSpec.Builder(applicationContext)
.setAlias(RealmKeyAlias)
.setSubject(X500Principal("CN=$RealmKeyAlias"))
.setSerialNumber(BigInteger.ONE)
.setStartDate(start.time)
.setEndDate(end.time)
.build()
val kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore")
kpg.initialize(spec)
kpg.generateKeyPair()
}
}