Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Yakiv Mospan, Svyatoslav Hromyak] Secure data in Android

[Yakiv Mospan, Svyatoslav Hromyak] Secure data in Android

Presentation from GDG DevFest Ukraine 2017 - the biggest community-driven Google tech conference in the CEE.

Learn more at: https://devfest.gdg.org.ua

Google Developers Group Lviv

October 14, 2017
Tweet

More Decks by Google Developers Group Lviv

Other Decks in Technology

Transcript

  1. Secure data in Android Remember to hard reset whenever you

    leave your device on the table Yakiv Mospan Android Developer @ Team Technologies Svyatoslav Hromyak Android Developer @ Team Technologies
  2. Prerequisites Kotlin Gradle Plugin 1.1.50 Android SDK 26 Android Studio

    3.0 Beta 6 Android Virtual Device API 18 Android Virtual Device API 23 Fetch or download sample source code from GitHub https://github.com/TeamTechnologies/security-workshop-sample #dfua
  3. Overview #dfua Developing Secrets Keeper Application Encryption in Android Compatibility,

    Fingerprint and Confirm Credentials Encryption What is it? How it works ?
  4. Key How it works Secret key Private key Public key

    sh7aertsca.. Сipher data Financial data Credentials Sensitive data Plain data Algorithm Asymmetric Symmetric RSA EC AES DES #dfua
  5. How it works Plain data #dfua sh7aertsca.. Сipher data Secret

    key Private key Public key Key RSA EC AES DES Financial data Credentials Sensitive data Algorithm Asymmetric Symmetric
  6. Secret key Private key Public key Key How it works

    Sensitive data Personal life information, physical or mental health details, criminal or civil offences, private photos, private user documents, etc. #dfua sh7aertsca.. Сipher data RSA EC AES DES Financial data Credentials Algorithm Asymmetric Symmetric Plain data
  7. How it works #dfua sh7aertsca.. Сipher data Secret key Private

    key Public key Key Accounts, transactions, reports, credit card information, etc. RSA EC AES DES Credentials Algorithm Asymmetric Symmetric Plain data Sensitive data Financial data
  8. How it works Sensitive data Financial data Credentials #dfua sh7aertsca..

    Сipher data Secret key Private key Public key Key Usernames, passwords, touch pincodes, fingerprint data, and all other stuff that can provide access to data above. RSA EC AES DES Algorithm Asymmetric Symmetric Plain data
  9. How it works Plain data Algorithm #dfua sh7aertsca.. Сipher data

    Secret key Private key Public key Key RSA EC AES DES Financial data Credentials Sensitive data Asymmetric Symmetric
  10. How it works The oldest and best-known technique. The encryption

    key and the decryption key are the same. #dfua sh7aertsca.. Сipher data Secret key Private key Public key Key RSA EC AES DES Financial data Credentials Sensitive data Plain data Asymmetric Algorithm Symmetric
  11. sh7aertsca.. Сipher data How it works #dfua A modern branch

    of cryptography. Also known as public-key cryptography in which the algorithms employ a pair of keys (a public key and a private key) and use a different component of the pair for different steps of the algorithm. Secret key Private key Public key Key RSA EC AES DES Financial data Credentials Sensitive data Plain data Algorithm Asymmetric Symmetric
  12. How it works #dfua sh7aertsca.. Сipher data Secret key Private

    key Public key Key EC DES Financial data Credentials Sensitive data RSA Plain data Algorithm Asymmetric Symmetric AES
  13. How it works #dfua sh7aertsca.. Сipher data Secret key Private

    key Public key Key Financial data Credentials Sensitive data Plain data EC RSA Algorithm Asymmetric Symmetric AES DES
  14. How it works #dfua sh7aertsca.. Сipher data Secret key Private

    key Public key Key Financial data Credentials Sensitive data Plain data EC Algorithm Asymmetric Symmetric RSA AES DES
  15. How it works Asymmetric Symmetric RSA EC AES DES #dfua

    sh7aertsca.. Сipher data Secret key Private key Public key Key Financial data Credentials Sensitive data Plain data Algorithm
  16. How it works Key #dfua sh7aertsca.. Сipher data Private key

    Public key Secret key Asymmetric Symmetric RSA EC AES DES Financial data Credentials Sensitive data Plain data Algorithm
  17. Private key Public key How it works Secret key A

    single secret key which is used in conventional symmetric encryption to encrypt and decrypt a message. Symmetric #dfua sh7aertsca.. Сipher data RSA EC AES DES Asymmetric Financial data Credentials Sensitive data Plain data Algorithm Key
  18. How it works Private key Public key Asymmetric Key Pair.

    #dfua sh7aertsca.. Сipher data Secret key RSA EC AES DES Symmetric Financial data Credentials Sensitive data Plain data Algorithm Asymmetric Key
  19. How it works A single secret key which is used

    in conventional symmetric encryption which is used to encrypt and decrypt a message. #dfua sh7aertsca.. Сipher data Secret key RSA EC AES DES Symmetric Financial data Credentials Sensitive data Plain data Algorithm Asymmetric Private key Public key Key
  20. How it works The public component of a pair of

    cryptographic keys used for encryption in asymmetric cryptography. Asymmetric #dfua sh7aertsca.. Сipher data Secret key RSA EC AES DES Symmetric Financial data Credentials Sensitive data Plain data Algorithm Private key Public key Key
  21. Сipher data How it works #dfua sh7aertsca.. Private key Public

    key Secret key RSA EC AES DES Asymmetric Symmetric Financial data Credentials Sensitive data Plain data Algorithm Key
  22. How it works sh7aertsca.. Сipher data Cipher Output #dfua Private

    key Public key Secret key RSA EC AES DES Asymmetric Symmetric Financial data Credentials Sensitive data Key Plain data Algorithm
  23. Key How it works Plain data Сipher data #dfua sh7aertsca..

    Private key Public key Secret key RSA EC AES DES Asymmetric Symmetric Financial data Credentials Sensitive data Algorithm
  24. Android builds on the Java Cryptography Architecture (JCA), that provides

    API for digital signatures, certificates, encryption, keys generation and management. #dfua
  25. Keys KeyPair Generator Architecture Key Generator Provides the public API

    for generating symmetric cryptographic keys. #dfua Cipher Certificate Key Store Secure Random Provider
  26. Key Store Keys Certificate KeyPair Generator Architecture Key Generator An

    engine class which is capable of generating a private key and its related public key utilizing the algorithm it was initialized with. #dfua Cipher Secure Random Provider
  27. Provider KeyPair Generator Architecture Secure Random Key Generator Generates cryptographically

    secure pseudo-random numbers. #dfua Cipher Certificate Key Store Keys
  28. KeyPair Generator Secure Random Key Generator Provider Architecture Keys Keys

    created with Generators. #dfua Cipher Certificate Key Store
  29. KeyPair Generator Secure Random Key Generator Provider Architecture Key Store

    Keys #dfua Cipher Certificate Database with a well secured mechanism of data protection, that is used to save, get and remove keys. Requires entrance password and passwords for each of the keys.
  30. KeyPair Generator Secure Random Key Generator Provider Cipher Architecture Certificate

    Key Store Keys Certificate used to validate and save asymmetric keys. #dfua
  31. KeyPair Generator Secure Random Key Generator Provider Architecture Cipher Provides

    access to implementations of cryptographic ciphers for encryption and decryption. #dfua Certificate Key Store Keys
  32. KeyPair Generator Architecture Certificate Key Store Keys Secure Random Key

    Generator Provider Defines a set of extensible implementations - independent API’s. #dfua Cipher
  33. AndroidKeyStore JCA Provider implementation No Keystore passwords (really, at all)

    Key material never enters the application process Key material may be bound to the secure hardware Asymmetric keys available from 18 + Symmetric keys available from 23 + #dfua
  34. Main goal of sample application is to to save user

    Secrets locally and keep them protected using Encryption, Fingerprint and Confirm Credentials API’s. #dfua
  35. Requirements Support Android 18 + Devices Allow user to access

    application only if Lock Screen is set Protect user password with Encryption Protect user Secrets with Encryption Allow user to access Secrets with Fingerprint Add additional Confirm Credentials protection #dfua
  36. Project is separated on different Stages using gradle flavors. Stage

    represents some task, that need to be completed. Stage can have subtasks - levels.
  37. If during the session you went out of time, lost

    focus, came later than others or something just went wrong - select next Stage or Level and continue to work on it.
  38. Slides are mostly designed to explain the use cases and

    APIs. Guides with more detailed information (what need to be done to complete the stage and full code snippets) are placed in Readme file . On each Stage you need to listen for explanations from Slide and follow the Readme Guides in parallel. If something went wrong, you can apply any of Stages or Levels instantly by changing the flavor.
  39. val keyguardManager = context.getSystemService( Context.KEYGUARD_SERVICE) as KeyguardManager fun isDeviceSecure(): Boolean

    = if (hasMarshmallow()) keyguardManager.isDeviceSecure else keyguardManager.isKeyguardSecure fun hasMarshmallow(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M Device Lock Screen SystemServices class #dfua
  40. val keyguardManager = context.getSystemService( Context.KEYGUARD_SERVICE) as KeyguardManager fun isDeviceSecure(): Boolean

    = if (hasMarshmallow()) keyguardManager.isDeviceSecure else keyguardManager.isKeyguardSecure fun hasMarshmallow(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M Device Lock Screen SystemServices class #dfua System Service that is used to check if device/keyguard is secure.
  41. val keyguardManager = context.getSystemService( Context.KEYGUARD_SERVICE) as KeyguardManager fun isDeviceSecure(): Boolean

    = if (hasMarshmallow()) keyguardManager.isDeviceSecure else keyguardManager.isKeyguardSecure fun hasMarshmallow(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M Device Lock Screen SystemServices class #dfua Returns whether the device is secured with a PIN, pattern or password.
  42. val keyguardManager = context.getSystemService( Context.KEYGUARD_SERVICE) as KeyguardManager fun isDeviceSecure(): Boolean

    = if (hasMarshmallow()) keyguardManager.isDeviceSecure else keyguardManager.isKeyguardSecure fun hasMarshmallow(): Boolean = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M Device Lock Screen SystemServices class #dfua Return whether the keyguard is secured by a PIN, pattern or password or a SIM card is currently locked.
  43. Android Key Store KeyStoreWrapper class #dfua private val keyStore: KeyStore

    = createAndroidKeyStore() private fun createAndroidKeyStore(): KeyStore { val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(null) return keyStore }
  44. Android Key Store KeyStoreWrapper class #dfua private val keyStore: KeyStore

    = createAndroidKeyStore() private fun createAndroidKeyStore(): KeyStore { val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(null) return keyStore } Use simple factory method to get a KeyStore instance
  45. Android Key Store KeyStoreWrapper class #dfua private val keyStore: KeyStore

    = createAndroidKeyStore() private fun createAndroidKeyStore(): KeyStore { val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(null) return keyStore } With specific Provider implementation
  46. Android Key Store KeyStoreWrapper class #dfua private val keyStore: KeyStore

    = createAndroidKeyStore() private fun createAndroidKeyStore(): KeyStore { val keyStore = KeyStore.getInstance("AndroidKeyStore") keyStore.load(null) return keyStore } And finally create new Keystore
  47. Create Asymmetric Key KeyStoreWrapper class, createAndroidKeyStoreAsymmetricKey method #dfua val generator

    = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair()
  48. Create Asymmetric Key KeyStoreWrapper class, createAndroidKeyStoreAsymmetricKey method #dfua val generator

    = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair() Factory method to get Key Pair Generator instance
  49. Create Asymmetric Key KeyStoreWrapper class, createAndroidKeyStoreAsymmetricKey method #dfua val generator

    = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair() Where we need to specify the Algorithm we want
  50. Create Asymmetric Key KeyStoreWrapper class, createAndroidKeyStoreAsymmetricKey method #dfua val generator

    = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair() val generator = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair() And implementation Provider
  51. Create Asymmetric Key KeyStoreWrapper class, createAndroidKeyStoreAsymmetricKey method #dfua val generator

    = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair()
  52. Create Asymmetric Key KeyStoreWrapper class, createAndroidKeyStoreAsymmetricKey method #dfua val generator

    = KeyPairGenerator.getInstance( “RSA”, "AndroidKeyStore") // Initialize KeyPairGenerator // KeyPairGeneratorSpec - deprecated,available from 18 API // KeyGenParameterSpec - available from 23 + API return generator.generateKeyPair() Generate a Key Pair with initialized Specification
  53. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyPairGeneratorSpec method #dfua val builder

    = KeyPairGeneratorSpec.Builder(context) .setAlias(alias) .setSerialNumber(BigInteger.ONE) .setSubject(X500Principal("CN=${alias} CA Certificate")) .setStartDate(startDate.time) .setEndDate(endDate.time) generator.initialize(builder.build())
  54. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyPairGeneratorSpec method #dfua val builder

    = KeyPairGeneratorSpec.Builder(context) .setAlias(alias) .setSerialNumber(BigInteger.ONE) .setSubject(X500Principal("CN=${alias} CA Certificate")) .setStartDate(startDate.time) .setEndDate(endDate.time) generator.initialize(builder.build()) Builder to get Key Pair Generator Spec instance, deprecated in API 23
  55. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyPairGeneratorSpec method #dfua val builder

    = KeyPairGeneratorSpec.Builder(context) .setAlias(alias) .setSerialNumber(BigInteger.ONE) .setSubject(X500Principal("CN=${alias} CA Certificate")) .setStartDate(startDate.time) .setEndDate(endDate.time) generator.initialize(builder.build()) String, unique, identifier of the Key. Saving another key with the same alias will overwrite the first one.
  56. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyPairGeneratorSpec method #dfua val builder

    = KeyPairGeneratorSpec.Builder(context) .setAlias(alias) .setSerialNumber(BigInteger.ONE) .setSubject(X500Principal("CN=${alias} CA Certificate")) .setStartDate(startDate.time) .setEndDate(endDate.time) generator.initialize(builder.build())
  57. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyPairGeneratorSpec method #dfua val builder

    = KeyPairGeneratorSpec.Builder(context) .setAlias(alias) .setSerialNumber(BigInteger.ONE) .setSubject(X500Principal("CN=${alias} CA Certificate")) .setStartDate(startDate.time) .setEndDate(endDate.time) generator.initialize(builder.build()) Initialize Key Pair Generator with created Specification
  58. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyGenParameterSpec method #dfua val builder

    = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_ECB) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) generator.initialize(builder.build())
  59. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyGenParameterSpec method #dfua val builder

    = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_ECB) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) generator.initialize(builder.build()) Builder to get Key Gen Parameter Spec instance, added in API 23. Used for asymmetric and symmetric keys
  60. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyGenParameterSpec method #dfua val builder

    = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_ECB) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) generator.initialize(builder.build()) Purpose of Key usage must be specified
  61. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyGenParameterSpec method #dfua val builder

    = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_ECB) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) generator.initialize(builder.build()) As well as Cipher Block Mode
  62. Create Asymmetric Key KeyStoreWrapper class, initGeneratorWithKeyGenParameterSpec method #dfua val builder

    = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_ECB) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) generator.initialize(builder.build()) val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_ECB) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) generator.initialize(builder.build()) And Cipher Encryption Paddings
  63. Create Asymmetric Key KeyStoreWrapper class, Initialize KeyPairGenerator #dfua if (SystemServices.hasMarshmallow())

    { initGeneratorWithKeyGenParameterSpec(generator, alias) } else { initGeneratorWithKeyPairGeneratorSpec(generator, alias) }
  64. Get Key KeyStoreWrapper class, getAndroidKeyStoreAsymmetricKeyPair method #dfua val privateKey =

    keyStore.getKey(alias, null) as PrivateKey? val publicKey = keyStore.getCertificate(alias)?.publicKey return if (privateKey != null && publicKey != null) { KeyPair(publicKey, privateKey) } else { null }
  65. Get Key KeyStoreWrapper class, getAndroidKeyStoreAsymmetricKeyPair method #dfua val privateKey =

    keyStore.getKey(alias, null) as PrivateKey? val publicKey = keyStore.getCertificate(alias)?.publicKey return if (privateKey != null && publicKey != null) { KeyPair(publicKey, privateKey) } else { null } Get a key by alias
  66. Get Key KeyStoreWrapper class, getAndroidKeyStoreAsymmetricKeyPair method #dfua val privateKey =

    keyStore.getKey(alias, null) as PrivateKey? val publicKey = keyStore.getCertificate(alias)?.publicKey return if (privateKey != null && publicKey != null) { KeyPair(publicKey, privateKey) } else { null } Get a certificate by alias
  67. Get Key KeyStoreWrapper class, getAndroidKeyStoreAsymmetricKeyPair method #dfua val privateKey =

    keyStore.getKey(alias, null) as PrivateKey? val publicKey = keyStore.getCertificate(alias)?.publicKey return if (privateKey != null && publicKey != null) { KeyPair(publicKey, privateKey) } else { null } Get a certificate by alias
  68. Encrypt data with Cipher CipherWrapper class #dfua var TRANSFORMATION_ASYMMETRIC =

    "RSA/ECB/PKCS1Padding" val cipher: Cipher = Cipher.getInstance(transformation) fun encrypt(data: String, key: Key?): String { cipher.init(Cipher.ENCRYPT_MODE, key) val bytes = cipher.doFinal(data.toByteArray()) return Base64.encodeToString(bytes, Base64.DEFAULT) }
  69. Encrypt data with Cipher CipherWrapper class #dfua var TRANSFORMATION_ASYMMETRIC =

    "RSA/ECB/PKCS1Padding" val cipher: Cipher = Cipher.getInstance(transformation) fun encrypt(data: String, key: Key?): String { cipher.init(Cipher.ENCRYPT_MODE, key) val bytes = cipher.doFinal(data.toByteArray()) return Base64.encodeToString(bytes, Base64.DEFAULT) } Factory method to get Cipher instance for given transformation
  70. Encrypt data with Cipher CipherWrapper class #dfua var TRANSFORMATION_ASYMMETRIC =

    "RSA/ECB/PKCS1Padding" val cipher: Cipher = Cipher.getInstance(transformation) fun encrypt(data: String, key: Key?): String { cipher.init(Cipher.ENCRYPT_MODE, key) val bytes = cipher.doFinal(data.toByteArray()) return Base64.encodeToString(bytes, Base64.DEFAULT) } Initialize Cipher for encryption
  71. Encrypt data with Cipher CipherWrapper class #dfua var TRANSFORMATION_ASYMMETRIC =

    "RSA/ECB/PKCS1Padding" val cipher: Cipher = Cipher.getInstance(transformation) fun encrypt(data: String, key: Key?): String { cipher.init(Cipher.ENCRYPT_MODE, key) val bytes = cipher.doFinal(data.toByteArray()) return Base64.encodeToString(bytes, Base64.DEFAULT) } Make actual encryption of byte array
  72. Encrypt data with Cipher CipherWrapper class #dfua var TRANSFORMATION_ASYMMETRIC =

    "RSA/ECB/PKCS1Padding" val cipher: Cipher = Cipher.getInstance(transformation) fun encrypt(data: String, key: Key?): String { cipher.init(Cipher.ENCRYPT_MODE, key) val bytes = cipher.doFinal(data.toByteArray()) return Base64.encodeToString(bytes, Base64.DEFAULT) } Convert encrypted bytes to text
  73. Decrypt data with Cipher CipherWrapper class #dfua fun decrypt(data: String,

    key: Key?): String { cipher.init(Cipher.DECRYPT_MODE, key) val encryptedData = Base64.decode(data, Base64.DEFAULT) val decodedData = cipher.doFinal(encryptedData) return String(decodedData) }
  74. Decrypt data with Cipher CipherWrapper class #dfua fun decrypt(data: String,

    key: Key?): String { cipher.init(Cipher.DECRYPT_MODE, key) val encryptedData = Base64.decode(data, Base64.DEFAULT) val decodedData = cipher.doFinal(encryptedData) return String(decodedData) } Initialize Cipher for decryption
  75. Decrypt data with Cipher CipherWrapper class #dfua fun decrypt(data: String,

    key: Key?): String { cipher.init(Cipher.DECRYPT_MODE, key) val encryptedData = Base64.decode(data, Base64.DEFAULT) val decodedData = cipher.doFinal(encryptedData) return String(decodedData) } Decode encrypted text to the byte array
  76. Decrypt data with Cipher CipherWrapper class #dfua fun decrypt(data: String,

    key: Key?): String { cipher.init(Cipher.DECRYPT_MODE, key) val encryptedData = Base64.decode(data, Base64.DEFAULT) val decodedData = cipher.doFinal(encryptedData) return String(decodedData) } Make actual decryption of byte array
  77. Decrypt data with Cipher CipherWrapper class #dfua fun decrypt(data: String,

    key: Key?): String { cipher.init(Cipher.DECRYPT_MODE, key) val encryptedData = Base64.decode(data, Base64.DEFAULT) val decodedData = cipher.doFinal(encryptedData) return String(decodedData) } Convert decrypted bytes to text
  78. Master Key EncryptionServices class #dfua private val keyStoreWrapper = KeyStoreWrapper(context)

    fun createMasterKey(keyPassword: String? = null) { keyStoreWrapper.createAndroidKeyStoreAsymmetricKey( MASTER_KEY) } fun removeMasterKey() { keyStoreWrapper.removeAndroidKeyStoreKey(MASTER_KEY) }
  79. Protect Data EncryptionServices class, encrypt and decrypt methods #dfua val

    masterKey = keyStoreWrapper .getAndroidKeyStoreAsymmetricKeyPair(MASTER_KEY) CipherWrapper(CipherWrapper.TRANSFORMATION_ASYMMETRIC) .encrypt(data, masterKey?.public) CipherWrapper(CipherWrapper.TRANSFORMATION_ASYMMETRIC) .decrypt(data, masterKey?.private)
  80. Encrypt Large Data RSA keys was desired to work with

    small amount of data Valid message length depends on the key size The bigger key is, the bigger message can be encrypted Separate data and encrypt it part by part Use symmetric key to encrypt data and encrypt it with RSA key #dfua
  81. Create Symmetric Key with Default Provider KeyStoreWrapper class #dfua fun

    generateDefaultSymmetricKey(): SecretKey { val keyGenerator = KeyGenerator.getInstance("AES") return keyGenerator.generateKey() }
  82. Create Symmetric Key with Default Provider KeyStoreWrapper class #dfua fun

    generateDefaultSymmetricKey(): SecretKey { val keyGenerator = KeyGenerator.getInstance("AES") return keyGenerator.generateKey() } Factory method to get Key Generator instance with given Algorithm
  83. Create Symmetric Key with Default Provider KeyStoreWrapper class #dfua fun

    generateDefaultSymmetricKey(): SecretKey { val keyGenerator = KeyGenerator.getInstance("AES") return keyGenerator.generateKey() } Generate a Secret Key Instance
  84. Create Symmetric Key with Android Provider KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method

    #dfua val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_PKCS7) keyGenerator.init(builder.build()) return keyGenerator.generateKey()
  85. Create Symmetric Key with Android Provider KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method

    #dfua val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_PKCS7) keyGenerator.init(builder.build()) return keyGenerator.generateKey() Factory method to get Key Generator instance with given Algorithm and Provider
  86. Create Symmetric Key with Android Provider KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method

    #dfua val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_PKCS7) keyGenerator.init(builder.build()) return keyGenerator.generateKey() There is new Key Properties class in API 23, that contains various helpful constants.
  87. Create Symmetric Key with Android Provider KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method

    #dfua val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_PKCS7) keyGenerator.init(builder.build()) return keyGenerator.generateKey()
  88. Create Symmetric Key with Android Provider KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method

    #dfua val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val builder = KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) builder.setBlockModes(KeyProperties.BLOCK_MODE_CBC) builder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_PKCS7) keyGenerator.init(builder.build()) return keyGenerator.generateKey()
  89. Wrap Key with Cipher CipherWrapper class #dfua fun wrapKey( keyToBeWrapped:

    Key, keyToWrapWith: Key?): String { cipher.init(Cipher.WRAP_MODE, keyToWrapWith) val decodedData = cipher.wrap(keyToBeWrapped) return Base64.encodeToString(decodedData, Base64.DEFAULT) }
  90. Wrap Key with Cipher CipherWrapper class #dfua fun wrapKey( keyToBeWrapped:

    Key, keyToWrapWith: Key?): String { cipher.init(Cipher.WRAP_MODE, keyToWrapWith) val decodedData = cipher.wrap(keyToBeWrapped) return Base64.encodeToString(decodedData, Base64.DEFAULT) } Initialize Cipher for key wrapping
  91. Wrap Key with Cipher CipherWrapper class #dfua fun wrapKey( keyToBeWrapped:

    Key, keyToWrapWith: Key?): String { cipher.init(Cipher.WRAP_MODE, keyToWrapWith) val decodedData = cipher.wrap(keyToBeWrapped) return Base64.encodeToString(decodedData, Base64.DEFAULT) } Wrap key with another key
  92. Unwrap Key with Cipher CipherWrapper class #dfua fun unWrapKey( wrappedKeyData:

    String, algorithm: String, wrappedKeyType: Int,keyToUnWrapWith: Key?): Key { val data = Base64.decode(wrappedKeyData, Base64.DEFAULT) cipher.init(Cipher.UNWRAP_MODE, keyToUnWrapWith) return cipher.unwrap(data, algorithm, wrappedKeyType) }
  93. Unwrap Key with Cipher CipherWrapper class #dfua fun unWrapKey( wrappedKeyData:

    String, algorithm: String, wrappedKeyType: Int,keyToUnWrapWith: Key?): Key { val data = Base64.decode(wrappedKeyData, Base64.DEFAULT) cipher.init(Cipher.UNWRAP_MODE, keyToUnWrapWith) return cipher.unwrap(data, algorithm, wrappedKeyType) } Initialize Cipher for key unwrapping
  94. Unwrap Key with Cipher CipherWrapper class #dfua fun unWrapKey( wrappedKeyData:

    String, algorithm: String, wrappedKeyType: Int,keyToUnWrapWith: Key?): Key { val data = Base64.decode(wrappedKeyData, Base64.DEFAULT) cipher.init(Cipher.UNWRAP_MODE, keyToUnWrapWith) return cipher.unwrap(data, algorithm, wrappedKeyType) } For unwrapping we need to explicitly specify algorithm that encrypted key was created with
  95. Master Key For Different APIs EncryptionServices class, createMasterKey method #dfua

    if (SystemServices.hasMarshmallow()) { createAndroidSymmetricKey() } else { createDefaultSymmetricKey() }
  96. Master Key For Different APIs EncryptionServices class #dfua private fun

    createAndroidSymmetricKey() { keyStoreWrapper.createAndroidKeyStoreSymmetricKey( MASTER_KEY) }
  97. Master Key For Different APIs EncryptionServices class, createDefaultSymmetricKey method #dfua

    val key = keyStoreWrapper.generateDefaultSymmetricKey() val masterKey = keyStoreWrapper. createAndroidKeyStoreAsymmetricKey(MASTER_KEY) val encryptedSymmetricKey = CipherWrapper(CipherWrapper.TRANSFORMATION_ASYMMETRIC) .wrapKey(key, masterKey.public) storage.saveEncryptionKey(encryptedSymmetricKey)
  98. Protect Data For Different APIs EncryptionServices class, encrypt and decrypt

    methods #dfua if (SystemServices.hasMarshmallow()) { encryptWithAndroidSymmetricKey(data) decryptWithAndroidSymmetricKey(data) } else { encryptWithDefaultSymmetricKey(data) decryptWithDefaultSymmetricKey(data) }
  99. Protect Data For Different APIs EncryptionServices class, symmetric encrypt and

    decrypt methods #dfua val masterKey = keyStoreWrapper .getAndroidKeyStoreSymmetricKey(MASTER_KEY) CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .encrypt(data, masterKey) CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .decrypt(data, masterKey)
  100. Protect Data For Different APIs EncryptionServices class, encryptWithDefaultSymmetricKey method #dfua

    val masterKey = keyStoreWrapper .getAndroidKeyStoreAsymmetricKeyPair(MASTER_KEY) val encryptionKey = storage.getEncryptionKey() val symmetricKey = ... // Unwrap Key return CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .encrypt(data, symmetricKey)
  101. Protect Data For Different APIs EncryptionServices class, decryptWithDefaultSymmetricKey method #dfua

    val masterKey = keyStoreWrapper .getAndroidKeyStoreAsymmetricKeyPair(MASTER_KEY) val encryptionKey = storage.getEncryptionKey() val symmetricKey = ... // Unwrap Key return CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .decrypt(data, symmetricKey)
  102. Protect Data For Different APIs EncryptionServices class, Unwrap Key #dfua

    val cipher = CipherWrapper( CipherWrapper.TRANSFORMATION_ASYMMETRIC) val symmetricKey = cipher.unWrapKey( encryptionKey, ALGORITHM_AES, Cipher.SECRET_KEY, masterKey?.private) as SecretKey
  103. Initialization Vector Is a fixed-size input to a cryptographic primitive

    Is typically required to be random or pseudorandom Randomization is crucial to achieve semantic security The point of an IV is to tolerate the use of the same key to encrypt several distinct messages. #dfua
  104. Encryption with Initialization Vector CipherWrapper class, encrypt method #dfua cipher.init(Cipher.ENCRYPT_MODE,

    key) var result = "" if (useInitializationVector) { val iv = cipher.iv val ivString = Base64.encodeToString(iv, Base64.DEFAULT) result = ivString + IV_SEPARATOR } val bytes = cipher.doFinal(data.toByteArray()) result += Base64.encodeToString(bytes, Base64.DEFAULT) return result
  105. Encryption with Initialization Vector CipherWrapper class, encrypt method #dfua cipher.init(Cipher.ENCRYPT_MODE,

    key) var result = "" if (useInitializationVector) { val iv = cipher.iv val ivString = Base64.encodeToString(iv, Base64.DEFAULT) result = ivString + IV_SEPARATOR } val bytes = cipher.doFinal(data.toByteArray()) result += Base64.encodeToString(bytes, Base64.DEFAULT) return result Automatically Generated Initialization Vector
  106. Encryption with Initialization Vector CipherWrapper class, encrypt method #dfua cipher.init(Cipher.ENCRYPT_MODE,

    key) var result = "" if (useInitializationVector) { val iv = cipher.iv val ivString = Base64.encodeToString(iv, Base64.DEFAULT) result = ivString + IV_SEPARATOR } val bytes = cipher.doFinal(data.toByteArray()) result += Base64.encodeToString(bytes, Base64.DEFAULT) return result We will add as prefix to encryption result, for later usage
  107. Encryption with Initialization Vector CipherWrapper class, encrypt method #dfua cipher.init(Cipher.ENCRYPT_MODE,

    key) var result = "" if (useInitializationVector) { val iv = cipher.iv val ivString = Base64.encodeToString(iv, Base64.DEFAULT) result = ivString + IV_SEPARATOR } val bytes = cipher.doFinal(data.toByteArray()) result += Base64.encodeToString(bytes, Base64.DEFAULT) return result Add encrypted string as a postfix to the result
  108. Decryption with Initialization Vector CipherWrapper class, decrypt method #dfua var

    encodedString: String if (useInitializationVector) { // Parse Initialization Vector and init Cipher } else{ encodedString = data cipher.init(Cipher.DECRYPT_MODE, key) } val encrData = Base64.decode(encodedString,Base64.DEFAULT) val decodedData = cipher.doFinal(encrData) return String(decodedData)
  109. Decryption with Initialization Vector CipherWrapper class, Parse Initialization Vector and

    init Cipher #dfua val split = data.split(IV_SEPARATOR.toRegex()) if (split.size != 2) throw IllegalArgumentException("Passed data is incorrect. There was no IV specified with it.") val ivString = split[0] encodedString = split[1] val ivSpec = IvParameterSpec(Base64.decode(ivString, Base64.DEFAULT)) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)
  110. Decryption with Initialization Vector CipherWrapper class, Parse Initialization Vector and

    init Cipher #dfua val split = data.split(IV_SEPARATOR.toRegex()) if (split.size != 2) throw IllegalArgumentException("Passed data is incorrect. There was no IV specified with it.") val ivString = split[0] encodedString = split[1] val ivSpec = IvParameterSpec(Base64.decode(ivString, Base64.DEFAULT)) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec) Split encrypted data by our predefined Initialization Vector separator
  111. Decryption with Initialization Vector CipherWrapper class, Parse Initialization Vector and

    init Cipher #dfua val split = data.split(IV_SEPARATOR.toRegex()) if (split.size != 2) throw IllegalArgumentException("Passed data is incorrect. There was no IV specified with it.") val ivString = split[0] encodedString = split[1] val ivSpec = IvParameterSpec(Base64.decode(ivString, Base64.DEFAULT)) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec) Get Initialization vector
  112. Decryption with Initialization Vector CipherWrapper class, Parse Initialization Vector and

    init Cipher #dfua val split = data.split(IV_SEPARATOR.toRegex()) if (split.size != 2) throw IllegalArgumentException("Passed data is incorrect. There was no IV specified with it.") val ivString = split[0] encodedString = split[1] val ivSpec = IvParameterSpec(Base64.decode(ivString, Base64.DEFAULT)) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec) Get encrypted text
  113. Decryption with Initialization Vector CipherWrapper class, Parse Initialization Vector and

    init Cipher #dfua val split = data.split(IV_SEPARATOR.toRegex()) if (split.size != 2) throw IllegalArgumentException("Passed data is incorrect. There was no IV specified with it.") val ivString = split[0] encodedString = split[1] val ivSpec = IvParameterSpec(Base64.decode(ivString, Base64.DEFAULT)) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec) Create Initialization Vector Parameter Specification
  114. Decryption with Initialization Vector CipherWrapper class, Parse Initialization Vector and

    init Cipher #dfua val split = data.split(IV_SEPARATOR.toRegex()) if (split.size != 2) throw IllegalArgumentException("Passed data is incorrect. There was no IV specified with it.") val ivString = split[0] encodedString = split[1] val ivSpec = IvParameterSpec(Base64.decode(ivString, Base64.DEFAULT)) cipher.init(Cipher.DECRYPT_MODE, key, ivSpec) And initialize cipher for decryption mode with it
  115. Protect Data with Initialization Vector EncryptionServices class, all methods where

    symmetric key is used #dfua return CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .encrypt(data, masterKey, true) return CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .decrypt(data, masterKey, true)
  116. Key Invalidation Issue KeyPairGeneratorSpec.setEncryptionRequired() “This will protect the key pair

    with the secure lock screen credential (e.g., password, PIN, or pattern). Note that this feature requires that the secure lock screen (e.g., password, PIN, pattern) is set up, otherwise key pair generation will fail. Moreover, this key pair will be deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device Administrator).” #dfua
  117. The issue is very simple to reproduce, on pre API

    23, keys will be removed even if setEncryptionRequired is not set. Change Lock Screen type and all of AndroidKeyStore keys will gone. #dfua
  118. What to do ? Android Key Store may be used

    safely on M devices and later Before M, reload data when keys are invalidated Do not use Android Key Store for local only content Instead prefer to use default java Provider (or other) #dfua
  119. Default Keystore KeyStoreWrapper class, createDefaultKeyStore method #dfua val defaultKeyStoreFile =

    File( context.filesDir, defaultKeyStoreName) val store = KeyStore.getInstance(KeyStore.getDefaultType()) if (!defaultKeyStoreFile.exists()) { store.load(null) } else { store.load(FileInputStream(defaultKeyStoreFile), null) } return store
  120. Default Keystore KeyStoreWrapper class, createDefaultKeyStore method #dfua val defaultKeyStoreFile =

    File( context.filesDir, defaultKeyStoreName) val store = KeyStore.getInstance(KeyStore.getDefaultType()) if (!defaultKeyStoreFile.exists()) { store.load(null) } else { store.load(FileInputStream(defaultKeyStoreFile), null) } return store Create a file for the key store
  121. Default Keystore KeyStoreWrapper class, createDefaultKeyStore method #dfua val defaultKeyStoreFile =

    File( context.filesDir, defaultKeyStoreName) val store = KeyStore.getInstance(KeyStore.getDefaultType()) if (!defaultKeyStoreFile.exists()) { store.load(null) } else { store.load(FileInputStream(defaultKeyStoreFile), null) } return store Create keystore instance with default java provider
  122. Default Keystore KeyStoreWrapper class, createDefaultKeyStore method #dfua val defaultKeyStoreFile =

    File( context.filesDir, defaultKeyStoreName) val store = KeyStore.getInstance(KeyStore.getDefaultType()) if (!defaultKeyStoreFile.exists()) { store.load(null) } else { store.load(FileInputStream(defaultKeyStoreFile), null) } return store Initialize empty keystore if file not exists yet
  123. Default Keystore KeyStoreWrapper class, createDefaultKeyStore method #dfua val defaultKeyStoreFile =

    File( context.filesDir, defaultKeyStoreName) val store = KeyStore.getInstance(KeyStore.getDefaultType()) if (!defaultKeyStoreFile.exists()) { store.load(null) } else { store.load(FileInputStream(defaultKeyStoreFile), null) } return store Load keystore from file otherwise
  124. Save Symmetric Key in Default Keystore KeyStoreWrapper class, createDefaultKeyStoreSymmetricKey method

    #dfua val key = generateDefaultSymmetricKey() val keyEntry = KeyStore.SecretKeyEntry(key) defaultKeyStore.setEntry(alias, keyEntry, KeyStore.PasswordProtection(password.toCharArray())) defaultKeyStore.store(FileOutputStream(defaultKeyStoreFile), password.toCharArray())
  125. Save Symmetric Key in Default Keystore KeyStoreWrapper class, createDefaultKeyStoreSymmetricKey method

    #dfua val key = generateDefaultSymmetricKey() val keyEntry = KeyStore.SecretKeyEntry(key) defaultKeyStore.setEntry(alias, keyEntry, KeyStore.PasswordProtection(password.toCharArray())) defaultKeyStore.store(FileOutputStream(defaultKeyStoreFile), password.toCharArray()) Generate default symmetric key, as we already did at level 2
  126. Save Symmetric Key in Default Keystore KeyStoreWrapper class, createDefaultKeyStoreSymmetricKey method

    #dfua val key = generateDefaultSymmetricKey() val keyEntry = KeyStore.SecretKeyEntry(key) defaultKeyStore.setEntry(alias, keyEntry, KeyStore.PasswordProtection(password.toCharArray())) defaultKeyStore.store(FileOutputStream(defaultKeyStoreFile), password.toCharArray()) Create a Secret Entry for this key
  127. Save Symmetric Key in Default Keystore KeyStoreWrapper class, createDefaultKeyStoreSymmetricKey method

    #dfua val key = generateDefaultSymmetricKey() val keyEntry = KeyStore.SecretKeyEntry(key) defaultKeyStore.setEntry(alias, keyEntry, KeyStore.PasswordProtection(password.toCharArray())) defaultKeyStore.store(FileOutputStream(defaultKeyStoreFile), password.toCharArray()) Set this entry to keystore, with alias and password
  128. Save Symmetric Key in Default Keystore KeyStoreWrapper class, createDefaultKeyStoreSymmetricKey method

    #dfua val key = generateDefaultSymmetricKey() val keyEntry = KeyStore.SecretKeyEntry(key) defaultKeyStore.setEntry(alias, keyEntry, KeyStore.PasswordProtection(password.toCharArray())) defaultKeyStore.store(FileOutputStream(defaultKeyStoreFile), password.toCharArray()) And finally update the file with keystore entries
  129. Save Symmetric Key in Default Keystore KeyStoreWrapper class #dfua fun

    getDefaultKeyStoreSymmetricKey(alias: String, keyPassword: String): SecretKey? { return try { defaultKeyStore.getKey(alias, keyPassword.toCharArray()) as SecretKey } catch (e: UnrecoverableKeyException) { null } }
  130. Save Symmetric Key in Default Keystore KeyStoreWrapper class #dfua fun

    getDefaultKeyStoreSymmetricKey(alias: String, keyPassword: String): SecretKey? { return try { defaultKeyStore.getKey(alias, keyPassword.toCharArray()) as SecretKey } catch (e: UnrecoverableKeyException) { null } } We need to provide password to get a key
  131. Save Symmetric Key in Default Keystore KeyStoreWrapper class #dfua fun

    getDefaultKeyStoreSymmetricKey(alias: String, keyPassword: String): SecretKey? { return try { defaultKeyStore.getKey(alias, keyPassword.toCharArray()) as SecretKey } catch (e: UnrecoverableKeyException) { null } } Exception will be thrown if key with given alias and password doesn’t exist in keystore
  132. Protect Data and Compatibility Issues EncryptionServices class #dfua private fun

    createDefaultSymmetricKey(password: String) { keyStoreWrapper.createDefaultKeyStoreSymmetricKey( MASTER_KEY, password) }
  133. Protect Data and Compatibility Issues EncryptionServices class, encryption and decryption

    on pre M #dfua val masterKey = keyStoreWrapper .getDefaultKeyStoreSymmetricKey(MASTER_KEY, keyPassword) return CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .encrypt(data, masterKey, true) return masterKey?.let { CipherWrapper(CipherWrapper.TRANSFORMATION_SYMMETRIC) .decrypt(data, masterKey, true) } ?: ""
  134. Fingerprint In most cases it is used as optional authentication

    Tied to AndroidKeyStore and requires to create Fingerprint Key Keys gets invalidated when fingerprint is added or removed On AVDs keys may be never invalidated (API 24) This is also valid for devices (Samsung s6) #dfua
  135. val fingerprintManager = context.getSystemService( Context.FINGERPRINT_SERVICE) as FingerprintManager fun isFingerprintHardwareAvailable(): Boolean

    = fingerprintManager?.isHardwareDetected ?: false fun hasEnrolledFingerprints(): Boolean = fingerprintManager?.hasEnrolledFingerprints() ?: false Fingerprint Manager SystemServices class #dfua
  136. val fingerprintManager = context.getSystemService( Context.FINGERPRINT_SERVICE) as FingerprintManager fun isFingerprintHardwareAvailable(): Boolean

    = fingerprintManager?.isHardwareDetected ?: false fun hasEnrolledFingerprints(): Boolean = fingerprintManager?.hasEnrolledFingerprints() ?: false Fingerprint Manager SystemServices class #dfua System service that is responsible for fingerprint. Available from API 23. There is FingerprintManagerCompat in support library, that behaves like there is no fingerprint hardware, on devices running below 23 API (not using it as it is not working with AVD 23 API and on AVD 24+ API keys are not invalidating)
  137. val fingerprintManager = context.getSystemService( Context.FINGERPRINT_SERVICE) as FingerprintManager fun isFingerprintHardwareAvailable(): Boolean

    = fingerprintManager?.isHardwareDetected ?: false fun hasEnrolledFingerprints(): Boolean = fingerprintManager?.hasEnrolledFingerprints() ?: false Fingerprint Manager SystemServices class #dfua Check if there is fingerprint hardware on device
  138. val fingerprintManager = context.getSystemService( Context.FINGERPRINT_SERVICE) as FingerprintManager fun isFingerprintHardwareAvailable(): Boolean

    = fingerprintManager?.isHardwareDetected ?: false fun hasEnrolledFingerprints(): Boolean = fingerprintManager?.hasEnrolledFingerprints() ?: false Fingerprint Manager SystemServices class #dfua Returns true if there was at least one fingerprint added. Is not working properly after device reboot on AVD 23, returns false even if there were fingerprints added. Becomes to work properly after adding / removing fingerprint.
  139. fun authenticateFingerprint( cryptoObject: FingerprintManager.CryptoObject, cancellationSignal: CancellationSignal, flags: Int, callback: FingerprintManager.AuthenticationCallback,

    handler: Handler?) { fingerprintManager?.authenticate( cryptoObject,cancellationSignal,flags,callback,handler) } Fingerprint Manager SystemServices class #dfua
  140. fun authenticateFingerprint( cryptoObject: FingerprintManager.CryptoObject, cancellationSignal: CancellationSignal, flags: Int, callback: FingerprintManager.AuthenticationCallback,

    handler: Handler?) { fingerprintManager?.authenticate( cryptoObject,cancellationSignal,flags,callback,handler) } Fingerprint Manager SystemServices class #dfua Holder for Cipher, that will be authenticated with fingerprint
  141. fun authenticateFingerprint( cryptoObject: FingerprintManager.CryptoObject, cancellationSignal: CancellationSignal, flags: Int, callback: FingerprintManager.AuthenticationCallback,

    handler: Handler?) { fingerprintManager?.authenticate( cryptoObject,cancellationSignal,flags,callback,handler) } Fingerprint Manager SystemServices class #dfua Used to cancel authentication manually
  142. fun authenticateFingerprint( cryptoObject: FingerprintManager.CryptoObject, cancellationSignal: CancellationSignal, flags: Int, callback: FingerprintManager.AuthenticationCallback,

    handler: Handler?) { fingerprintManager?.authenticate( cryptoObject,cancellationSignal,flags,callback,handler) } Fingerprint Manager SystemServices class #dfua From Docs: “optional flags; should be 0”
  143. fun authenticateFingerprint( cryptoObject: FingerprintManager.CryptoObject, cancellationSignal: CancellationSignal, flags: Int, callback: FingerprintManager.AuthenticationCallback,

    handler: Handler?) { fingerprintManager?.authenticate( cryptoObject,cancellationSignal,flags,callback,handler) } Fingerprint Manager SystemServices class #dfua Our main point of interest here, will be called during authentication
  144. fun authenticateFingerprint( cryptoObject: FingerprintManager.CryptoObject, cancellationSignal: CancellationSignal, flags: Int, callback: FingerprintManager.AuthenticationCallback,

    handler: Handler?) { fingerprintManager?.authenticate( cryptoObject,cancellationSignal,flags,callback,handler) } Fingerprint Manager SystemServices class #dfua Warms up the fingerprint hardware and starts scanning for a fingerprint
  145. fun onAuthenticationError(errMsgId: Int, err: CharSequence) fun onAuthenticationHelp(helpMsgId: Int, help: CharSequence)

    fun onAuthenticationFailed() fun onAuthenticationSucceeded(result: AuthenticationResult) Fingerprint AuthenticationCallback AuthenticationFingerprint class #dfua
  146. User Authentication Required KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method #dfua val builder:

    KeyGenParameterSpec.Builder = ... builder.setUserAuthenticationRequired(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder.setInvalidatedByBiometricEnrollment(true) }
  147. User Authentication Required KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method #dfua val builder:

    KeyGenParameterSpec.Builder = ... builder.setUserAuthenticationRequired(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder.setInvalidatedByBiometricEnrollment(true) } Requers created key to be authenticated with fingerprint
  148. User Authentication Required KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method #dfua val builder:

    KeyGenParameterSpec.Builder = ... builder.setUserAuthenticationRequired(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder.setInvalidatedByBiometricEnrollment(true) } Tells whenever to invalidate fingerprint keys
  149. Fingerprint Key EncryptionServices class #dfua if (SystemServices.hasMarshmallow()) { keyStoreWrapper.createAndroidKeyStoreSymmetricKey( FINGERPRINT_KEY,

    true, true) } if (SystemServices.hasMarshmallow()) { keyStoreWrapper.removeAndroidKeyStoreKey(FINGERPRINT_KEY) }
  150. Fingerprint Crypto Object EncryptionServices class, prepareFingerprintCryptoObject method #dfua try {

    val symmetricKey = keyStoreWrapper .getAndroidKeyStoreSymmetricKey(FINGERPRINT_KEY) val cipher = CipherWrapper( CipherWrapper.TRANSFORMATION_SYMMETRIC).cipher cipher.init(Cipher.ENCRYPT_MODE, symmetricKey) FingerprintManager.CryptoObject(cipher) }
  151. Fingerprint Crypto Object EncryptionServices class, prepareFingerprintCryptoObject method #dfua try {

    val symmetricKey = keyStoreWrapper .getAndroidKeyStoreSymmetricKey(FINGERPRINT_KEY) val cipher = CipherWrapper( CipherWrapper.TRANSFORMATION_SYMMETRIC).cipher cipher.init(Cipher.ENCRYPT_MODE, symmetricKey) FingerprintManager.CryptoObject(cipher) } Fingerprint keys doesn’t require to use Initialization Vector
  152. Fingerprint Crypto Object EncryptionServices class, prepareFingerprintCryptoObject method #dfua try {

    val symmetricKey = keyStoreWrapper .getAndroidKeyStoreSymmetricKey(FINGERPRINT_KEY) val cipher = CipherWrapper( CipherWrapper.TRANSFORMATION_SYMMETRIC).cipher cipher.init(Cipher.ENCRYPT_MODE, symmetricKey) FingerprintManager.CryptoObject(cipher) } Simple wrapper for Cipher that is passed to FingerprintManager
  153. Fingerprint Crypto Object EncryptionServices class, prepareFingerprintCryptoObject method #dfua catch (e:

    Throwable) { if (e is Key Permanently Invalidated Exception || e is IllegalBlockSizeException) { return null } else if (e is InvalidKeyException) { return null } throw e }
  154. Fingerprint Crypto Object EncryptionServices class, prepareFingerprintCryptoObject method #dfua catch (e:

    Throwable) { if (e is Key Permanently Invalidated Exception || e is IllegalBlockSizeException) { return null } else if (e is InvalidKeyException) { return null } throw e } Fingerprint Key was invalidated
  155. Fingerprint Crypto Object EncryptionServices class, prepareFingerprintCryptoObject method #dfua catch (e:

    Throwable) { if (e is Key Permanently Invalidated Exception || e is IllegalBlockSizeException) { return null } else if (e is InvalidKeyException) { return null } throw e } Fingerprint Key was not generated
  156. Validate Fingerprint Authentication EncryptionServices class, validateFingerprintAuthentication method #dfua try {

    cryptoObject.cipher.doFinal(KEY_VALIDATION_DATA) return true } catch (e: Throwable) { if (e is KeyPermanentlyInvalidatedException || e is IllegalBlockSizeException) { return false } throw e }
  157. Validate Fingerprint Authentication EncryptionServices class, validateFingerprintAuthentication method #dfua try {

    cryptoObject.cipher.doFinal(KEY_VALIDATION_DATA) return true } catch (e: Throwable) { if (e is KeyPermanentlyInvalidatedException || e is IllegalBlockSizeException) { return false } throw e } Run final authentication test
  158. Validate Fingerprint Authentication EncryptionServices class, validateFingerprintAuthentication method #dfua try {

    cryptoObject.cipher.doFinal(KEY_VALIDATION_DATA) return true } catch (e: Throwable) { if (e is KeyPermanentlyInvalidatedException || e is IllegalBlockSizeException) { return false } throw e } Will be thrown if key was invalidated after during authentication
  159. User Authentication Required KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method #dfua val builder:

    KeyGenParameterSpec.Builder = ... builder.setUserAuthenticationRequired(true) builder.setUserAuthenticationValidityDurationSeconds(delay) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder.setUserAuthenticationValidWhileOnBody(true) }
  160. User Authentication Required KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method #dfua val builder:

    KeyGenParameterSpec.Builder = ... builder.setUserAuthenticationRequired(true) builder.setUserAuthenticationValidityDurationSeconds(delay) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder.setUserAuthenticationValidWhileOnBody(true) } Marks this key to require confirm credentials validation
  161. User Authentication Required KeyStoreWrapper class, createAndroidKeyStoreSymmetricKey method #dfua val builder:

    KeyGenParameterSpec.Builder = ... builder.setUserAuthenticationRequired(true) builder.setUserAuthenticationValidityDurationSeconds(delay) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { builder.setUserAuthenticationValidWhileOnBody(true) } Sets whether the key will remain authorized only until the device is removed from the user's body
  162. Confirm Credentials Key EncryptionServices class #dfua if (SystemServices.hasMarshmallow()) { keyStoreWrapper.createAndroidKeyStoreSymmetricKey(

    CONFIRM_CREDENTIALS_KEY, userAuthenticationRequired = true, userAuthenticationValidityDurationSeconds = delay) } if (SystemServices.hasMarshmallow()) { keyStoreWrapper.removeAndroidKeyStoreKey( CONFIRM_CREDENTIALS_KEY) }
  163. Validate Confirm Credentials Authentication EncryptionServices class, validateConfirmCredentialsAuthentication method val symmetricKey

    = keyStoreWrapper .getAndroidKeyStoreSymmetricKey(CONFIRM_CREDENTIALS_KEY) val cipherWrapper = CipherWrapper( CipherWrapper.TRANSFORMATION_SYMMETRIC) #dfua
  164. Validate Confirm Credentials Authentication EncryptionServices class, validateConfirmCredentialsAuthentication method try {

    return if (symmetricKey != null) { cipherWrapper.encrypt( KEY_VALIDATION_DATA.toString(), symmetricKey) true } else false } #dfua
  165. Validate Confirm Credentials Authentication EncryptionServices class, validateConfirmCredentialsAuthentication method catch (e:

    Throwable) { if (e is UserNotAuthenticatedException || e is KeyPermanentlyInvalidatedException) { return false } else if (e is InvalidKeyException) { return false } throw e } #dfua
  166. Validate Confirm Credentials Authentication EncryptionServices class, validateConfirmCredentialsAuthentication method catch (e:

    Throwable) { if (e is UserNotAuthenticatedException || e is KeyPermanentlyInvalidatedException) { return false } else if (e is InvalidKeyException) { return false } throw e } #dfua User is not authenticated or the lock screen has been disabled or reset
  167. Validate Confirm Credentials Authentication EncryptionServices class, validateConfirmCredentialsAuthentication method catch (e:

    Throwable) { if (e is UserNotAuthenticatedException || e is KeyPermanentlyInvalidatedException) { return false } else if (e is InvalidKeyException) { return false } throw e } #dfua Confirm Credentials key was not generated
  168. Confirm Credentials Intent SystemServices class val keyguard = context.getSystemService( Context.KEYGUARD_SERVICE)

    as KeyguardManager val intent = keyguard.createConfirmDeviceCredentialIntent( title, description) if (intent != null) { activity.startActivityForResult(intent, requestCode) } #dfua
  169. Confirm Credentials Intent SystemServices class val keyguard = context.getSystemService( Context.KEYGUARD_SERVICE)

    as KeyguardManager val intent = keyguard.createConfirmDeviceCredentialIntent( title, description) if (intent != null) { activity.startActivityForResult(intent, requestCode) } #dfua Confirm Credentials is a part of KeyguardManager system service
  170. Confirm Credentials Intent SystemServices class val keyguard = context.getSystemService( Context.KEYGUARD_SERVICE)

    as KeyguardManager val intent = keyguard.createConfirmDeviceCredentialIntent( title, description) if (intent != null) { activity.startActivityForResult(intent, requestCode) } #dfua Creates intent for launching the activity or null if no password is required(no Lock Screen setup). It is available from API 21+ and can be used without cryptographic keys (but it will be not possible to specify user authentication validity duration seconds without it)
  171. Confirm Credentials Intent SystemServices class val keyguard = context.getSystemService( Context.KEYGUARD_SERVICE)

    as KeyguardManager val intent = keyguard.createConfirmDeviceCredentialIntent( title, description) if (intent != null) { activity.startActivityForResult(intent, requestCode) } #dfua You can customize the title and description. Or a generic one will be provided for you if you leave it empty
  172. Confirm Credentials Intent SystemServices class val keyguard = context.getSystemService( Context.KEYGUARD_SERVICE)

    as KeyguardManager val intent = keyguard.createConfirmDeviceCredentialIntent( title, description) if (intent != null) { activity.startActivityForResult(intent, requestCode) } #dfua Start activity with confirm credentials intent and wait for RESULT_OK
  173. Summary Android provides various of possibilities to secure data But

    not all of them works as designed to Do not use Android Key Store API on pre M devices Or use it if you not scared to lose data (can be reloaded) Choose the Key Algorithm that is best for your needs Remember that asymmetric Keys are not good for large data #dfua
  174. Summary Use Initialization Vectors and Salt value for better protection

    Choose hardware-backed keys when possible Fingerprint is not the main security option Always handle cases of key invalidation Remember that there is a fingerprint compatibility helper Use Confirm Credentials instead of custom screen locks #dfua
  175. Security is a complex unit. All of that will not

    work if application is running on corrupted environment. #dfua
  176. Resources JCA Documentation http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html Android Keystore Documentation http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/CryptoSpec.html Android Keystore

    Supported Algorithms http://developer.android.com/training/articles/keystore.html#SupportedAlgorithms Android Source https://source.android.com/security/keystore/ #dfua
  177. Resources Fingerprint & Confirm Credentials Authentication https://developer.android.com/about/versions/marshmallow/android-6.0.html Fingerprint Google Sample

    https://github.com/googlesamples/android-FingerprintDialog Confirm Credentials Google Sample https://github.com/googlesamples/android-ConfirmCredential Android Arsenal, Security and Fingerprint tags https://android-arsenal #dfua
  178. Resources Nikolay Elenkov, Book https://www.amazon.com/Android-Security-Internals-In-Depth-Architecture/dp/1593275811 Nikolay Elenkov, Blog http://nelenkov.blogspot.com/ Dorian

    Cussen, Blog https://doridori.github.io/android-security-the-forgetful-keystore/ Courses https://www.coursera.org/learn/crypto #dfua
  179. Thank You! Questions? Yakiv Mospan Android Developer @ Team Technologies

    Svyatoslav Hromyak Android Developer @ Team Technologies