Android System Securing, Hardening, & Privacy

Implementing StrongBox Key Attestation: A Step-by-Step Android Developer Guide

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction

In the landscape of modern mobile security, protecting sensitive data and cryptographic keys is paramount. Android’s security architecture has continuously evolved, introducing robust hardware-backed keystores to shield against increasingly sophisticated attacks. At the pinnacle of these advancements lies StrongBox Keymaster, a dedicated, tamper-resistant security chip designed to offer the highest level of cryptographic isolation on Android devices. This guide delves into the practical implementation of StrongBox Key Attestation, providing Android developers with a step-by-step approach to leverage this powerful feature for enhanced application security.

Key attestation is a critical mechanism that allows an application to cryptographically verify the properties of a key and its origin. By attesting a key, your application can gain high assurance that a specific key was generated within a secure hardware environment (like StrongBox), has certain immutable properties, and has not been tampered with or exported. This trust foundation is essential for scenarios involving digital rights management, secure payments, strong user authentication, and protecting highly sensitive data.

Understanding StrongBox and the Keymaster HAL

What is StrongBox?

StrongBox Keymaster is a hardware security module (HSM) that runs on a physically separate, isolated chip, often referred to as a Secure Element (SE). Unlike keys stored in the Trusted Execution Environment (TEE), StrongBox keys are protected by an even higher degree of isolation, making them resilient to sophisticated software exploits targeting the TEE, and even certain physical attacks. Devices supporting StrongBox Keymaster typically implement it on a dedicated chip that provides cryptographic operations and key storage completely isolated from the main application processor.

The Keymaster Hardware Abstraction Layer (HAL)

Android interacts with hardware-backed keystores, including StrongBox, through the Keymaster Hardware Abstraction Layer (HAL). The Keymaster HAL defines a set of interfaces that cryptographic modules must implement. When an application requests a key operation, the Android Keystore system directs the request to the appropriate Keymaster implementation – be it software-backed, TEE-backed, or StrongBox-backed. StrongBox’s key differentiator is its `SECURITY_LEVEL_STRONGBOX`, indicating that the key material and cryptographic operations are handled exclusively within the StrongBox chip.

Generating StrongBox-Backed Keys

To leverage StrongBox’s enhanced security, you must explicitly request that your keys be backed by it during generation. This is achieved using the `setIsStrongBoxBacked(true)` method within the `KeyGenParameterSpec` when creating a new key pair or secret key. Note that StrongBox support is available on devices running Android 9 (API level 28) and higher, provided the device includes the necessary hardware.

Here’s how to generate an Elliptic Curve (EC) key pair intended for signing and verification, securely stored within StrongBox:

import android.security.keystore.KeyGenParameterSpec;import android.security.keystore.KeyProperties;import java.io.IOException;import java.security.InvalidAlgorithmParameterException;import java.security.KeyPairGenerator;import java.security.KeyStore;import java.security.KeyStoreException;import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException;import java.security.cert.CertificateException;import java.util.Calendar;import javax.security.auth.x500.X500Principal;public class StrongBoxKeyGenerator {    private static final String KEY_ALIAS = "my_strongbox_signing_key";    private static final String ANDROID_KEYSTORE = "AndroidKeyStore";    public static void generateStrongBoxSigningKey() {        try {            KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);            keyStore.load(null);            // Check if key already exists            if (keyStore.containsAlias(KEY_ALIAS)) {                System.out.println("Key "" + KEY_ALIAS + "" already exists.");                return;            }            Calendar start = Calendar.getInstance();            Calendar end = Calendar.getInstance();            end.add(Calendar.YEAR, 1);            KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(                    KEY_ALIAS,                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)                    .setAlgorithmParameterSpec(new android.security.keystore.ECGenParameterSpec("secp256r1"))                    .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)                    .setKeySize(256)                    .setUserAuthenticationRequired(true) // Requires biometric/PIN auth for use                    .setUserAuthenticationValidityDurationSeconds(300) // 5 minutes validity                    .setIsStrongBoxBacked(true) // Crucial for StrongBox backing                    .setAttestationChallenge("my_app_challenge_1234".getBytes()) // Optional challenge for attestation                    .setCertificateSubject(new X500Principal("CN=My App, O=My Organization"))                    .setCertificateSerialNumber(java.math.BigInteger.valueOf(1337))                    .setCertificateNotBefore(start.getTime())                    .setCertificateNotAfter(end.getTime())                    .build();            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(                    KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE);            keyPairGenerator.initialize(keyGenParameterSpec);            keyPairGenerator.generateKeyPair();            System.out.println("StrongBox-backed EC key "" + KEY_ALIAS + "" generated successfully.");        } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException |                    KeyStoreException | IOException | CertificateException e) {            e.printStackTrace();            System.err.println("Error generating StrongBox key: " + e.getMessage());        }    }}

In this code, `setIsStrongBoxBacked(true)` instructs the Android Keystore system to attempt to generate the key within StrongBox. If StrongBox is not available or encounters an error, the key generation might fail or fall back to TEE (depending on the device’s Keymaster implementation and Android version), which is why attestation is essential to verify the actual security level.

The Key Attestation Process

Key attestation is the mechanism by which your app or a remote server can obtain cryptographically verifiable proof about a key’s characteristics and its hardware origin. When you request attestation, the StrongBox Keymaster generates a certificate chain that includes details about the key and the device’s security posture.

Attestation Certificate Chain

The attestation certificate chain consists of several certificates:

  1. Key Attestation Certificate: Issued by the Keymaster, this certificate directly contains the attestation record for your generated key.
  2. Attestation Certificate Authority (CA) Certificate: Issued by the device’s Keymaster or TEE, signing the key attestation certificate.
  3. OEM Root Certificate: Issued by the device manufacturer, signing the attestation CA certificate.
  4. Google Root Certificate: The ultimate trust anchor, issued by Google, signing the OEM root certificate.

You retrieve this chain using `KeyStore.getCertificateChain(KEY_ALIAS)`. The most crucial part of this chain is the Key Attestation Certificate, which embeds an ASN.1 structure containing the attestation record.

Attestation Record Details

The attestation record, embedded as an extension (OID `1.3.6.1.4.1.11129.2.1.17`) within the Key Attestation Certificate, provides detailed information:

  • `attestationVersion` and `keymasterVersion`: Versions of the attestation format and Keymaster.
  • `attestationSecurityLevel` and `keymasterSecurityLevel`: Crucially, these indicate whether the attestation and the key itself are backed by StrongBox (`SECURITY_LEVEL_STRONGBOX`), TEE (`SECURITY_LEVEL_TRUSTED_ENVIRONMENT`), or software.
  • `rootOfTrust`: Contains critical device security information like `verifiedBootKey` (hash of the verified boot key), `deviceLocked` (true if the bootloader is locked), and `verifiedBootState` (e.g., `VERIFIED`, `UNVERIFIED`, `UNSUPPORTED`).
  • `attestationChallenge`: If provided during key generation, this challenge is included, allowing you to link the attestation to a specific request.
  • `softwareEnforced` and `hardwareEnforced`: These lists detail the key properties (purposes, algorithm, user authentication requirements, etc.) that are enforced by software (Android Keystore) versus those enforced by the secure hardware (StrongBox/TEE). For strong security, critical properties should be hardware-enforced.

Verifying Key Attestation

Verifying the attestation involves several steps, ideally performed on a trusted remote server, but can also be partially done on the client for initial checks.

Step 1: Validate the Certificate Chain

First, validate the entire certificate chain:

  1. Verify that the Google Root Certificate is a trusted root CA.
  2. Verify the signature of each certificate in the chain, working upwards to the Google Root.
  3. Check the validity periods for all certificates.
  4. Ensure the certificate paths are correct and no certificates are revoked.

Step 2: Parse the Attestation Record

Starting with Android 12 (API level 31), you can conveniently parse the attestation record using the `KeyAttestation` class. For older API levels, you would need to manually parse the ASN.1 structure.

import android.security.attestation.AttestationSecurityLevel;import android.security.attestation.KeyAttestation;import android.security.attestation.RootOfTrust;import java.io.IOException;import java.security.cert.Certificate;import java.security.cert.CertificateEncodingException;import java.security.cert.X509Certificate;import java.util.Arrays;import java.util.List;public class AttestationVerifier {    public static boolean verifyStrongBoxAttestation(Certificate[] certificateChain, byte[] expectedChallenge) {        if (certificateChain == null || certificateChain.length == 0) {            System.err.println("Certificate chain is null or empty.");            return false;        }        // 1. Basic Certificate Chain validation (simplified)        // In a real-world scenario, you'd use CertificateFactory, TrustManager, etc.        // For this example, we assume the chain is generally valid for parsing.        X509Certificate keyAttestationCert = (X509Certificate) certificateChain[0];        System.out.println("Key Attestation Certificate Subject: " + keyAttestationCert.getSubjectX500Principal());        try {            // Parse the attestation record using KeyAttestation (API 31+)            KeyAttestation attestation = KeyAttestation.getAttestationFromCertificate(keyAttestationCert);            // 2. Verify Security Levels            if (attestation.getKeymasterSecurityLevel() != AttestationSecurityLevel.STRONGBOX ||                    attestation.getAttestationSecurityLevel() != AttestationSecurityLevel.STRONGBOX) {                System.err.println("Key or Attestation not StrongBox-backed. Keymaster security level: " +                        attestation.getKeymasterSecurityLevel() +                        ", Attestation security level: " + attestation.getAttestationSecurityLevel());                return false;            }            System.out.println("Key and Attestation are StrongBox-backed.");            // 3. Verify Root of Trust properties            RootOfTrust rootOfTrust = attestation.getRootOfTrust();            if (!rootOfTrust.isDeviceLocked()) {                System.err.println("Device bootloader is unlocked. Security compromised.");                return false;            }            if (rootOfTrust.getVerifiedBootState() != RootOfTrust.VerifiedBootState.VERIFIED) {                System.err.println("Verified boot state is not VERIFIED: " + rootOfTrust.getVerifiedBootState());                return false;            }            System.out.println("Device is locked and verified boot is VERIFIED.");            // 4. Verify Attestation Challenge (if provided)            if (expectedChallenge != null && !Arrays.equals(attestation.getAttestationChallenge(), expectedChallenge)) {                System.err.println("Attestation challenge mismatch.");                return false;            }            System.out.println("Attestation challenge matches.");            // 5. Verify Hardware-Enforced Properties (example: ensure signing purpose is hardware enforced)            if (!attestation.getHardwareEnforced().getPurposes().contains(KeyProperties.PURPOSE_SIGN)) {                System.err.println("Signing purpose is not hardware-enforced.");                return false;            }            System.out.println("Signing purpose is hardware-enforced.");            // Further checks could involve:            // - Checking `softwareEnforced` vs `hardwareEnforced` for other critical properties            // - Checking key algorithm, digests, key size, etc.            System.out.println("StrongBox Key Attestation verification successful!");            return true;        } catch (CertificateEncodingException e) {            e.printStackTrace();            System.err.println("Error decoding certificate: " + e.getMessage());            return false;        } catch (IOException e) {            e.printStackTrace();            System.err.println("Error parsing attestation: " + e.getMessage());            return false;        }    }}

Step 3: Verify Key Properties

After parsing, critically examine the extracted properties:

  • Security Levels: Confirm both `keymasterSecurityLevel` and `attestationSecurityLevel` are `SECURITY_LEVEL_STRONGBOX`. If not, the key is not as secure as expected.
  • Root of Trust: Ensure `isDeviceLocked()` is `true` and `getVerifiedBootState()` is `VERIFIED`. An unlocked bootloader or an unverified boot state indicates a potentially compromised device.
  • Attestation Challenge: If you provided a unique challenge during key generation, verify that the `attestationChallenge` in the record matches what you sent. This prevents replay attacks and ensures the attestation is for your specific request.
  • Hardware-Enforced Properties: Scrutinize `hardwareEnforced` properties. For instance, if you intend the key for signing, `KeyProperties.PURPOSE_SIGN` should ideally be in the `hardwareEnforced` list. If a critical property is only `softwareEnforced`, it means Android’s software layer enforces it, not the StrongBox, reducing its trustworthiness.

Advanced Considerations and Best Practices

  • Error Handling: Always anticipate that StrongBox might not be available or that attestation might fail. Gracefully handle exceptions like `KeyPermanentlyInvalidatedException` if the key becomes unusable.
  • Device Compatibility: Not all Android 9+ devices have StrongBox. You can check for StrongBox presence by trying to generate a StrongBox-backed key and observing the attestation result, or by inspecting `KeyInfo.getSecurityLevel()` after a successful generation (though attestation provides stronger guarantees).
  • Attestation Challenge Usage: For robust security, the `attestationChallenge` should be a unique, cryptographically random nonce generated by your server for each attestation request. This prevents an attacker from replaying an old attestation certificate.
  • Server-Side Verification: While basic checks can be done on the client, the full and authoritative verification of the attestation certificate chain and record should occur on a trusted remote server. This protects against a compromised client manipulating the verification logic.
  • Key Revocation: Implement mechanisms to revoke trust in attested keys if device compromise is detected (e.g., if future attestations fail security checks).

Conclusion

Implementing StrongBox Key Attestation significantly elevates the security posture of your Android applications. By providing a verifiable chain of trust from a hardware-backed root to your cryptographic keys, you can confidently build applications that handle sensitive operations with the highest assurance. While it introduces additional complexity, the robust protection against software vulnerabilities and physical tampering offered by StrongBox Keymaster and its attestation capabilities is an indispensable asset for developers committed to delivering truly secure mobile experiences.

Android Mobile Specs & Compare Directory

Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner