【譯】Android中的安全數據— Android中的加密(第2部分)

目錄

  • 鎖屏
  • 選擇一個鑰匙
  • 密鑰存儲
  • 密鑰生成
  • 密鑰管理
  • 加密與解密
  • 使用範例
  • 下一步是什麼
  • 安全提示

鎖屏

如果要保護數據,請保護設備。

爲了更加安全,在提供對任何應用程序功能的訪問權限之前,我們可以要求用戶設置其設備的鎖屏(如果尚未設置)。另外,我們將在本系列的稍後部分中介紹的其他一些功能(例如指紋)也需要設置鎖定屏幕。

還有一項特殊的系統服務-KeyguardManager可以幫助我們完成此任務。

 

isDeviceSecure 方法-檢查設備是否用PIN,碼型或密碼保護。可從API 23獲得。

isKeyguardSecure 方法-檢查鍵盤鎖是否由PIN,圖案或密碼保護,或者當前是否已鎖定SIM卡。可從API 16獲得。這不是最佳選擇,因爲它還在檢查SIM卡是否被鎖定,但總比沒有好。

 

 

祕密守護者,註冊屏幕

現在,在onStart()“活動”中,只需檢查設備是否已使用鎖定屏幕進行保護,如果沒有,則顯示安全警報。

 

完整的源代碼在這裏。

選擇一個鑰匙

現在,當使用鎖屏保護設備時,我們可以集中精力於應用程序敏感的數據保護,例如用戶密碼和機密(請參閱Android中的加密(第1部分),示例項目)。我們已經知道加密將用於此目的。首先,我們需要選擇要使用的密鑰(對稱,非對稱)和算法。

我們也知道,對稱密鑰可從Android 23+ API獲得,而非對稱密鑰可從18+ API獲得(請參閱Android中的加密(第1部分),Android密鑰存儲)。我們的選擇是可以預測的,我們將使用非對稱密鑰,但是仍然選擇哪種算法?讓我們在文檔中尋求幫助:

 

 

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方法一起使用。

僞造的自簽名證書的打印輸出:

<span style="color:#292929">數據:
  版本: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</span>

提供關鍵細節後,初始化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”消息:

 

完整的源代碼在這裏。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章