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

Secure Android Applications

Secure Android Applications

Secure Android Applications - What a developer must care about
DevFest Budapest 2017

Tamas Balogh

October 10, 2017
Tweet

More Decks by Tamas Balogh

Other Decks in Programming

Transcript

  1. HTTP + Transport Layer Security TLS: Transport layer HTTP: Application

    layer What about GET params? • Encrypted, but logged on the server! HTTPS Network Security http://nhprice.com/what-is-ios-model- the-overall-explanation-of-ios-7- layers.html
  2. Latest version: TLS 1.2 On Android - Fragmented Supported vs

    Enabled Transport Layer security Network Security https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
  3. class ForceTlsSocketFactory @Throws(KeyManagementException::class, NoSuchAlgorithmException::class) constructor(val internalSSLSocketFactory: SSLSocketFactory) : SSLSocketFactory() {

    @Throws(IOException::class) override fun createSocket(): Socket { return enableTLSOnSocket(internalSSLSocketFactory.createSocket()) } //... private fun enableTLSOnSocket(socket: Socket?): Socket { if (socket != null && socket is SSLSocket) { socket.enabledProtocols = arrayOf("TLSv1.1", "TLSv1.2") } return socket!! } } Force TLS 1.2 Network Security
  4. val builder = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) // For below API 16 use

    TLS 1.0 if (FORCE_TLS_1_2) { if (Build.VERSION.SDK_INT >= 16) { builder.tlsVersions(TlsVersion.TLS_1_2) } } if (Build.VERSION.SDK_INT >= 20) { builder.tlsVersions(TlsVersion.TLS_1_2) } val client = OkHttpClient.Builder() .connectionSpecs(listOf(builder.build())) .build() Usage with OkHttp 3 Network Security
  5. TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS - Defines TLS/SSL ECDHE – Key agreement protocol

    RSA – Authentication protocol AES_256_GCM – Block cipher/Key size/Block mode SHA384 – Message authentication function Cipher Suits Network Security
  6. //Not secure enough, but compatible - OkHttp Docs: The following

    ciphers are on the HTTP/2's bad cipher suites list if (Build.VERSION.SDK_INT >= API_LEVEL_11) { builder.cipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) } //Secure - Chrome 51 supports if (Build.VERSION.SDK_INT >= API_LEVEL_20) { builder.cipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) } //Secure - Chrome 51 supports if (Build.VERSION.SDK_INT >= API_LEVEL_24) { builder.cipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) } Cipher Suits Network Security
  7. The server must also support the TLS versions and the

    cipher suits. Check it with OpenSSL nmap -sV --script ssl-enum-ciphers -p 443 hostname Cipher Suits Network Security
  8. Asymmetric crypto - Protection again Man-in-the-middle attacks Technically the public

    part of the server key e.q RSA (1) CA Certified certificate • CA is responsible for that • CA holds the cert and validates it (2) Self-signed certificate • Created by the server administrator • By default leads to an exception HTTPS - Authentication Network Security
  9. To make sure we communicate with the right party Include

    the certificate into the app, and validate the server using it To get that certificate echo | openssl s_client -connect hostname:443 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p’ > hostname.pem Android handles BKS-V1 certs, use Portecle app to convert PEM to BKS-V1 HTTPS – Certificate pinning Network Security
  10. private fun getTrustManagers(context: Context, keyStoreFile: Int, keystorePassword: String): Array<TrustManager> {

    val trusted = KeyStore.getInstance("BKS") val rawResource = context.resources.openRawResource(keyStoreFile) trusted.load(rawResource, keystorePassword.toCharArray()) val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) trustManagerFactory.init(trusted) return trustManagerFactory.trustManagers } HTTPS – Certificate pinning Network Security
  11. @Throws(KeyStoreException::class, CertificateException::class, NoSuchAlgorithmException::class, IOException::class, KeyManagementException::class) fun getPinnedCertSocketFactory(context: Context, keyStoreFile: Int,

    keystorePassword: String, forceTls12: Boolean): SSLSocketFactory { val trustManagers = getTrustManagers(context, keyStoreFile, keystorePassword) val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustManagers, null) var socketFactory = sslContext.socketFactory if (forceTls12 && Build.VERSION.SDK_INT in 16..19) { socketFactory = ForceTlsSocketFactory(sslContext.socketFactory) } return socketFactory } HTTPS – Certificate pinning Network Security
  12. Where to store sensitive data? (1) Internal Storage - only

    accessible by the app Really? - What if allowBackup=true? (this is accessible with an adb command) Really? – What is the device is rooted? (2) External Storage Anyone can read and write that L But the internal one is limited , so sometimes we need it How to store sensitive data? Encrypt it! -> No one can read Authenticate it! -> Modification is detected! Storing sensitive data on the device Data Security
  13. (1) Shared Preferences Encrypt the values by yourself -> See

    cryptography section! (2) Databases – SQL Use SQLCipher – Supports AES-256-CBC+HMAC_SHA1 val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, "password", null) (3) Databases – NoSQL Use Realm - Supports AES-256-GCM val realmConfiguration = RealmConfiguration.Builder().encryptionKey(key).build() (4) File storage Use Facebook Conceal – AES-256-GCM Secure Solutions for Storage Types Data Security
  14. Crypto is (also) fragmented! (e.q AES-256 is API26+) Android Crypto

    implementations Above the JVM: BouncyCastle Below the JVM: OpenSSL Different versions... ...different ciphers supported ...known vulnerabilities in older versions Solution: Include the BouncyCastle as a lib Package names will collide! -> Spongy Castle Implementations Cryptography
  15. Repackaged version of Bouncy Castle Technically the same, but different

    packagename Different identifier – SC You can include the version you want – 1.58.0 is latest! Includes most of the available ciphers and algorithms Symmetric crypto e.g. AES – 128/256 – CBC/GCM Asymmetric crypto e.g. RSA, ECDSA, ECDHE Key derivation e.g. PBKDF2WithHmacSHA1, PBEWITHHMACSHA1 ... SpongyCastle Cryptography
  16. Include the library: compile 'com.madgag.spongycastle:core:1.56.0.0' compile 'com.madgag.spongycastle:prov:1.56.0.0’ Register as a

    crypto provider class MyApplication : Application() { companion object { init { Security.insertProviderAt(BouncyCastleProvider(), 1) } } } Example: Generate keys for Realm Cryptography
  17. Use PBDKF2 for Keys Use user input as password (e.q

    a string) – Do not store that Salt it with random number – Initialization Vector (IV) Save IV for later use fun generateRandom(lengthInBytes: Int): ByteArray { val random = SecureRandom.getInstance(“SHA1PRNG”) val genBytes = ByteArray(lengthInBytes) random.nextBytes(genBytes) return genBytes } Generate 256bit key for AES-256-GCM, And another 256bit key for HMAC fun deriveKey(password: String, iv: ByteArray): ByteArray { val iterationCount = 1000 val keySpec = PBEKeySpec(password.toCharArray(), iv, iterationCount, KEY_SIZE) val keyFactory = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA1”) val keyBytes = keyFactory.generateSecret(keySpec).encoded return keyBytes } Example: Generate keys for Realm Cryptography
  18. Passing it for Realm: fun provideRealm(context: Context, password: CharArray?): Realm

    { val config = RealmConfiguration.Builder() .name(DATABASE_NAME) .encryptionKey(getKeys(context, password)) .schemaVersion(1) .build() return Realm.getInstance(config) } private fun getKeys(context: Context, password: CharArray?): ByteArray { val manager = PasswordManager(context) if (!manager.isPasswordSet(AES_KEY)) { manager.setDerivedPassword(AES_KEY, password!!, 256) } if (!manager.isPasswordSet(HMAC_KEY)) { manager.setDerivedPassword(HMAC_KEY, password!!, 256) } var aesKey: ByteArray? = manager.getDerivedPassword(AES_KEY, password!!, 256) var hmacKey: ByteArray? = manager.getDerivedPassword(HMAC_KEY, password!!, 256) val fullKey: ByteArray = aesKey!!.plus(hmacKey!!) return fullKey } Example: Generate keys for Realm Cryptography
  19. For networking Use HTTPS Specify the best TLS version and

    cipher suite Pin all certificates For local data Encrypt and authenticate Use libraries when possible For cryptography Package the latest Spongy Castle Use random IV and save it! Use PBDF2 for passwords Use AES-256-GCM for encryption Summary Secure Android Applications