第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 实现流程:生成→存储→提取引用
- 获取 KeyGenerator 实例:
KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") - 初始化 KeyGenerator:传入上述
KeyGenParameterSpec - 生成密钥:调用
keyGenerator.generateKey(),密钥自动写入 KeyStore - 提取密钥引用:通过
KeyStore.getInstance("AndroidKeyStore")加载,再keyStore.getEntry("my_aes_key_alias", null)获得SecretKeyEntry - 使用密钥:从 entry 获取
SecretKey,初始化 Cipher 执行加解密
3.4 内联SVG:AES密钥生成与存储流程
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_PKCS7 | GCM 必须使用 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 特征声明。