简体   繁体   English

Java AES-256-CBC无法正常工作

[英]Java AES-256-CBC not working as expected

Created a new class to test something with AES in CBC and CTR mode. 创建了一个新类,以CBC和CTR模式使用AES测试某些内容。 So with this code, CTR is working fine, but CBC returns empty arrays. 因此,使用此代码,CTR可以正常工作,但是CBC返回空数组。 Not sure why this happens, hope somebody can explain that. 不知道为什么会这样,希望有人能解释一下。

import org.junit.Before;
import org.junit.Test;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import java.security.*;
import java.util.Map;

public class AES_retest {

    private static final String plaintext = "Hallo Welt";
    private static final String key = "C0BAE23DF8B51807B3E17D21925FADF2";
    private String iv_string = "I need a initialization vector...";
    private Cipher encrypt_cipher_ctr, decrypt_cipher_ctr, encrypt_cipher_cbc, decrypt_cipher_cbc;

    @Before
    public void prepare_Test() throws GeneralSecurityException {
        byte[] tmp = new byte[16];
        System.arraycopy(iv_string.getBytes(), 0, tmp, 0, 16);

        removeCryptographyRestrictions();

        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
        //initialization vector
        IvParameterSpec iv = new IvParameterSpec(tmp);
        encrypt_cipher_cbc = Cipher.getInstance("AES/CBC/PKCS5Padding");
        encrypt_cipher_cbc.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
        decrypt_cipher_cbc = Cipher.getInstance("AES/CBC/PKCS5Padding");
        decrypt_cipher_cbc.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
    }

    @Test
    public void multiple_CBC_update() throws BadPaddingException, IllegalBlockSizeException {
        System.out.println("Testing CBC:");
        System.out.println("Plaintext: " + plaintext);
        System.out.println("Plaintext as HEX: " + bytesToHex(plaintext.getBytes()));
        byte[] first_encryption = encrypt_cipher_cbc.update(plaintext.getBytes());
        byte[] second_encryption = encrypt_cipher_cbc.update(plaintext.getBytes());
        encrypt_cipher_cbc.doFinal();
        byte[] first_decryption = decrypt_cipher_cbc.update(first_encryption);
        byte[] second_decryption = decrypt_cipher_cbc.update(second_encryption);
        decrypt_cipher_cbc.doFinal();
        System.out.println("First encryption: " + bytesToHex(first_encryption));
        System.out.println("Second encryption: " + bytesToHex(second_encryption));
        System.out.println("First decryption: " + bytesToHex(first_decryption));
        System.out.println("Second decryption: " + bytesToHex(second_decryption));
    }
}

Because I want to use both CTR and CBC in my program I would like to use a AES implementation that can handle both at the same time. 因为我想在程序中同时使用CTR和CBC,所以我想使用可以同时处理两者的AES实现。 Is this possible with the given implementation? 对于给定的实现,这可能吗?

I would suppose that it has something to do with the defined Padding. 我想这与定义的填充有关。 If I use NoPadding in decryption, the Cipher text is decrypted correctly, but the padding is not removed. 如果我在解密中使用NoPadding,则密码文本将正确解密,但不会删除填充。 If I use PCS5Padding on decryption, a empty array or null is returned. 如果在解密时使用PCS5Padding,则返回一个空数组或null。 Also the first encryption returns a empty array... 同样,第一次加密会返回一个空数组。

Picture of what IntelliJ shows while debugging 调试时IntelliJ显示的图片

Added the doFinal calls as zaph suggested, now I get following error: 按照zaph的建议添加了doFinal调用,现在出现以下错误:

Testing CBC:
Plaintext: Hallo Welt
Plaintext as HEX: 48616c6c6f2057656c74

javax.crypto.BadPaddingException: Given final block not properly padded

at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:989)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2048)
at AES_retest.multiple_CBC_update(AES_retest.java:117)

In the context of my program I will send and receive packets over a network socket that are encrypted. 在我的程序上下文中,我将通过网络套接字发送和接收经过加密的数据包。 So I need to decrypt and encrypt every packet independently. 因此,我需要独立解密和加密每个数据包。 I do not want to call doFinal at the end of every packet, because this would mean, that the same packet send twice would be encrypted in the same way. 我不想在每个数据包的末尾调用doFinal,因为这意味着发送两次相同的数据包将以相同的方式进行加密。 If that would be what I want, than I could use ECB mode. 如果那是我想要的,那么我可以使用ECB模式。 ;) ;)

eg I want to send the message "Hello World" twice to an EchoServer, the Server should be able to decrypt the first received packet, without being aware that there are more packets following. 例如,我想向EchoServer发送两次消息“ Hello World”,则服务器应该能够解密第一个接收到的数据包,而无需注意后面还有更多的数据包。 Also the Client should be able to encrypt and send the messages, unknowing if the user will provide additional data that should be send. 此外,客户端应能够加密和发送消息,而无需知道用户是否会提供应发送的其他数据。 Not sure how and where padding hast to be added in this context. 不知道在这种情况下必须如何以及在何处添加填充。

Cipher.doFinal has this annoying affect to call Cipher.init after every call. Cipher.doFinal具有这种烦人的效果,在每次调用后都调用Cipher.init。 So if I would Encrypt "Hello World" twice and call 'doFinal' after every encryption, both packets (if every "Hello World" gets its own packet) would look the same. 因此,如果我对“ Hello World”进行两次加密并在每次加密后调用“ doFinal”,则两个数据包(如果每个“ Hello World”都有自己的数据包)将看起来相同。

You are missing encrypt_cipher_cbc.doFinal . 您缺少encrypt_cipher_cbc.doFinal

From: Class Cipher - doFinal 来自: 密码类-doFinal

byte[] doFinal() Finishes a multiple-part encryption or decryption operation, depending on how this cipher was initialized. byte[] doFinal()完成多部分加密或解密操作,具体取决于此密码的初始化方式。

byte[] doFinal(byte[] input) Encrypts or decrypts data in a single-part operation, or finishes a multiple-part operation. byte[] doFinal(byte[] input)在单部分操作中加密或解密数据,或完成多部分操作。

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

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