目录
- 初始化向量
- 默认值
- 自订值
- 空值
- 随机加密
- 使用范例
- 下一步是什么
- 安全提示
初始化向量
初始化向量是加密原语的固定大小输入。通常要求它是随机或伪随机的。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密钥对消息进行加密和解密: