Java AES-256-CBC не работает должным образом

Создан новый класс для тестирования чего-либо с AES в режимах CBC и CTR. Таким образом, с этим кодом CTR работает нормально, но CBC возвращает пустые массивы. Не уверен, почему это происходит, надеюсь, кто-нибудь может это объяснить.

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

Поскольку я хочу использовать как CTR, так и CBC в своей программе, я хотел бы использовать реализацию AES, которая может обрабатывать оба одновременно. Возможно ли это с данной реализацией?

Я предполагаю, что это как-то связано с определенным отступом. Если я использую NoPadding в дешифровании, текст шифра расшифровывается правильно, но заполнение не удаляется. Если я использую PCS5Padding при расшифровке, возвращается пустой массив или ноль. Также первое шифрование возвращает пустой массив...

Изображение того, что показывает IntelliJ при отладке

Добавил вызовы doFinal, как предложил zaph, теперь я получаю следующую ошибку:

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)

В контексте моей программы я буду отправлять и получать пакеты через сетевой сокет, которые зашифрованы. Поэтому мне нужно расшифровать и зашифровать каждый пакет независимо. Я не хочу вызывать doFinal в конце каждого пакета, потому что это будет означать, что один и тот же пакет, отправленный дважды, будет зашифрован одинаково. Если бы это было то, что я хочу, то я мог бы использовать режим ECB.;)

Например, я хочу дважды отправить сообщение "Hello World" на EchoServer, Сервер должен иметь возможность дешифровать первый полученный пакет, не зная, что за ним следуют другие пакеты. Также Клиент должен иметь возможность шифровать и отправлять сообщения, не зная, предоставит ли пользователь дополнительные данные для отправки. Не уверен, как и где должен быть добавлен отступ в этом контексте.

Cipher.doFinal имеет такой раздражающий эффект, чтобы вызывать Cipher.init после каждого вызова. Так что, если бы я дважды зашифровал "Hello World" и вызывал doFinal после каждого шифрования, оба пакета (если каждый "Hello World" получает свой собственный пакет) выглядели бы одинаково.

1 ответ

Решение

Вам не хватает encrypt_cipher_cbc.doFinal,

От: Класс Шифр ​​- дофинал

byte[] doFinal()Завершает операцию шифрования или дешифрования, состоящую из нескольких частей, в зависимости от того, как был инициализирован этот шифр.

byte[] doFinal(byte[] input)Шифрует или дешифрует данные в одной операции или завершает работу из нескольких частей.

Другие вопросы по тегам