目錄
- 初始化向量
- 默認值
- 自訂值
- 空值
- 隨機加密
- 使用範例
- 下一步是什麼
- 安全提示
初始化向量
初始化向量是加密原語的固定大小輸入。通常要求它是隨機或僞隨機的。IV的重點是允許使用相同的密鑰來加密幾個不同的消息。
在大多數提供程序(包括提供程序和提供程序)中,塊算法模式(如CBC
中的AES
)都是必需的。AndroidKeyStore
BC
在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解密數據
要創建自定義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,默認情況下,AndroidKeyStore
Provider不允許使用自定義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)
但它不起作用(至少對於AES
和CBC
)。即使在禁用隨機化之後,Cipher
仍然會崩潰InvalidAlgorithmParameterException
並繼續需要默認初始化向量。
使用範例
讓我們使用帶有初始化矢量的對稱AES密鑰對消息進行加密和解密: