【问题标题】:AES/CBC/PKCS5Padding encryption with fixed IV (or without one)AES/CBC/PKCS5Padding 加密与固定 IV(或没有)
【发布时间】:2021-03-05 20:22:37
【问题描述】:

我需要编写一个使用 AES256 加密字符串的 Java 函数,使用 CBC 模式和 PKCS#5 填充。我已经获得了一个密钥和一些前后示例,因此我可以验证我的实现。这就是我所拥有的。我发现预期的结果正是这个在线生成器产生的结果:https://encode-decode.com/aes-256-cbc-encrypt-online/

我必须为我的 Cipher 实例提供的参数之一是初始化向量(“IV”)。如果我不指定一个,Java 会使用一个随机的,因此每次运行都会产生不同的结果,这不是我想要的行为。

上面的生成器不会向它的用户询问 IV,它仍然会产生与我的目标相同的结果。所以我想知道这怎么可能。人们是否倾向于使用相同的 IV(无论它是否安全),例如“0000000000000000”、“1234567812345678”(我都尝试过,以防万一)?或者有没有其他方法可以在不使用 IV 的情况下使用上述参数进行加密?

以防万一,这是我目前的代码:

package com.example.test;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AesTest {
    public static String key = "abcdefghijklmnopqrstuvwxyz012345";
    public static String email = "test@example.com";
    public static String initVector = "????????????????";

    public static void main(String []args) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");

            cipher.init(
                Cipher.ENCRYPT_MODE,
                new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"),
                new IvParameterSpec(initVector.getBytes(StandardCharsets.UTF_8))
            );

            byte[] encrypted = cipher.doFinal(email.getBytes());
            System.out.println(Base64.getEncoder().encodeToString(encrypted));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

【问题讨论】:

  • 我以这种方式使用硬编码字符串常量:IvParameterSpec("aaaabbbbccccdddd".getBytes("ASCII"));。它必须是 16 个字节。
  • CBC 模式需要 IV,您可以将其设置为静态。 ECB模式不需要IV,但有其他问题。也许更有趣的问题是为什么需要非随机密文。随机化加密提供了语义安全性,攻击者无法仅通过观察密文来推断明文(或明文块)的相等性。
  • 对 CBC 使用常量或可预测的 IV 是一个安全问题。 CBC 的 IV 必须是唯一且不可预测的。如果您需要确定性加密,请使用 AES-GCM-SIV 或 AES-SIV。

标签: java encryption cryptography aes


【解决方案1】:

是的,如果默认情况下不是随机的,通常使用全零 IV 作为默认值。初始化向量与 CBC 的第一个明文块进行异或运算,因此如果所有 bytes 都设置为零值,则简单地保留明文。

这可以通过对完整的明文块执行 ECB 和 CBC 来轻松检查。例如。 ASCII aaaaaaaaaaaaaaaa 的加密,即 16 个 a 字符将导致 ECB 的以下密文:

mExSanM1tVyEV1hjSqBlTZcuxSr1ybN1rpCtwYiyIYg=

这个是 CBC 的:

mExSanM1tVyEV1hjSqBlTcZkEjmYpQWV7Nmnr0thwhw=

很明显,第一个块必须相同,因为欧洲央行不使用 IV。所以第一个块加密是直接在明文上进行的,就像你期望的全零 IV 一样。

请注意,CBC 仅在 IV 对对手完全不可预测的情况下才提供语义安全性,即 IV 中的所有位对对手来说必须是随机的。

对于 Java,您可以像这样创建 IvParameterSpec

new IvParameterSpec(new byte[cipher.getBlockSize()]);

【讨论】:

  • new IvParameterSpec(new byte[cipher.getBlockSize()]); 是它的工作原理。谢谢!
  • 在许多情况下,IV 是在密文之前添加的,因此在解密前 128 位时用作 IV 来解密其余部分。
猜你喜欢
  • 2018-11-28
  • 2018-11-13
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 2022-11-16
相关资源
最近更新 更多