【译】Android中的安全数据— Android中的加密(第2部分)

目录

  • 锁屏
  • 选择一个钥匙
  • 密钥存储
  • 密钥生成
  • 密钥管理
  • 加密与解密
  • 使用范例
  • 下一步是什么
  • 安全提示

锁屏

如果要保护数据,请保护设备。

为了更加安全,在提供对任何应用程序功能的访问权限之前,我们可以要求用户设置其设备的锁屏(如果尚未设置)。另外,我们将在本系列的稍后部分中介绍的其他一些功能(例如指纹)也需要设置锁定屏幕。

还有一项特殊的系统服务-KeyguardManager可以帮助我们完成此任务。

 

isDeviceSecure 方法-检查设备是否用PIN,码型或密码保护。可从API 23获得。

isKeyguardSecure 方法-检查键盘锁是否由PIN,图案或密码保护,或者当前是否已锁定SIM卡。可从API 16获得。这不是最佳选择,因为它还在检查SIM卡是否被锁定,但总比没有好。

【译】Android中的安全数据— Android中的加密(第2部分)_第1张图片

 

 

秘密守护者,注册屏幕

现在,在onStart()“活动”中,只需检查设备是否已使用锁定屏幕进行保护,如果没有,则显示安全警报。

 

完整的源代码在这里。

选择一个钥匙

现在,当使用锁屏保护设备时,我们可以集中精力于应用程序敏感的数据保护,例如用户密码和机密(请参阅Android中的加密(第1部分),示例项目)。我们已经知道加密将用于此目的。首先,我们需要选择要使用的密钥(对称,非对称)和算法。

我们也知道,对称密钥可从Android 23+ API获得,而非对称密钥可从18+ API获得(请参阅Android中的加密(第1部分),Android密钥存储)。我们的选择是可以预测的,我们将使用非对称密钥,但是仍然选择哪种算法?让我们在文档中寻求帮助:

【译】Android中的安全数据— Android中的加密(第2部分)_第2张图片

 

 

Android密钥存储系统。可用的密码转换,格式为:算法/模式/填充

RSA-我们可以Cipher在API 18+设备上用于Android密钥存储非对称密钥的唯一一种可用算法。

密钥存储

在Android上,加密密钥存储在中KeyStore

 

还有一种架构getInstance("type")方法,该方法KeyStore通过遍历已注册安全提供者的列表(从最喜欢的 一个)开始创建具有给定类型的实例我们将搜索“ AndroidKeyStore ”类型。

还有另一个KeyStoreFabric方法:— 从指定的Provider 返回指定类型的对象。getInstance("type", "provider")KeyStore

基本上称之为:

val keyStore = KeyStore.getInstance(“ AndroidKeyStore”)keyStore.provider.name // AndroidKeyStore 
keyStore.type // AndroidKeyStorekeyStore.provider.name // AndroidKeyStore 
keyStore.type // AndroidKeyStore

与调用几乎相同:

val provider =“ AndroidKeyStore” 
val keyStore = KeyStore.getInstance(提供者,提供者)keyStore.provider.name // AndroidKeyStore 
keyStore.type // AndroidKeyStorekeyStore.provider.name // AndroidKeyStore 
keyStore.type // AndroidKeyStore

但是请注意,如果在不同的提供程序中有多个具有相同名称的注册类型,则getInstance(“type”)method将返回它们中的第一个匹配结果。这有两个不同的方面:

  • 您(或设备供应商)可以创建自己的Provider,并将其设置为最喜欢的,只需设置其位置即可(在本系列文章的后面部分中,您将了解如何进行设置)。从理论上讲,这可能会导致一些混乱,您会出错,而不是预期的密钥存储类型。
  • 另一方面,这种方法可用于解决一些兼容性问题,即系统将AndroidKeyStore在另一个Provider中添加新类型的实现,并保持相同的名称约定(还有另一个系统Provider,称为“ AndroidKeyStoreBCWorkaround”,我们将在“加密和解密”段落)。这使我们可以在不同的API上保持相同的工作代码,这很酷。

getInstance(“type”)到目前为止,该方法一直对我有效。文档样本也引用了此方法,因此,我建议您使用它来获取KeyStore实例,而不是其他getInstance(“type”, “provider”)方法。


如果您仍然有疑问或某些功能无法正常使用,请使用keyStore.provider.namekeyStore.type方法来验证所创建KeyStore实例的详细信息。


获取实例之后,您必须调用load(loadStoreParameter)方法,该方法将基于提供的加载密钥存储数据ProtectionParameter

保护参数可用于检查密钥存储数据的完整性,或用于保护敏感密钥存储数据(例如PrivateKey)的机密性。

对于AndroidKeyStore提供者,我们只需要null作为参数传递,系统将根据我们的应用程序标识符将数据加载到后台。

密钥生成

在Android上,非对称加密密钥的创建方式KeyPairGenerator如下:

 

与密钥存储区类似,有一种fabric getInstance(“algorithm”, “provider”) 方法,使用该方法来创建密钥。

该方法还有另一个简化版本getInstance(“algorithm”)不要使用它。这种方法在所有现有的提供程序中搜索算法,与密钥库不同,密钥存储区我们使用的是非常独特的“ AndroidKeyStore ”类型,算法名称在不同的提供程序中很常见(“ RSA ”几乎无处不在)。在这里,我们需要显式定义我们要使用的提供程序。


KeyPairGenerator实例必须使用规范初始化。在M之前KeyPairGeneratorSpec应使用class提供它:

 

在Android密钥存储区中,每个密钥必须具有一个标识符-alias。如果您尝试使用已存在的别名将密钥保存到密钥存储中,它将被新密钥覆盖。使用setAlias()builders方法提供别名。


非对称密钥必须使用证书签名。它主要用于客户端-服务器通信中,其中客户端(或服务器)正在验证证书,以确保服务器确实是他声称的身份(而不是中间人)。没有证书,您将无法保存非对称密钥。

如果在一个应用程序中都希望同时使用公钥和私钥,则只需创建一个伪造的,自签名的证书即可。

证书需要一个开始日期和结束日期(有效期),可以使用setStartDatesetEndDate构建器方法进行设置。另外,您还需要提供序列号和证书主题,可以与setSerialNumberand setSubjectbuilder方法一起使用。

伪造的自签名证书的打印输出:

数据:
  版本:3(0x2)
  序列号:1(0x1)
签名算法:sha256WithRSAEncryption 
  颁发者:CN = MASTER_KEY CA证书
  有效期
    :2017年11月7日12:59:12 GMT 
    不之后:Nov 7 12:59:12 2037 GMT 
  主题:CN = MASTER_KEY CA证书
  主题公钥信息:
    公钥算法:rsaEncryption 
      公钥:(2048位)
      模数:
        00:b8:bf:51:10:fc:8c:7f:39:31:cc:是:43:43:81:
        f1:8b:5a:55:94:c4:5c:8c:56:51:5a:63:85:36:87:
        ff:3e:f2:a2:3b:9c: b0:e0:a8:3d:5e:1b:41:9c:00:
        6e:02:b2:42:d0:9c:e8:2f:4a:52:62:ac:7d:8e:75:
        a0:5e:58:57:ae:a5:2e:2c:48:0c:7f:cc:1a:95:46:
        2b:2b:a7:5e:96:69:d7:98:b8:32: 92:7d:80:e9:19:
        07:da:52:1a:29:de:e1:fb:56:43:60:7f:28:ce:23:
        ca:ee:12:11:17: 1d:0b:86:76:1a:f1:99:69:81:01:
        b0:d3:2c:6b:e7:ac:4f:f2:f7:97:88:ef:94:7a:28:
        a4:66:6e:d5:29:67:84:12:2e:d3:d3:d7:a6:f6:d4:
        ed:81:a4:24:9b:f2:2a:77:16:d9: 0d:62:31:cd:cc:
        c4:f0:fc:be:8d:6a:b4:14:fc:26:6b:a0:06:79:95:
        40:68:0e:da:5e: 25:69:f9:36:fb:eb:35:a5:e2:63:
        81:f0:88:c2:8e:be:fc:8d:65:ce:99:7f:88:cf:af:
        50:9a:59:77:dc:cd:76:a9:8c:64:de:e8:57:3b:40:
        bf:72:21:2c:60:3d:e0:7b:dd:1e: 01:81:3a:24:81:
        d4:a9:e2:e8:af:80:f6:00:f6:7f:fd:9f:48:d2:f7:
        96:d1 
      指数:65537(0x10001)
签名算法:sha256WithRSAEncryption 
  1f:f6:40:99:1c:c1:62:19:89:1f:35:fb:18:7e:93:1e:99:8c:
  84 :a4:cd:7b:93:c7:23:46:7c:9a:50:aa:a5:f2:34:07:82:ef:
  45:28:ac:50:6c:4e:a2:92 :35:e4:75:97:12:47:ef:80:e4:6d:
  b2:61:e4:4b:7f:79:4c:7c:ee:87:a9:ad:23:a1:ec :e9:1a:2c:
  8e:0c:04:61:6c:4b:f3:6e:a6:ff:3e:bb:ad:45:5a:c5:0f:ae:
  4e:7c:d5:93 :d0:98:69:0d:3e:bc:22:1f:85:11:db:0e:80:66:
  ff:58:4d:57:2f:64:cb:f8:c0:07:c9 :91:f9:7a:a8:48:0e:f6:
  2a:08:d9:db:89:8c:5b:24:a7:ad:8a:08:f5:aa:3e:ac:99:31 :
  15:9d:93:4f:d1:c5:7b:2d:41:f2:7e:99:5b:38:b8:1d:1a:63:
  d2:57:34:10:4b:06:95 :39:41:df:22:38:8d:a9:4f:9b:05:86:
  46:09:02:51:fc:41:39:54:ca:dd:1d:8e:34:77:01:1b:87:51:
  22:9c:4b:e8:ae:d5:8d: d8:e6:e1:ba:18:41:94:ef:64:b6:63:
  d9:2e:06:ea:1e:ae:80:11:5f:71:b2:28:b0:cc: 4e:18:5e:3f:
  4f:28:ae:4f:90:57:1e:41:51:36:02:94:ad:9b:7d:03:25:e7:
  f7:8a:4d: 26

提供关键细节后,初始化KeyPairGenerator使用规范实例initialize(specification)方法。


在MKeyGenParameterSpec被介绍。它用于初始化非对称和对称密钥。KeyPairGeneratorSpec不推荐使用。

 

KeyGenParameterSpec要求指定密钥用法的目的。例如,使用创建的密钥KeyProperties.PURPOSE_ENCRYPT不能用于解密。

另外,您必须指定要与此密钥一起使用的阻止模式和加密填充(请参阅“ 加密,模式和填充)。使用setBlockModessetEncryptionPaddings构建方法。

不再需要手动定义伪造的证书,KeyGenParameterSpec它将自动执行。您仍然可以使用以下方法自定义默认值:

 

最后,当KeyPairGenerator实例使用规范初始化时,使用generateKeyPair()方法创建私钥-公钥对。在Android Key Store提供程序中,此方法将自动 保存 键入 KeyStore

密钥管理

KeyStore 提供的方法可以帮助我们管理保存的密钥:

 

getKey(“ alias”,“ password”) —返回具有给定别名的键,如果给定别名不存在或未标识与键相关的条目,则返回null。在Android Key Store中,不需要密码。

getCertificate(“ alias”) —返回证书,如果给定的别名不存在或不包含证书,则返回null。

deleteEntry(“ alias”) —删除具有给定别名的密钥。KeyStoreException
如果无法删除该条目,将被抛出。

完整的源代码在这里。

加密与解密

在Android上,加密和解密是通过进行的Cipher

 

有一种结构getInstance(“transformation”)方法,即在现有的提供程序之间搜索给定的转换(就像我们在上面回顾的其他加密组件中一样),应将其用于创建Cipher实例。

转换表示将用于加密或解密的算法,格式为:“算法/模式/填充”。


getInstance(“transformation”, "provider")这里还存在可以显式指定Provider的Method 。但是请注意,您不应将其与Cipher一起使用。

val转换=“ RSA / ECB / PKCS1Padding” 
val提供程序=“ AndroidKeyStore”// API 19 
val cipher:Cipher = Cipher.getInstance(transformation)
cipher.provider.name // AndroidOpenSSL// API 23,24 
val cipher:Cipher = Cipher.getInstance(transformation)
cipher.provider.name // AndroidKeyStoreBCWorkaroundval cipher:Cipher = Cipher.getInstance(transformation,provider)
//抛出java.security.NoSuchAlgorithmException:
//提供者AndroidKeyStore不提供RSA / ECB / PKCS1Padding// API 19 
val cipher:Cipher = Cipher.getInstance(transformation)
cipher.provider.name // AndroidOpenSSL// API 23,24 
val cipher:Cipher = Cipher.getInstance(transformation)
cipher.provider.name // AndroidKeyStoreBCWorkaroundval cipher:Cipher = Cipher.getInstance(transformation,provider)
//抛出java.security.NoSuchAlgorithmException:
//提供者AndroidKeyStore不提供RSA / ECB / PKCS1Padding

如您所见,从技术上讲,AndroidKeyStore提供程序不向密码提供RSA算法。而是有AndroidOpenSSLAndroidKeyStoreBCWorkaround提供者,他们知道如何AndroidKeyStore为该算法使用提供者密钥。


要开始使用Cipher实例,我们需要使用Key将其初始化以进行特定操作。使用init(mode, key)方法with对其Cipher.ENCRYPT_MODE进行初始化以进行加密:

 

或使用init(mode, key)with方法Cipher.DECRYPT_MODE来初始化用于解密的密码:

 

初始化后,使用doFinal(data)方法,使用此密码来处理加密或解密的数据。

您可以根据需要多次重新初始化创建的密码实例。

完整的源代码在这里。

使用范例

总结一下我们正在讨论的所有内容,让我们尝试加密和解密简单的“ Hello World”消息:

 

完整的源代码在这里。

你可能感兴趣的:(Android,Security,Android,安全,加密,数据安全,密钥)