简体   繁体   English

AES/CBC/PKCS5Padding 加密与固定 IV(或没有)

[英]AES/CBC/PKCS5Padding encryption with fixed IV (or without one)

I need to code a Java function that encrypts a string using AES256, with CBC mode and PKCS#5 padding.我需要编码一个 Java function 使用 AES256 加密字符串,使用 CBC 模式和 PKCS#5 填充。 I've been given a secret key and some before-after examples so I can validate my implementation.我已经获得了一个密钥和一些前后示例,因此我可以验证我的实现。 This is all I've got.这就是我所拥有的。 I found that the expected results are exactly the one produced by this online generator: https://encode-decode.com/aes-256-cbc-encrypt-online/我发现预期的结果正是这个在线生成器产生的结果: https://encode-decode.com/aes-256-cbc-encrypt-online/

One of the parameters I must provide my Cipher instance with is an initialization vector ("IV").我必须为我的 Cipher 实例提供的参数之一是初始化向量(“IV”)。 If I don't specify one, Java uses a random one, and therefore produces a different result on each run, which is not the behavior I want.如果我没有指定一个,Java 使用一个随机的,因此每次运行都会产生不同的结果,这不是我想要的行为。

The above generator does not ask its users for an IV, and still it produces the same results as my target.上面的生成器不会向它的用户询问 IV,它仍然会产生与我的目标相同的结果。 So I'd like to know how it is possible.所以我想知道这怎么可能。 Do people tend to use the same IV (regardless of whether it's secure or not), something like "0000000000000000", "1234567812345678" (I tried both, just in case)?人们是否倾向于使用相同的 IV(无论它是否安全),例如“0000000000000000”、“1234567812345678”(我都尝试过,以防万一)? Or is there any other way to encrypt with the above parameters without using an IV?或者有没有其他方法可以在不使用 IV 的情况下使用上述参数进行加密?

Just in case, here is my code for the moment:以防万一,这是我目前的代码:

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();
        }
    }
}

Yes, generally an all zero IV is used as default, if it is not randomized by default.是的,如果默认情况下不是随机的,通常使用全零 IV 作为默认值。 The initialization vector is XOR'ed with the first plaintext block for CBC, so if all bytes are set to value zero then the plaintext is simply kept.初始化向量与 CBC 的第一个明文块进行异或运算,因此如果所有字节都设置为零值,则简单地保留明文。

This can be easily checked by performing both ECB and CBC on a full block of plaintext.这可以通过对完整的明文块同时执行 ECB 和 CBC 来轻松检查。 Eg encryption of ASCII aaaaaaaaaaaaaaaa , ie 16 a characters will result in the following ciphertext for ECB:例如,ASCII aaaaaaaaaaaaaaaa的加密,即 16 a字符将导致 ECB 的以下密文:

mExSanM1tVyEV1hjSqBlTZcuxSr1ybN1rpCtwYiyIYg=

and this one for CBC:这是CBC的:

mExSanM1tVyEV1hjSqBlTcZkEjmYpQWV7Nmnr0thwhw=

Quite clearly the first blocks must be identical, as ECB doesn't use an IV.很明显,第一个块必须相同,因为欧洲央行不使用 IV。 So the first block encrypt is directly over the plaintext, just as you expect with an all zero IV.所以第一个块加密是直接在明文上进行的,正如您对全零 IV 的期望一样。

Note that CBC only provides semantic security if the IV is fully unpredictable to an adversary, ie all bits in the IV must appear random to an adversary.请注意,CBC 仅在 IV 对对手完全不可预测时才提供语义安全性,即 IV 中的所有位对对手来说必须是随机的。

For Java you can just create an IvParameterSpec like this:对于 Java,您可以像这样创建一个IvParameterSpec

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM