Share
Embed
Transcript
61 slides
-
Types of encryption • Symmetric Encryption ◦ Uses single key
to encrypt/decrypt data at rest • Asymmetric Encryption ◦ Uses a public/private key pair to encrypt/decrypt a message transfer • Hybrid Encryption ◦ Uses both symmetric and asymmetric encryption to optimize message transfer -
JetSec Crypto 2019 2021 2023 May 2025 Today Retired in
1.1.0 First stable version Deprecated in alpha07 First Alpha version Version 1.1.0 alpha06 -
Issues with JetSec Crypto • Deprecated since 2023 • Random
Crashes happening! -
So what do we do now? • Community fork •
Custom implementation -
AeadConfig.register() val aeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(AeadKeyTemplates.AES256_GCM) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref(context, "keyset_name", "keyset_pref")
.build().keysetHandle val aead = aeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), Aead::class.java ) -
AeadConfig.register() val aeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(AeadKeyTemplates.AES256_GCM) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref(context, "keyset_name", "keyset_pref")
.build().keysetHandle val aead = aeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), Aead::class.java ) -
AeadConfig.register() val aeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(AeadKeyTemplates.AES256_GCM) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref(context, "keyset_name", "keyset_pref")
.build().keysetHandle val aead = aeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), Aead::class.java ) -
val KEY_ALIAS = "My Key Name" fun generateKeyInAndroidMasterKeyStore() { val
keyGenParameterSpec = KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() val keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore") keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } -
val KEY_ALIAS = "My Key Name" fun generateKeyInAndroidMasterKeyStore() { val
keyGenParameterSpec = KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() val keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore") keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } -
val KEY_ALIAS = "My Key Name" fun generateKeyInAndroidMasterKeyStore() { val
keyGenParameterSpec = KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() val keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore") keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } -
val KEY_ALIAS = "My Key Name" fun generateKeyInAndroidMasterKeyStore() { val
keyGenParameterSpec = KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() val keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore") keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } -
val keyStore = KeyStore.getInstance("AndroidKeyStore") val doesKeyExists = keyStore.aliases().toList().find { it
== KEY_ALIAS } != null if (!doesKeyExists) { // Generate key } -
AeadConfig.register() val aeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(AeadKeyTemplates.AES256_GCM) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref(context, "keyset_name", "keyset_pref")
.build().keysetHandle val aead = aeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), Aead::class.java ) -
DeterministicAeadConfig.register() val deterministicAeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(DeterministicAeadKeyTemplates.AES256_SIV) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref( context, "deterministic_keyset_name",
"keyset_pref" ) .build().keysetHandle val deterministicAead = deterministicAeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), DeterministicAead::class.java -
DeterministicAeadConfig.register() val deterministicAeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(DeterministicAeadKeyTemplates.AES256_SIV) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref( context, "deterministic_keyset_name",
"keyset_pref" ) .build().keysetHandle val deterministicAead = deterministicAeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), DeterministicAead::class.java -
DeterministicAeadConfig.register() val deterministicAeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(DeterministicAeadKeyTemplates.AES256_SIV) .withMasterKeyUri("android-keystore://${KEY_ALIAS}") .withSharedPref( context, "deterministic_keyset_name",
"keyset_pref" ) .build().keysetHandle val deterministicAead = deterministicAeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), DeterministicAead::class.java -
// Encrypt and Decrypt Non-Determinstically aead.encrypt(plaintext, aad) aead.decrypt(ciphertext, aad) //
Encrypt and Decrypt Determinstically deterministicAead.encryptDeterministically(plaintext, aad) deterministicAead.decryptDeterministically(ciphertext, aad) -
// Encrypt and Decrypt Non-Determinstically aead.encrypt(plaintext, aad) aead.decrypt(ciphertext, aad) //
Encrypt and Decrypt Determinstically deterministicAead.encryptDeterministically(plaintext, aad) deterministicAead.decryptDeterministically(ciphertext, aad) -
“Warning: because Android Keystore is unreliable, we strongly recommend disabling
it by not setting any master key URI.” https://javadoc.io/static/com.google.crypto.tink/tink-android/1.16.0/com/google/ crypto/tink/integration/android/AndroidKeysetManager.html -
“When Android Keystore is disabled or otherwise unavailable, keysets will
be stored in cleartext. This is not as bad as it sounds because keysets remain inaccessible to any other apps running on the same device. Moreover, as of July 2020, most active Android devices support either full-disk encryption or file-based encryption, which provide strong security protection against key theft even from attackers with physical access to the device. Android Keystore is only useful when you want to require user authentication for key use, which should be done if and only if you're absolutely sure that Android Keystore is working properly on your target devices. “ https://javadoc.io/static/com.google.crypto.tink/tink-android/1.16.0/com/google/ crypto/tink/integration/android/AndroidKeysetManager.html -
Android OS Encryption 4.4 7.0 10.0 Enforce FBE File-based encryption
(FBE) Full-disk encryption (FDE) FDE encrypt the entire storage with single key. FBE encrypt individual files with multiple keys -
If you’re targeting minimum SDK 29 (Android 10), then you
probably don’t need any encryption as the OS automatically encrypt your app’s internal directory with a unique keys. -
Application Sandbox In addition, Android application are executed in individual
sandboxs so they cannot access the contents of other apps. -
val KEY_ALIAS = "My Key Name" fun generateKeyInAndroidMasterKeyStore() { val
keyGenParameterSpec = KeyGenParameterSpec.Builder( KEY_ALIAS, KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build() val keyGenerator = KeyGenerator.getInstance("AES", "AndroidKeyStore") keyGenerator.init(keyGenParameterSpec) keyGenerator.generateKey() } -
AeadConfig.register() val aeadKeySetHandle = AndroidKeysetManager.Builder() .withKeyTemplate(AeadKeyTemplates.AES256_GCM) .withSharedPref(context, "keyset_name", "keyset_pref") .build().keysetHandle
val aead = aeadKeySetHandle.getPrimitive( RegistryConfiguration.get(), Aead::class.java ) -
But if it’s stored in plain text, what if the
hacker gain root access, that expose the data stored, can they not use this plain text key to decrypt? -
• To gain root access, you’d have to unlock bootloader,
which would delete your internal data! ◦ An outlier is that some OS forks, like LineageOS, require unlocked bootloader to function. • Root detections are not reliable and hackers can still bypass these checks -
But what about attack that requires physical access? For example,
root access is an elevation of privilege attack. If a hacker gain physical access (and root access), encryption is not going to protect your data at rest anyways. There is no way to really prevent this! -
If encryption is not going to protect against these attacks,
why are we even doing encryption? -
The short is we don’t need encryption for data at
rest. • Existence of JetSec Crypto implies that the default shared preferences has security flaw which is not true • False sense of security bring more harm because devs thought that user’s data are protected and started storing more and more sensitive datas. • However, some sector still requires this due to legal reasons. In that case, use this custom implementation. -
Do not store sensitive data Architecture your system so that
sensitive data would only be stored on the backend and not on the frontend. -
Have short lifespan for sensitive data • Clear the data
on the device as soon as possible ◦ Example: User logout, data no longer relevant after a certain operation • Use Worker to periodically clean data -
Remote wipe Allow user to force logout and wipe their
data in the app through other means.