当前位置: 首页 > news >正文

【Android Keystore】Android 密钥库系统使用指南

Android 密钥库系统

https://developer.android.google.cn/privacy-and-security/keystore?hl=zh-cn

Android Keystore 系统的核心设计目标之一,就是确保密钥材料(Key Material)​难以从设备中提取,并且通常无法在其他设备中使用。

Android Keystore 是一个系统服务,它提供了一个安全的容器来生成、存储和管理加密密钥,并确保密钥材料本身难以从设备中提取。

Android Keystore 是一个安全的密钥管理系统,而不仅仅是一个简单的密钥存储库。它负责密钥的全生命周期管理(生成、存储、使用),并确保密钥材料的安全

Android Keystore 系统提供了一种安全的方式来生成、存储和使用加密密钥,确保密钥材料难以从设备中提取,以下示例展示如何使用 Java 代码生成密钥、检查其是否受硬件支持、进行数据加密和解密,以及验证签名。

1. 生成密钥 🔐

首先,使用 KeyPairGenerator 生成一个 RSA 密钥对,并将其存储在 Android Keystore 中。密钥生成时会指定用途(如加密、解密、签名、验证)、摘要算法、是否需要用户认证等参数。

import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.spec.ECGenParameterSpec;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;// 生成非对称密钥对(例如 RSA 或 EC)
public KeyPair generateKeyPair(String alias, boolean requireAuth) throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(alias,KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY).setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1).setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS).setKeySize(2048);if (requireAuth) {builder.setUserAuthenticationRequired(true);// 设置认证有效期(秒),或每次操作都需要认证// builder.setUserAuthenticationValidityDurationSeconds(300);}keyPairGenerator.initialize(builder.build());return keyPairGenerator.generateKeyPair();
}// 生成对称密钥(例如 AES)
public SecretKey generateSymmetricKey(String alias) throws Exception {KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias,KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT).setBlockModes(KeyProperties.BLOCK_MODE_GCM).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE).setKeySize(256).build();keyGenerator.initialize(spec);return keyGenerator.generateKey();
}

2. 检查密钥的硬件支持 🔍

生成密钥后,可以检查密钥是否存储在硬件安全模块(如 TEE 或 StrongBox)中。

import android.security.keystore.KeyInfo;
import java.security.KeyFactory;public void checkKeySecurityLevel(String alias) throws Exception {KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null);KeyStore.Entry entry = keyStore.getEntry(alias, null);if (entry instanceof KeyStore.PrivateKeyEntry) {PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();KeyFactory factory = KeyFactory.getInstance(privateKey.getAlgorithm(), "AndroidKeyStore");KeyInfo keyInfo = factory.getKeySpec(privateKey, KeyInfo.class);boolean isInsideSecureHardware = keyInfo.isInsideSecureHardware();int securityLevel = KeyProperties.SECURITY_LEVEL_SOFTWARE;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {securityLevel = keyInfo.getSecurityLevel();if (securityLevel == KeyProperties.SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {System.out.println("Key is in Trusted Execution Environment (TEE)");} else if (securityLevel == KeyProperties.SECURITY_LEVEL_STRONGBOX) {System.out.println("Key is in StrongBox");} else {System.out.println("Key is in software");}} else {System.out.println("isInsideSecureHardware: " + isInsideSecureHardware);}}
}

3. 使用密钥进行加密和解密 🔒

使用生成的密钥进行加密和解密操作。以下示例使用 RSA 非对称加密。

import javax.crypto.Cipher;public byte[] encryptData(String alias, byte[] data) throws Exception {KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null);KeyStore.Entry entry = keyStore.getEntry(alias, null);if (entry instanceof KeyStore.PrivateKeyEntry) {PublicKey publicKey = ((KeyStore.PrivateKeyEntry) entry).getCertificate().getPublicKey();Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}throw new Exception("No such key or not a private key entry");
}public byte[] decryptData(String alias, byte[] encryptedData) throws Exception {KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null);KeyStore.Entry entry = keyStore.getEntry(alias, null);if (entry instanceof KeyStore.PrivateKeyEntry) {PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(encryptedData);}throw new Exception("No such key or not a private key entry");
}

4. 使用密钥进行签名和验证 ✍️

使用密钥对数据进行签名和验证,确保数据完整性和来源可信。

import java.security.Signature;public byte[] signData(String alias, byte[] data) throws Exception {KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null);KeyStore.Entry entry = keyStore.getEntry(alias, null);if (entry instanceof KeyStore.PrivateKeyEntry) {PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();Signature signature = Signature.getInstance("SHA256withRSA");signature.initSign(privateKey);signature.update(data);return signature.sign();}throw new Exception("No such key or not a private key entry");
}public boolean verifyData(String alias, byte[] data, byte[] signatureBytes) throws Exception {KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");keyStore.load(null);KeyStore.Entry entry = keyStore.getEntry(alias, null);if (entry instanceof KeyStore.PrivateKeyEntry) {PublicKey publicKey = ((KeyStore.PrivateKeyEntry) entry).getCertificate().getPublicKey();Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(publicKey);signature.update(data);return signature.verify(signatureBytes);}throw new Exception("No such key or not a private key entry");
}

5. 注意事项 ⚠️

  • 密钥别名: 每个密钥需要一个唯一的别名,用于在 Keystore 中标识和检索。
  • 用户认证: 如果设置了 setUserAuthenticationRequired(true),使用密钥时需要用户认证(如指纹、PIN、图案等)。如果认证方式被移除,密钥将永久失效。
  • 算法和模式支持: 不同设备和 Android 版本支持的算法和模式可能不同,建议检查设备支持情况。
  • 错误处理: 所有操作都应妥善处理异常,如 KeyStoreExceptionNoSuchAlgorithmExceptionInvalidKeyException 等。

6. 完整流程示例 💡

以下是一个完整的示例,从生成密钥到使用它进行加密和解密:

public void fullKeyUsageExample() {String alias = "my_key_alias";try {// 1. 生成密钥KeyPair keyPair = generateKeyPair(alias, false);// 2. 检查硬件支持checkKeySecurityLevel(alias);// 3. 加密数据String originalData = "Sensitive data";byte[] encryptedData = encryptData(alias, originalData.getBytes("UTF-8"));// 4. 解密数据byte[] decryptedData = decryptData(alias, encryptedData);String decryptedString = new String(decryptedData, "UTF-8");// 5. 签名数据byte[] signature = signData(alias, originalData.getBytes("UTF-8"));// 6. 验证签名boolean isValid = verifyData(alias, originalData.getBytes("UTF-8"), signature);} catch (Exception e) {e.printStackTrace();}
}
http://www.dtcms.com/a/395200.html

相关文章:

  • RBAC权限模型实战图解:绘制企业权限矩阵,告别混乱授权
  • 【ROS2】通讯协议接口 Interface
  • Spring —— 事务控制
  • 基于vue开发的背单词网站
  • javascript 角色跟踪实践
  • 第九周作业
  • 【ThinkPHP项目添加新页面完整解决方案】
  • Thinkphp框架相关漏洞扫描器(一)
  • 【网络通讯】Qt中使用Modbus Tcp协议(附Demo)
  • 在 macOS 上使用 Windows 快捷键指南
  • pd26 虚拟机 (Mac中文)
  • 本周的股指
  • (论文速读)生成式摄影:让AI理解相机的物理世界
  • ELK 企业级日志分析系统
  • 项目日记 -日志系统 -功能完善
  • install_docker.sh
  • opencv的DNN模块里
  • FPGA学习笔记——图像处理之对比度调节(线性调节)
  • SkyWalking 核心概念与智能探针工作原理深度揭秘(上)
  • leetcode hot100 简单难度 day02-刷题
  • ARP报文格式
  • 【论文速递】2025年第26周(Jun-22-28)(Robotics/Embodied AI/LLM)
  • 用【PinMe】轻松实现前端部署(文章附有演示案例)
  • 巨坑Spring ai 之spring-ai-starter-vector-store-elasticsearch
  • 【LeetCode 每日一题】2349. 设计数字容器系统
  • i.MX6ULL移植内核6.6(一)修改网络驱动和LCD驱动
  • vue-router(vue 路由)基本使用指南(一)
  • 酒店台账报表:押金原路退回与收支自动化指南-东方仙盟自动化
  • ⸢ 伍-Ⅰ⸥ ⤳ 默认安全治理实践:软件供应链安全治理
  • LeetCode 刷题【88. 合并两个有序数组、89. 格雷编码】