使用 TripleDES 加密时将初始化向量 (IV) 附加到加密字节
Appending the initialization vector (IV) to the encrypted bytes when encrypting with TripleDES
我想向客户端发送加密令牌,我正在使用 javax.crypto.Cipher 进行加密。据我所知,不推荐使用 ECB 作为加密模式,因此我使用带有初始化向量的 CBC 和 TripleDES 作为密码方法。据我了解,有几点是正确的。
- 更重要的是 IV 是随机的并且每次加密都会初始化一个新的而不是保密的。
- 必须使用相同的 IV 来加密和解密令牌。
- 没有存储 IV 值的标准方法,在这方面每个实现都可能不同。
因此,对于这些,我通过存储附加到加密字节数组的 IV 来实现我的实现,并且在解密阶段,IV 从字节数组中切出并用于解密。以下是 Scala 代码,但在 Java.
中差别不大
val algorithmName = "TripleDES"
def encrypt(bytes: Array[Byte], secret: String): Array[Byte] = {
val secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), algorithmName)
val encipher = Cipher.getInstance(algorithmName + "/CBC/PKCS5Padding")
val iv = encipher.getParameters.getParameterSpec(classOf[IvParameterSpec])
encipher.init(Cipher.ENCRYPT_MODE, secretKey, iv)
encipher.doFinal(bytes) ++ iv.getIV
}
def decrypt(bytes: Array[Byte], secret: String): Array[Byte] = {
val secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), algorithmName)
val encipher = Cipher.getInstance(algorithmName + "/CBC/PKCS5Padding")
val ivIndex = bytes.length - 8
val iv = new IvParameterSpec(bytes, ivIndex, 8)
encipher.init(Cipher.DECRYPT_MODE, secretKey, iv)
encipher.doFinal(bytes, 0, ivIndex)
}
此外字节数组是encoded/decoded
org.apache.commons.codec.binary.Base64.encodeBase64String / decodeBase64 发送给客户端之前。
所以我的问题是,这种将 IV 存储在与存储加密字符串相同的字节数组中的方法有什么错误或危险吗?有没有更好的替代方法来存储 IV:s?
IV 的唯一目的是防止攻击者能够使用密文中的模式来推断有关明文的信息(参见 semantic security),方法是确保使用相同密钥加密的两个相同的明文, 对于不同的 IVs 会有明显不同的密文。
不知道密钥的攻击者无法从 IV 获得任何收益,因为 IV 在实际加密操作之前和解密操作之后使用(通常;我想不出任何使用的密码或模式IV 不同,但它们可能存在。不过,带有 CBC 的 DES 绝对不是其中之一)。因此,将您的 IV 包含在您的密文中并没有什么坏处,并且将 IV 附加到密文是一种非常常见的做法。
我想向客户端发送加密令牌,我正在使用 javax.crypto.Cipher 进行加密。据我所知,不推荐使用 ECB 作为加密模式,因此我使用带有初始化向量的 CBC 和 TripleDES 作为密码方法。据我了解,有几点是正确的。
- 更重要的是 IV 是随机的并且每次加密都会初始化一个新的而不是保密的。
- 必须使用相同的 IV 来加密和解密令牌。
- 没有存储 IV 值的标准方法,在这方面每个实现都可能不同。
因此,对于这些,我通过存储附加到加密字节数组的 IV 来实现我的实现,并且在解密阶段,IV 从字节数组中切出并用于解密。以下是 Scala 代码,但在 Java.
中差别不大val algorithmName = "TripleDES"
def encrypt(bytes: Array[Byte], secret: String): Array[Byte] = {
val secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), algorithmName)
val encipher = Cipher.getInstance(algorithmName + "/CBC/PKCS5Padding")
val iv = encipher.getParameters.getParameterSpec(classOf[IvParameterSpec])
encipher.init(Cipher.ENCRYPT_MODE, secretKey, iv)
encipher.doFinal(bytes) ++ iv.getIV
}
def decrypt(bytes: Array[Byte], secret: String): Array[Byte] = {
val secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), algorithmName)
val encipher = Cipher.getInstance(algorithmName + "/CBC/PKCS5Padding")
val ivIndex = bytes.length - 8
val iv = new IvParameterSpec(bytes, ivIndex, 8)
encipher.init(Cipher.DECRYPT_MODE, secretKey, iv)
encipher.doFinal(bytes, 0, ivIndex)
}
此外字节数组是encoded/decoded org.apache.commons.codec.binary.Base64.encodeBase64String / decodeBase64 发送给客户端之前。
所以我的问题是,这种将 IV 存储在与存储加密字符串相同的字节数组中的方法有什么错误或危险吗?有没有更好的替代方法来存储 IV:s?
IV 的唯一目的是防止攻击者能够使用密文中的模式来推断有关明文的信息(参见 semantic security),方法是确保使用相同密钥加密的两个相同的明文, 对于不同的 IVs 会有明显不同的密文。
不知道密钥的攻击者无法从 IV 获得任何收益,因为 IV 在实际加密操作之前和解密操作之后使用(通常;我想不出任何使用的密码或模式IV 不同,但它们可能存在。不过,带有 CBC 的 DES 绝对不是其中之一)。因此,将您的 IV 包含在您的密文中并没有什么坏处,并且将 IV 附加到密文是一种非常常见的做法。