Skip to main content

Android Encryption Updates from I/O 2019

Android Encryption Updates from I/O 2019

Now the Google I/O’ 19 is officially in the books I wanted to do a short overview on some of the interesting Android Encryption updates announced at this years event. This overview contains three main topics, Adiantum mode, the Jetpack Security Crypto library, and TLS 1.3 enabled by default.  Each of these encryption updates contains there own special niche in the Android ecosystem and I feel is a great step forward for the security of the data in the ecosystem - especially for low end devices.  This post provides sample Java code for getting started, provides links on how to find out more, and also provides tips for implementation details possibly not called out in the documentation.  Remember that while this is sample code some of the libraries in this post still run in a pre-release state and some of these topics, like Jetpack Security, only run on Android Q as of right now.  Please take this in consideration when reading this post and please leave a comment if you have any questions.  Let's jump in!

All code from this post is available on my Github here.

 

Adiantum Encryption Mode 🔐

Adiantum mode

Android now supports encryption for devices that do not have hardware acceleration built-in with a new encryption mode called Adiantum.  This is a key security and user experience update to the Android ecosystem because previous to Adiantum phones and IoT devices often had to sacrifice user experience to encrypt their data on the filesystem.  Users would experience device slowness and lag as data was being encrypted and decrypted and this often would be a factor in making the decision to not encrypt data at all. Now with Adiantum, storage encryption is done with a fast hash and fast stream cipher which is a lot smaller than a same size cipher-text to plaintext, like done for AES.  According to the benchmarks on the Adiantum repository decryption is over 5 times faster than AES without accelerated hardware enabled. This encryption mode will be available when Android Q is released and device manufacturers can start taking advantage of this right away.

 

Jetpack Security 🗞

Jetpack Security

Next, encrypting data in your application.  This year a security library was added to Android Jetpack for file, shared preference, and API key encryption. This new security library is still in alpha but will be available for all devices running Android 6.0 above and will solve the problem of developers having to roll their own encryption solutions and risk making mistakes.  Jetpack Security will provide solutions for 3 common problems:

  1. Safely storing keysets for file or API key encryption / decryption.
  2. Safely storing a master key to encrypt / decrypt your existing SharedPreference keys.
  3. A recommended API to actually encrypt and decrypt files, shared preferences, and API keys. 

 

The following code below illustrates an example on how to get started with Jetpack Security for file encryption.  Before you can get started though you need to import the new Security Crypto library from Jetpack into your Gradle dependencies and load this library into project.  Remember, this version is in Alpha!

dependencies {
    implementation 'androidx.security:security-crypto:1.0.0-alpha01'
}

Next, you need to create a set of string based keys to store in the SharedPreferences.  These keys will then be encrypted.  Also, something to note is that even if these keys are compromised files cannot be decrypted without the master key.  Which brings us to the master key.  The master key is used along with the SharedPreference keys to create an EncryptedFile object.  When this object is created successfully it is essentially a set of decrypted byte stream characters.  From there it's a character conversion routine that reads all of the characters into a consumable string for observation.

Immediately after catching an exception or decrypting a file, please be sure to wipe all memory that holds reference to the encrypted_file, encryptedInputStream, stringBasedOutputStream, and the buffer to prevent security leakage.

import java.io.ByteArrayOutputStream;
import java.util.Set;
import java.util.HashSet;
import java.io.File;
import java.io.FileInputStream;
import androidx.security.crypto.EncryptedFile;
import androidx.security.crypto.MasterKeys;
 
// (1) Setting file or API specific keys in your SharedPreferences.
// Create your actual private keys for file encryption/decryption.
Set<String> key_set = new HashSet<String>();
key_set.add("stringbasedencryptionkeyone");
key_set.add("stringbasedencryptionkeytwo");
 
String keySetReference = "secret_file_keys";
 
// Store them in the shared pr
SharedPreferences sharedPref = this.getPreferences(this.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putStringSet(keySetReference, key_set);
editor.commit();
 
try {
    // (2) Getting a reference to your applications Master Keys
    // Get a reference to the master keys
    String masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC);
 
    // File to decrypt and read off disk
    String fileReference = "routing_numbers.txt";
    String stringBasedOutputStream;
    Context currentContext = this.getApplicationContext();
    File secret_file = new File(currentContext.getFilesDir(), fileReference);
 
 
    // (3) Using both keys to decrypt files and read them in your application.
    // Generate the encrypted file object with many constructor paramters:
    // 1) The secret file reference.
    // 2) The current application context.
    // 3) A master key alias for decrypting your keyset in the SharedPreferences.
    // 4) The FileEncryptionScheme (AES256_GCM_HKDF_4KB)
    // Note) The setKeysetAlias chained method call on the constructor call.
    //       This will set the SharedPreference key to the encryption keys in the SharedPreferences.
    EncryptedFile encrypted_file = new EncryptedFile.Builder(
            secret_file,
            currentContext,
            masterKeyAlias,
            EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).setKeysetAlias(keySetReference)
            .build();
 
    FileInputStream encryptedInputStream = encrypted_file.openFileInput();
    try {
 
        int buffer = encryptedInputStream.read();
        stringBasedOutputStream = "";
        char firstCharVal = (char)buffer;
        stringBasedOutputStream += firstCharVal;
        while (buffer != -1) {
            char charVal = (char)buffer;
            stringBasedOutputStream += charVal;
            buffer = encryptedInputStream.read();
        }
        // do something with the decrypted file (stringBasedOutputStream) here.
        // clean up all encrypted values held in memory right after to prevent security leak.
 
    } catch (Exception e) {
        // Handle Exception Here
        // Clear out:
        //   *encryptedInputStream
        //   *stringBasedOutputStream
        //   *encrypted_file
        //   to prevent security leakage.
    } finally {
        encryptedInputStream.close();
    }
 
 
} catch (Exception e) {
    // Handle Exception Here
}

 

TLS 1.3 By Default 📡

TLS 1.3 by Default

As of August of 2018, the TLS 1.3 draft became final and sparked a new era of secure network transport on the internet.  Servers, CDNs, and now mobile applications can take advantage of the security and performance updates that TLS 1.3 provides over 1.2. Google announced at I/O this year that Android Q will now support TLS 1.3 by default will use of conscrypt.  So what does that mean for your application's network traffic?  Does that mean that you can just enabled TLS 1.3 and get the benefits of it out of the box?  The answer to this is no.  You can enable TLS 1.3 on your Android application side, but if the servers, CDN, and load balancer's your application talks to do not support it 1.3, you will most likely be falling back to 1.2 and a different set of secure transport ciphers.  To take advantage of the performance and security benefits in 1.3, make sure your infrastructure team is using it as well.

The code examples below are a brief look at what is available in TLS 1.3 on the Android application side with conscrypt.  The first thing to note is the cipher-suite used.  Make sure these suites are supported by your infrastructure team as well.  This list of ciphers is thankfully condensed from what was available in TLS 1.2.  The last and most important thing to notice is the TLS fallback.  Notice that conscrypt provide a fallback all the way to TLS 1.0 for network transport infrastructure that does not support 1.3, 1.2, or 1.1.  This is a key support feature because there may be times where different connections have to use a different versions of TLS for legacy reasons.  The very last thing I also like to note is that conscrypt uses BoringSSL and not the OpenSSL as it's crypto engine.  So keep this in mind if you are digging through implementation details.

// SUPPORTED_TLS_1_3_CIPHER_SUITES in conscrypt for TLS 1.3
static final String[] SUPPORTED_TLS_1_3_CIPHER_SUITES = new String[] {
        "TLS_AES_128_GCM_SHA256",
        "TLS_AES_256_GCM_SHA384",
        "TLS_CHACHA20_POLY1305_SHA256",
};
 
// List of protocols enabled by default when TLS 1.3 is used.
// This means that your application can fall all the way back to TLS 1.0
/** Protocols to enable by default when "TLSv1.3" is requested. */
static final String[] TLSV13_PROTOCOLS = new String[] {
        SUPPORTED_PROTOCOL_TLSV1,
        SUPPORTED_PROTOCOL_TLSV1_1,
        SUPPORTED_PROTOCOL_TLSV1_2,
        SUPPORTED_PROTOCOL_TLSV1_3,
};
 
 
/**
 * Valid values for X509TrustManager.checkServerTrusted authType,
 * either key exchange algorithm part of the cipher suite, UNKNOWN,
 * or GENERIC (for TLS 1.3 cipher suites that don't imply a specific
 * key exchange method).
 */
public static final Set<String> SERVER_AUTH_TYPES = new HashSet<String>(Arrays.asList("DHE_DSS",
        "DHE_DSS_EXPORT", "DHE_RSA", "DHE_RSA_EXPORT", "DH_DSS_EXPORT", "DH_RSA_EXPORT",
        "RSA_EXPORT1024", "ECDH_ECDSA", "ECDH_RSA", "ECDHE_ECDSA", "ECDHE_RSA", "UNKNOWN"));
        "RSA_EXPORT1024", "ECDH_ECDSA", "ECDH_RSA", "ECDHE_ECDSA", "ECDHE_RSA", "UNKNOWN",
        "GENERIC"));
 
 
 
// Veiw SSLContext CipherSuites using TLSv1.3 with conscrpyt
 
SSLContext context = SSLContext.getInstance("TLSv1.3");
context.init(null, null, null);
SSLServerSocketFactory sf = context.getServerSocketFactory();
SSLServerSocket ssl = (SSLServerSocket) sf.createServerSocket();
HashSet ciphers = new HashSet<String>(Arrays.asList(ssl.getEnabledCipherSuites()))
                .containsAll(StandardNames.CIPHER_SUITES_TLS13);

In Summary ⌛️

In summary I am very excited to see these new advancements in storage and network encryption.  Adiantum, Jetpack Security, and the new Network Security Configurations all represent an effort by Google and the community to make their ecosystem more secure, especially in devices that do not have premium hardware.  Over the course of the next year I will be very interested to hear stories of IoT and wearables devices adapting Adiantum and how that goes.  I am also interested to hear stories of teams taking advantage of the new TLS 1.3 advancements available on Android too.  If you adopt any of these items or use Jetpack Security, please let me know.  I've love to hear your story.  

Thank you for reading, and please let me know if you have a question, comment, or concern.  You can find the code from this post here on my Github.

References 📘

  1. Android Security Blog: https://security.googleblog.com/search/label/android%20security
  2. Adiantum: https://github.com/google/adiantum
  3. Jetpack Security: https://developer.android.com/jetpack/androidx/releases/security
  4. Conscrypt: https://developer.android.com/jetpack/androidx/releases/security
  5. IETF - TLS 1.3: https://www.ietf.org/blog/tls13/

Member for

3 years 9 months
Matt Eaton

Long time mobile team lead with a love for network engineering, security, IoT, oss, writing, wireless, and mobile.  Avid runner and determined health nut living in the greater Chicagoland area.

Comments

Venkatesh Pras…

Tue, 01/28/2020 - 01:03 PM

Thanks for nice article. I have couple of questions regarding Android Security lib.

Can we use this for all types of files or only text?

"stringBasedOutputStream" this is output after extracting the file, Do I need to copy this data to another file to use that file ? I