第3章:AES密钥生成与存储——KeyGenerator配置、密钥规格、存入KeyStore、提取密钥引用

3.1 原理概述

Android KeyStore 允许开发者将 AES 密钥安全地生成并存储于硬件隔离区(TEE/StrongBox),而非软件堆内存。密钥材料永不离开安全环境,应用仅能通过 KeyStore.SecretKeyEntry 引用执行加密/解密操作。本章聚焦 AES 对称密钥的生成配置、规格选择、存储机制与引用获取。

关键概念: KeyGenerator 初始化时通过 KeyGenParameterSpec 定义密钥用途、块模式、填充方式、有效期等属性;密钥存入 KeyStore 后,应用只能通过别名获取 SecretKey 对象引用,无法直接读取二进制密钥值。

3.2 AES密钥规格与KeyGenerator配置

3.2.1 密钥长度

Android KeyStore 支持 AES-128、AES-192、AES-256。推荐使用 AES-256 以获得最高安全等级。

密钥长度安全性性能影响
128 bit一般最快
192 bit较好中等
256 bit最强最慢

3.2.2 块模式与填充

  • GCM:推荐模式,自带认证标签(AEAD),无需单独计算 HMAC。块大小为 128 bit,不允许使用填充(NoPadding)。
  • CBC/PKCS7Padding:兼容性高,但需要额外处理 IV 和 MAC 保护。
  • ECB:不安全,禁用。

3.2.3 KeyGenParameterSpec 配置示例

KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
        "my_aes_key_alias",
        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
    .setKeySize(256)
    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
    .setRandomizedEncryptionRequired(true)
    .setUserAuthenticationRequired(false)  // 是否绑定生物/锁屏认证
    .build();

3.3 实现流程:生成→存储→提取引用

  1. 获取 KeyGenerator 实例:KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
  2. 初始化 KeyGenerator:传入上述 KeyGenParameterSpec
  3. 生成密钥:调用 keyGenerator.generateKey(),密钥自动写入 KeyStore
  4. 提取密钥引用:通过 KeyStore.getInstance("AndroidKeyStore") 加载,再 keyStore.getEntry("my_aes_key_alias", null) 获得 SecretKeyEntry
  5. 使用密钥:从 entry 获取 SecretKey,初始化 Cipher 执行加解密

3.4 内联SVG:AES密钥生成与存储流程

AES密钥生成与存储流程 KeyGenerator.getInstance() KeyGenParameterSpec构建 KeyGenerator.init(spec) generateKey() → KeyStore KeyStore.load(null) KeyStore.getEntry(alias) 获取 SecretKey 引用 Cipher.init() 使用密钥 密钥材料永久驻留 KeyStore硬件安全区 应用不可直接读取 每次使用需通过 KeyStore.getEntry() 引用

3.5 完整代码示例:生成与提取AES密钥

import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import java.security.KeyStore;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class AesKeyStoreHelper {

    private static final String ANDROID_KEYSTORE = "AndroidKeyStore";
    private static final String KEY_ALIAS = "aes_gcm_key";

    public static void generateAesKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(
                KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE);

        KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
                KEY_ALIAS,
                KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setKeySize(256)
                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                .setRandomizedEncryptionRequired(true)
                .build();

        keyGenerator.init(spec);
        keyGenerator.generateKey();  // 密钥自动存入 KeyStore
    }

    public static SecretKey getKey() throws Exception {
        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
        keyStore.load(null);
        KeyStore.SecretKeyEntry entry = (KeyStore.SecretKeyEntry)
                keyStore.getEntry(KEY_ALIAS, null);
        return entry.getSecretKey();
    }
}

3.6 调试与验证

  • 日志确认:在 generateKey() 后通过 keyStore.containsAlias(KEY_ALIAS) 返回 true 验证存储成功。
  • 异常捕获:KeyStoreException、NoSuchAlgorithmException、InvalidAlgorithmParameterException 为常见异常。
  • 安全要求:Android 6.0+ 默认支持;Android 9+ 支持 StrongBox 密钥。

3.7 常见错误与避坑

错误原因解决方案
PURPOSE_ENCRYPT 未设置调用 Cipher 加密时抛出异常生成 spec 时必须包含加密用途
GCM 模式下使用填充指定 ENCRYPTION_PADDING_PKCS7GCM 必须使用 ENCRYPTION_PADDING_NONE
密钥别名冲突重复生成同名密钥生成前先检查 exists,或先删除再创建
设备不支持硬件隔离低端设备异常降级为软件 KeyStore(不推荐)或提示用户

3.8 性能与稳定性优化

  • 生成一次,多次复用:密钥生成是耗时操作(约 50~200ms),应在应用初始化阶段生成,之后每次只提取引用。
  • 缓存 SecretKey 引用:在内存中缓存 SecretKey 对象(不是密钥材料),避免每次加解密都重新加载 KeyStore。
  • StrongBox 支持检测:通过 KeyStore.getKeyCharacteristics() 检查密钥是否真正硬件保护。
进阶提示: 使用 KeyGenParameterSpec.Builder.setIsStrongBoxBacked(true) 可在 Android 9+ 强制使用 StrongBox 安全芯片,需在清单中添加 FEATURE_STRONGBOX_KEYSTORE 特征声明。