Introduction
Almost every mobile application handles an ever-increasing amount of sensitive data. From personal messages to financial transactions, safeguarding this information is of great importance. Many apps implement their own mechanism of encryption and decryption to keep the data safe at rest. With this, comes the concept of cryptographic keys and a very critical aspect of mobile security is the secure storage of these keys, which are essential for encrypting and decrypting data. Improper key management can lead to vulnerabilities, making applications susceptible to attacks and data breaches.
This article delves into effective strategies for securely generating and storing cryptographic keys in Android applications. We will explore the use of hardware-backed keystores, such as the Trusted Execution Environment (TEE) and StrongBox, to enhance the security of your applications and protect user data.
1. Understanding the Android Keystore System
1.1 What is the Android Keystore?
The Android Keystore system is a critical component of the Android security architecture. It allows developers to securely generate, store, and use cryptographic keys within their applications. By leveraging the Keystore, keys can be protected from extraction and unauthorized use, even if the application code or the device’s operating system is compromised.
Key Features of the Android Keystore:
- Isolation: Keys are stored in a container that makes them inaccessible to other applications and the operating system.
- Secure Key Operations: Cryptographic operations using the keys are performed within the Keystore, preventing direct access to the key material.
- Hardware Protection: On devices with hardware support, keys can be stored and used within secure hardware modules.
1.2 Software vs. Hardware-Backed Keystores
Software-Based Keystores:
- Storage: Keys are stored in the device’s encrypted storage.
- Security Level: While keys are protected by the operating system, they are potentially vulnerable to sophisticated software attacks.
– - Use Case: Suitable for less sensitive data where hardware-backed security is not mandatory.
Hardware-Backed Keystores:
- Storage: Keys are stored in secure hardware, isolated from the main processor.
- Security Level: Provides strong protection against both software and hardware attacks.
- Use Case: Essential for applications handling sensitive data, such as financial transactions or personal information.
Advantages of Hardware-Backed Keystores:
- Enhanced Security: Keys are protected against extraction, even if the device is rooted or compromised.
- Secure Execution: Cryptographic operations are performed within the secure hardware, safeguarding the operations themselves.
- Compliance: Meets higher security standards required by industry regulations and guidelines.
2. Hardware-Backed Keystores: TEE and StrongBox
2.1 Trusted Execution Environment (TEE)
The Trusted Execution Environment (TEE) is a secure area of the main processor in Android devices. It ensures that sensitive data is stored, processed, and protected in an isolated environment. The TEE provides hardware isolation, meaning that even if the main operating system is compromised, the TEE remains secure.
Key Characteristics of TEE:
- Isolation: Separates secure and non-secure execution environments.
- Secure Storage: Protects cryptographic keys and sensitive data.
- Wide Availability: Present on most modern Android devices.
2.2 StrongBox
StrongBox is a hardware-backed Keystore introduced in Android 9 (API level 28). It utilizes a dedicated secure processor, such as a Secure Element, to provide an even higher level of security than the TEE.
Benefits of StrongBox:
- Dedicated Hardware Security Module (HSM): Isolates keys from the main processor and TEE.
- Tamper Resistance: Offers resistance against physical attacks and hardware tampering.
- Enhanced Security Features: Supports features like ID attestation and anti-replay protections.
Considerations Regarding Device Compatibility:
- Availability: Only available on devices with the necessary hardware components.
- API Level Requirement: Requires Android 9 or higher.
- Fallback Strategy: Applications should implement a fallback to the TEE if StrongBox is not available.
3. Generating and Storing Keys Securely
3.1 Prioritizing StrongBox for Key Generation
When generating cryptographic keys, it’s best to prioritize StrongBox for the highest level of security.
Steps to Generate Keys Using StrongBox:
3.1.1. Check for StrongBox Support:
Before attempting to generate a key with StrongBox, verify that the device supports it.
boolean hasStrongBox = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_STRONGBOX_KEYSTORE);
3.1.2. Configure Key Generation Parameters:
Specify that the key should be StrongBox-backed during key generation.
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
keyAlias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.setIsStrongBoxBacked(true) // Request StrongBox backing
.build();
3.1.3. Generate the Key:
Use the KeyGenerator to create the key with the specified parameters.
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, “AndroidKeyStore”);
keyGenerator.init(keyGenParameterSpec);
SecretKey secretKey = keyGenerator.generateKey();
Best Practices for StrongBox Key Generation:
- Handle Exceptions Gracefully: StrongBox key generation may fail if the device lacks support or resources are constrained. Implement proper exception handling to fall back to TEE if necessary.
- Verify Key Storage Location: After key generation, verify that the key is indeed stored in StrongBox.
3.2 Falling Back to TEE When StrongBox is Unavailable
If StrongBox is not supported on the device, the next best option is to use the TEE for key storage.
Steps to Generate Keys Using TEE:
3.2.1. Configure Key Generation Parameters Without StrongBox:
Omit the StrongBox backing request.
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, “AndroidKeyStore”);
keyGenerator.init(keyGenParameterSpec);
SecretKey secretKey = keyGenerator.generateKey();
3.2.2. Generate the Key:
Proceed as before using the KeyGenerator.
3.2.3. Verify Hardware Backing:
Confirm that the key is stored in the TEE.
Strategies for Secure Key Generation Using the TEE:
- Ensure Hardware Security: Verify that the key is hardware-backed and not stored in software.
- Inform the User: If hardware-backed security is unavailable, consider informing the user or disabling sensitive features. This will vary from case to case. Take a call based on your need.
3.3 Verifying Hardware-Backed Key Storage
Verifying that a key is hardware-backed is crucial for compliance and security assurance.
Methods to Confirm Hardware-Backed Key Storage:
- Retrieve Key Information: Use KeyFactory and KeyInfo to get details about the key.
KeyFactory factory = KeyFactory.getInstance(
secretKey.getAlgorithm(), “AndroidKeyStore”);
KeyInfo keyInfo = (KeyInfo) factory.getKeySpec(secretKey, KeyInfo.class);
- Check Security Level: Examine the security level of the key.
int securityLevel = keyInfo.getSecurityLevel();
boolean isHardwareBacked = securityLevel == KeyProperties.SECURITY_LEVEL_TRUSTED_ENVIRONMENT
|| securityLevel == KeyProperties.SECURITY_LEVEL_STRONGBOX;
Importance of Verification:
- Compliance: Ensures adherence to security standards and guidelines.
- Security Assurance: Confirms that keys are protected against extraction and tampering.
4. Handling Exceptions and Security Failures
4.1 Custom Exception Handling
Implementing custom exceptions helps maintain clear and secure code. Though this is completely optional and every app can define their own ways to handle exceptions. We prefer keeping it clean and thus, having a dedicated exception sounds good for us.
Creating a Custom Exception:
public class HardwareSecurityException extends Exception {
public HardwareSecurityException(String message) {
super(message);
}
}
Using Custom Exceptions:
- During Key Generation: Throw a HardwareSecurityException if key generation fails or if the key is not hardware-backed.
Benefits:
- Provides specific error information.
- Enhances maintainability and readability of the code.
4.2 Failing Securely
When hardware-backed security isn’t available, it’s essential to fail securely. Here we have multiple ways to handle it. Either add additional support for software backed keys. Second and quick option is to disable sensitive features altogether. In our cases, as we deal with data that is very sensitive, we do not allow devices where we do not have hardware backed security.
Approaches:
- Disable Sensitive Features: Prevent access to features that require secure key storage.
- Inform the User: Provide clear messaging about the security limitations.
- Do Not Fall Back to Insecure Methods: Avoid using software-based keystores as a fallback for sensitive data.
Example Handling:
if (!isHardwareBacked) {
throw new HardwareSecurityException(“Device does not support required hardware security.”);
}
5. Compliance with Security Standards
5.1 Aligning with Industry Guidelines
Adhering to industry standards, such as those set by EMVCo, is crucial for applications handling sensitive data.
Key Requirements:
- Secure Key Storage: Use hardware-backed keystores to protect cryptographic keys.
- Key Usage Restrictions: Limit keys to specific purposes (e.g., encryption, decryption).
- Regular Audits: Ensure ongoing compliance through security reviews.
5.2 Best Practices in Secure Key Management
General Principles:
- Least Privilege: Grant keys only the permissions they need.
- Key Rotation: Implement regular key rotation policies.
- Secure Deletion: Properly delete keys when no longer needed.
Avoiding Common Mistakes:
- Exposing Key Material: Never log or transmit private keys.
- Inadequate Exception Handling: Always handle exceptions that could lead to security bypasses.
- Ignoring Device Variability: Account for differences in hardware capabilities across devices.
6. Devices Without TEE or StrongBox
6.1 Understanding Device Limitations
Some devices may lack hardware-backed security features due to age, cost, or manufacturer choices.
Implications:
- Security Risks: Keys stored in software are more vulnerable.
- Compliance Issues: May not meet industry security requirements.
- User Data Protection: Sensitive data may be at greater risk.
6.2 Programmatically Checking for Hardware Security Features
Techniques to Detect Hardware Security:
- Check for StrongBox:
boolean hasStrongBox = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_STRONGBOX_KEYSTORE);
- Verify TEE Support: Generate a test key and check if it’s hardware-backed.
Decision-Making Based on Capabilities:
- Fallback Strategies: Decide whether to use TEE or limit functionality.
- User Communication: Inform users if their device lacks necessary security features.
Conclusion
Recap of Key Points
- Secure key storage is essential for protecting sensitive data in Android applications.
- Prioritize hardware-backed keystores, using StrongBox when available, and falling back to TEE as needed.
- Verify that keys are stored securely to ensure compliance and enhance security.
- Handle exceptions and security failures gracefully, maintaining the integrity of your application’s security posture.
Originally published at https://medium.com on October 14, 2024.