【譯】Android中的安全數據-初始化向量

目錄

  • 初始化向量
  • 默認值
  • 自訂值
  • 空值
  • 隨機加密
  • 使用範例
  • 下一步是什麼
  • 安全提示

初始化向量

初始化向量是加密原語的固定大小輸入。通常要求它是隨機或僞隨機的。IV的重點是允許使用相同的密鑰來加密幾個不同的消息。

在大多數提供程序(包括提供程序和提供程序)中,塊算法模式(如CBC中的AES)都是必需的。AndroidKeyStoreBC


在API 18上,BC如果在解密過程中未指定IV,則使用默認Java的提供程序密鑰Cipher將落入IllegalArgumentException

 

 

在具有AndroidKeyStore提供者密鑰的API 23上,InvalidKeyException將引發:

<span style="color:#292929">InvalidKeyException:解密時需要IV。使用IvParameterSpec或AlgorithmParameters提供它。</span>

默認值

實現初始化向量支持的最簡單方法是使用由密碼在加密過程中生成的字節數組數據。可以使用以下cipher.getIV()方法進行檢索:

cipher.init(Cipher.ENCRYPT_MODE,key)
val iv = cipher.iv //返回自動生成的IV值... 
//使用密碼加密數據... 
//使用密碼加密數據

注意,默認值是在Cipher初始化期間生成的,因此cipher.init()必須首先調用它,否則cipher.getIv()將返回空數據。


然後,在解密期間,使用IvParameterSpec根據生成的IV值創建的Cipher進行初始化:

val ivSpec = IvParameterSpec(iv)
cipher.init(Cipher.DECRYPT_MODE,key,ivSpec)... 
//使用IV初始化的Cipher解密數據... 
//使用IV初始化的Cipher解密數據

Salt值一樣,初始化向量可以與加密數據一起存儲在公共存儲中。

存儲IV數據的一種可能方法是將數據添加到加密結果中:

 

並在解密之前根據加密數據進行解析:

 

完整的源代碼在這裏。

自訂值

正如Dorian Cussen在其博客中提到的IV,由提供的默認值Cipher主要取決於Provider的實現。

未實現時可能會遇到這種情況cipher.getIV() -返回“空”或null數組。

爲了安全起見並避免此類不愉快的時刻,請使用SecureRandomclass 明確聲明一個初始化向量。


要創建自定義IV值,請使用類中的nextBytes(byte[] key)方法SecureRandom

<span style="color:#292929">val iv = ByteArray(ivLength)
SecureRandom()。nextBytes(iv)</span>

ivLength依賴於操作模式。對於大多數模式,包括CBC,IV必須與其中的塊具有相同的長度 

AES算法使用128位塊,因此初始化矢量的長度等於128位(ivLength = 16// bytes)。


生成自定義IV值時,只需Cipher使用它初始化實例:

<span style="color:#292929">cipher.init(Cipher.ENCRYPT_MODE,密鑰,IvParameterSpec(iv))
cipher.init(Cipher.DECRYPT_MODE,密鑰,IvParameterSpec(iv))</span>

注意,生成的值必須被傳遞到init()用於方法加密和解密模式。

空值

可能(但不建議)作弊Cipher。無需在加密之前每次都生成新的隨機初始化向量數據,然後在解密之前進行保存和解析,而是將IV作爲數組初始化一次,具有固定長度的靜態值,並且可以隨時隨地使用:

//創建一個16字節的數組,填充爲0 [0,0,0,0 ..0] 
val iv = ByteArray(16)//在加密和解密期間將此數組用作IV數據
cipher.init(Cipher.ENCRYPT_MODE,key,IvParameterSpec(iv))
cipher.init(Cipher.DECRYPT_MODE,key,IvParameterSpec(iv))//在加密和解密期間將此數組用作IV數據
cipher.init(Cipher.ENCRYPT_MODE,key,IvParameterSpec(iv))
cipher.init(Cipher.DECRYPT_MODE,key,IvParameterSpec(iv))

請記住,這種實現扼殺了IV的本質。

隨機加密

爲了保護用戶數據免於使用不正確的(不是隨機的或空的)IV,默認情況下,AndroidKeyStoreProvider不允許使用自定義IV值:

val iv = ByteArray(16)
cipher.init(Cipher.ENCRYPT_MODE,key,IvParameterSpec(iv))//將拋出InvalidAlgorithmParameterException:調用者提供的IV //不允許
cipher.doFinal(data.toByteArray())//將拋出InvalidAlgorithmParameterException:調用者提供的IV //不允許
cipher.doFinal(data.toByteArray())

在API 23上,該setRandomizedEncryptionRequired方法已添加到KeyGenParameterSpec類中,該方法應允許您控制IV是否可以自定義。從文檔:

設置是否必須將使用此密鑰進行的加密充分隨機化,以便每次都爲相同的明文生成不同的密文。

當需要IND-CPA時:在使用IV的塊模式(例如GCM,CBC和CTR)中,加密時將拒絕調用方提供的IV,以確保僅使用隨機IV。

val builder = KeyGenParameterSpec.Builder()//強制僅使用由IV生成的默認生成。
// 默認值。
builder.setRandomizedEncryptionRequired(true)//啓用自定義生成的IV。
//不起作用。
builder.setRandomizedEncryptionRequired(false)//強制僅使用由IV生成的默認生成。
// 默認值。
builder.setRandomizedEncryptionRequired(true)//啓用自定義生成的IV。
//不起作用。
builder.setRandomizedEncryptionRequired(false)

但它不起作用(至少對於AESCBC)。即使在禁用隨機化之後,Cipher仍然會崩潰InvalidAlgorithmParameterException並繼續需要默認初始化向量。

使用範例

讓我們使用帶有初始化矢量的對稱AES密鑰對消息進行加密和解密:

 

完整的源代碼在這裏。

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