当前位置:   article > 正文

Android密钥库(AndroidKeyStore)使用_android keystore

android keystore

一、KeyStore描述

在 Android 开发中,KeyStore 是一个用于存储密钥和证书的安全容器。它提供了一种安全的方式来存储敏感信息,如密钥对、数字证书等,以防止它们被未授权的应用或攻击者访问。

KeyStore 通常用于加密数据、数字签名、TLS/SSL 连接等场景。

Android 开发中使用 KeyStore 的常见场景:

  1. 存储密钥对:可以使用 KeyStore 来生成和存储公钥和私钥的密钥对。这些密钥对通常用于数据加密、数字签名等操作。

  2. 存储数字证书:可以使用 KeyStore 来存储数字证书,用于验证身份、建立安全连接等场景。

  3. 安全存储密码:可以使用 KeyStore 来安全地存储密码、凭证、API 密钥等敏感信息,以防止它们被未授权的应用或攻击者访问。

  4. TLS/SSL 连接:可以使用 KeyStore 来管理客户端证书和受信任的 CA 证书,用于安全通信、建立 TLS/SSL 连接等操作。

  5. 双因素身份验证:可以使用 KeyStore 来存储和管理双因素身份验证所需的密钥和证书,用于提高身份验证的安全性。

在 Android 中,KeyStore 是通过 java.security.KeyStore 类来实现的。可以使用该类来创建、加载、存储和检索密钥和证书。Android 提供了特定于 Android 平台的 KeyStore 实现,称为 AndroidKeyStore,它提供了更高级的安全功能,如硬件支持、密钥链随机生成等。

二、KeyStore使用

  1. // 密钥库类型
  2. private const val PP_KEYSTORE_TYPE = "AndroidKeyStore"
  3. // 密钥库别名
  4. private const val PP_KEYSTORE_ALIAS = "pp_keystore_alias"
  5. // 加密算法标准算法名称
  6. private const val PP_TRANSFORMATION = "RSA/ECB/PKCS1Padding"

1. 生成公私钥密钥对

  1. /**
  2. * 触发生成密钥对.
  3. *
  4. * 生成RSA 密钥对,包括公钥和私钥
  5. *
  6. * @return KeyPair 密钥对,包含公钥和私钥
  7. */
  8. private fun generateKey(): KeyPair {
  9. // 创建密钥生成器
  10. val keyPairGenerator = KeyPairGenerator.getInstance(
  11. KeyProperties.KEY_ALGORITHM_RSA,
  12. PP_KEYSTORE_TYPE
  13. )
  14. // 配置密钥生成器参数
  15. KeyGenParameterSpec.Builder(
  16. PP_KEYSTORE_ALIAS,
  17. KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
  18. )
  19. .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
  20. .setDigests(KeyProperties.DIGEST_SHA256)
  21. .build().run {
  22. keyPairGenerator.initialize(this)
  23. }
  24. // 生成密钥对
  25. return keyPairGenerator.generateKeyPair()
  26. }

通过上述代码使用“AndroidKeyStore”类型的密钥库,生成 RSA 密钥对,包括公钥和私钥。

后续针对数据的加密和解密就需要使用此时密钥库中生成的 公钥和私钥。

2. AndroidKeyStore 密钥库得到密钥对

2.1 公钥
  1. /**
  2. * 获取公钥.
  3. *
  4. * @return 公钥
  5. */
  6. private fun getPublicKey(): PublicKey? {
  7. val keyStore = KeyStore.getInstance(PP_KEYSTORE_TYPE).apply {
  8. load(null)
  9. }
  10. // 判断密钥是否存在
  11. if (!keyStore.containsAlias(PP_KEYSTORE_ALIAS)) {
  12. return generateKey().public
  13. }
  14. val entry = keyStore.getEntry(PP_KEYSTORE_ALIAS, null)
  15. if (entry !is KeyStore.PrivateKeyEntry) {
  16. return null
  17. }
  18. return entry.certificate.publicKey
  19. }
2.2 私钥
  1. /**
  2. * 获取私钥.
  3. *
  4. * @return 密钥
  5. */
  6. private fun getPrivateKey(): PrivateKey? {
  7. val keyStore = KeyStore.getInstance(PP_KEYSTORE_TYPE).apply {
  8. load(null)
  9. }
  10. // 判断密钥是否存在
  11. if (!keyStore.containsAlias(PP_KEYSTORE_ALIAS)) {
  12. return generateKey().private
  13. }
  14. val entry = keyStore.getEntry(PP_KEYSTORE_ALIAS, null)
  15. if (entry !is KeyStore.PrivateKeyEntry) {
  16. return null
  17. }
  18. return entry.privateKey
  19. }

3. 加密、解密

3.1 加密
  1. /**
  2. * 数据加密.
  3. *
  4. * @param data 原始数据,字符串
  5. * @return 加密数据,字节数组
  6. */
  7. fun encryptData(data: String): ByteArray {
  8. return encryptDataInternal(data.toByteArray())
  9. }
  10. /**
  11. * 数据加密.
  12. *
  13. * @param bytes 原始数据
  14. * @return 加密数据
  15. */
  16. private fun encryptDataInternal(bytes: ByteArray): ByteArray {
  17. return getPublicKey()?.run {
  18. val cipher = Cipher.getInstance(PP_TRANSFORMATION)
  19. cipher.init(Cipher.ENCRYPT_MODE, this)
  20. cipher.doFinal(bytes)
  21. } ?: byteArrayOf()
  22. }
3.2 解密
  1. /**
  2. * 数据解密.
  3. *
  4. * @param bytes 加密数据
  5. * @return 原始数据,字符串
  6. */
  7. fun decryptData(bytes: ByteArray): String {
  8. return String(decryptDataInternal(bytes))
  9. }
  10. /**
  11. * 数据解密.
  12. *
  13. * @param bytes 加密数据
  14. * @return 原始数据
  15. */
  16. private fun decryptDataInternal(bytes: ByteArray): ByteArray {
  17. return getPrivateKey()?.run {
  18. val cipher = Cipher.getInstance(PP_TRANSFORMATION)
  19. cipher.init(Cipher.DECRYPT_MODE, this)
  20. cipher.doFinal(bytes)
  21. } ?: byteArrayOf()
  22. }

描述下Cipher对象参数:

Cipher.getInstance(String transformation) 是用于获取 Cipher 对象的静态方法。它接受一个字符串参数 transformation,该参数指定了要使用的加密算法、模式和填充方式

3.3 加解密对象Clpher参数transformation介绍

transformation 参数的格式通常为 "algorithm/mode/padding",其中:

  • algorithm:指定加密算法的名称,如 AES、DES、RSA 等。
  • mode:指定加密模式,如 ECB、CBC、CTR 等。
  • padding:指定填充方式,如 PKCS5Padding、NoPadding 等。

例如我们当前工具类,要使用 RSA 算法、ECB 模式和 PKCS5Padding 填充方式进行加密,你可以使用如下的 transformation 参数:

private const val PP_TRANSFORMATION = "RSA/ECB/PKCS1Padding"

然后调用 Cipher.getInstance(transformation) 方法来获取对应的 Cipher 对象,用于执行加密和解密操作。

在 Android 中,常见的加密算法和模式包括:

  • 加密算法:AES、DES、RSA 等。
  • 加密模式:ECB、CBC、CTR、GCM 等。
  • 填充方式:PKCS5Padding、NoPadding 等。

3.3.1 Android支持的transformation类型,参考Cipher文档:


Cipher  |  Android Developers

3.3.2 注意:padding使用OAEP填充方式
private const val PP_TRANSFORMATION = "RSA/ECB/OAEPwithSHA-512andMGF1Padding"

如果填充模式为OAEP,需要修改的代码如下

1. 密钥对生成需要修改代码
  1. // padding: 主要是生成KeySotre密钥对,填充模式:ENCRYPTION_PADDING_RSA_OAEP
  2. .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
  3. // mode: ECB
  4. .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
  5. // 消息摘要只支持512和256,OAEPwithSHA-512andMGF1Padding
  6. .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
2. 加密需要修改代码
  1. /**
  2. * 数据加密.
  3. *
  4. * @param bytes 原始数据
  5. * @return 加密数据
  6. */
  7. private fun encryptDataInternal(bytes: ByteArray): ByteArray {
  8. return getPublicKey()?.run {
  9. val cipher = Cipher.getInstance(TRANSLATOR_TRANSFORMATION)
  10. cipher.init(
  11. Cipher.ENCRYPT_MODE, this,
  12. OAEPParameterSpec(
  13. "SHA-512",
  14. "MGF1",
  15. MGF1ParameterSpec.SHA1,
  16. PSource.PSpecified.DEFAULT
  17. )
  18. )
  19. cipher.doFinal(bytes)
  20. } ?: byteArrayOf()
  21. }
注意


Android平台在使用RSA/ECB/OAEPWithSHA-256AndMGF1Padding加密模式时,对MGF1摘要算法的支持存在一些限制。

  1. Android密钥库(AndroidKeyStore)在实现OAEP加密时,只支持使用SHA-1作为MGF1摘要算法,不支持SHA-256或更高版本的SHA算法作为MGF1。
  2. 尽管Android开发者文档中给出了使用OAEPParameterSpec设置不同摘要算法的示例代码加密介绍官网,但实际上如果将MGF1摘要设置为SHA-256或更高,会抛出java.security.InvalidAlgorithmParameterException异常。
  3. 这一限制存在于Android框架的实现中,目的是为了与其他系统保持加密算法的互操作。
  4. 因此,在Android平台上使用RSA/ECB/OAEPWithSHA-256AndMGF1Padding加密时,开发者需要将MGF1摘要算法显式设置为SHA-1,而不能使用SHA-256或更高版本,否则会导致异常。

提示:正常我们需要对加密的数据进行本地存储,上述加密数据是ByteArray,字节数组不太适合本地存储,因此我们可以通过Base64将ByteArray数据转换为字符串进行保存,取出数据之时再做Base64解码。

  1. // ByteArray转Base64字符串
  2. Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
  3. // Base64字符串转ByteArray
  4. Base64.decode(encryptedString, Base64.DEFAULT)

到此为止,基本的使用和简单的参数描述已经完成。

4. 完整代码

  1. object KeyStoreHelper {
  2. // 密钥库类型
  3. private const val PP_KEYSTORE_TYPE = "AndroidKeyStore"
  4. // 密钥库别名
  5. private const val PP_KEYSTORE_ALIAS = "pp_keystore_alias"
  6. // 加密算法标准算法名称
  7. private const val PP_TRANSFORMATION = "RSA/ECB/PKCS1Padding"
  8. /**
  9. * 数据加密.
  10. *
  11. * @param data 原始数据,字符串
  12. * @return 加密数据,字节数组
  13. */
  14. fun encryptData(data: String): ByteArray {
  15. return encryptDataInternal(data.toByteArray())
  16. }
  17. /**
  18. * 数据解密.
  19. *
  20. * @param bytes 加密数据
  21. * @return 原始数据,字符串
  22. */
  23. fun decryptData(bytes: ByteArray): String {
  24. return String(decryptDataInternal(bytes))
  25. }
  26. /**
  27. * 数据加密.
  28. *
  29. * @param bytes 原始数据
  30. * @return 加密数据
  31. */
  32. private fun encryptDataInternal(bytes: ByteArray): ByteArray {
  33. return getPublicKey()?.run {
  34. val cipher = Cipher.getInstance(PP_TRANSFORMATION)
  35. cipher.init(Cipher.ENCRYPT_MODE, this)
  36. cipher.doFinal(bytes)
  37. } ?: byteArrayOf()
  38. }
  39. /**
  40. * 数据解密.
  41. *
  42. * @param bytes 加密数据
  43. * @return 原始数据
  44. */
  45. private fun decryptDataInternal(bytes: ByteArray): ByteArray {
  46. return getPrivateKey()?.run {
  47. val cipher = Cipher.getInstance(PP_TRANSFORMATION)
  48. cipher.init(Cipher.DECRYPT_MODE, this)
  49. cipher.doFinal(bytes)
  50. } ?: byteArrayOf()
  51. }
  52. /**
  53. * 获取公钥.
  54. *
  55. * @return 公钥
  56. */
  57. private fun getPublicKey(): PublicKey? {
  58. val keyStore = KeyStore.getInstance(PP_KEYSTORE_TYPE).apply {
  59. load(null)
  60. }
  61. // 判断密钥是否存在
  62. if (!keyStore.containsAlias(PP_KEYSTORE_ALIAS)) {
  63. return generateKey().public
  64. }
  65. val entry = keyStore.getEntry(PP_KEYSTORE_ALIAS, null)
  66. if (entry !is KeyStore.PrivateKeyEntry) {
  67. return null
  68. }
  69. return entry.certificate.publicKey
  70. }
  71. /**
  72. * 获取私钥.
  73. *
  74. * @return 密钥
  75. */
  76. private fun getPrivateKey(): PrivateKey? {
  77. val keyStore = KeyStore.getInstance(PP_KEYSTORE_TYPE).apply {
  78. load(null)
  79. }
  80. // 判断密钥是否存在
  81. if (!keyStore.containsAlias(PP_KEYSTORE_ALIAS)) {
  82. return generateKey().private
  83. }
  84. val entry = keyStore.getEntry(PP_KEYSTORE_ALIAS, null)
  85. if (entry !is KeyStore.PrivateKeyEntry) {
  86. return null
  87. }
  88. return entry.privateKey
  89. }
  90. /**
  91. * 触发生成密钥对.
  92. *
  93. * 生成RSA 密钥对,包括公钥和私钥
  94. *
  95. * @return KeyPair 密钥对,包含公钥和私钥
  96. */
  97. private fun generateKey(): KeyPair {
  98. // 创建密钥生成器
  99. val keyPairGenerator = KeyPairGenerator.getInstance(
  100. KeyProperties.KEY_ALGORITHM_RSA,
  101. PP_KEYSTORE_TYPE
  102. )
  103. // 配置密钥生成器参数
  104. KeyGenParameterSpec.Builder(
  105. PP_KEYSTORE_ALIAS,
  106. KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
  107. )
  108. .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
  109. .setDigests(KeyProperties.DIGEST_SHA256)
  110. .build().run {
  111. keyPairGenerator.initialize(this)
  112. }
  113. // 生成密钥对
  114. return keyPairGenerator.generateKeyPair()
  115. }
  116. }

参考

1. Android 密钥库系统

2. Cipher API文档

3. AndroidKeyStoreRSACipherSpi源码

4. 加密参考官网地址

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/783100
推荐阅读
相关标签
  

闽ICP备14008679号