【译】Android中的安全数据-初始化向量
目录
- 初始化向量
- 默认值
- 自订值
- 空值
- 随机加密
- 使用范例
- 下一步是什么
- 安全提示
初始化向量
初始化向量是加密原语的固定大小输入。通常要求它是随机或伪随机的。IV的重点是允许使用相同的密钥来加密几个不同的消息。
在大多数提供程序(包括提供程序和提供程序)中,块算法模式(如CBC
中的AES
)都是必需的。AndroidKeyStore
BC
在API 18上,BC
如果在解密过程中未指定IV,则使用默认Java的提供程序密钥Cipher
将落入IllegalArgumentException
:
在具有AndroidKeyStore
提供者密钥的API 23上,InvalidKeyException
将引发:
InvalidKeyException:解密时需要IV。使用IvParameterSpec或AlgorithmParameters提供它。
默认值
实现初始化向量支持的最简单方法是使用由密码在加密过程中生成的字节数组数据。可以使用以下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
数组。
为了安全起见并避免此类不愉快的时刻,请使用SecureRandom
class 明确声明一个初始化向量。
要创建自定义IV
值,请使用类中的nextBytes(byte[] key)
方法SecureRandom
:
val iv = ByteArray(ivLength)SecureRandom()。nextBytes(iv)
在ivLength
依赖于操作模式。对于大多数模式,包括CBC,IV必须与其中的块具有相同的长度 。
AES算法使用128位块,因此初始化矢量的长度等于128位(
ivLength = 16// bytes
)。
生成自定义IV值时,只需Cipher
使用它初始化实例:
cipher.init(Cipher.ENCRYPT_MODE,密钥,IvParameterSpec(iv))cipher.init(Cipher.DECRYPT_MODE,密钥,IvParameterSpec(iv))
注意,生成的值必须被传递到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密钥对消息进行加密和解密:
完整的源代码在这里。
更多相关文章
- Android中加密机制
- Android(安卓)项目开发实战:图案解锁
- 自定义Radio样式配合ListView
- Android之TabHost组件美化
- Android(安卓)FFmpeg
- 下拉刷新和加载更多
- Android在布局文件指定位置动态增加删除布局
- Preference 摘
- 使用DatePicker以及TimePicker显示当前日期和时间