Java AES-256-CBC 未按预期工作
Java AES-256-CBC not working as expected
创建了一个新的 class 以在 CBC 和 CTR 模式下使用 AES 测试某些内容。所以使用这段代码,CTR 工作正常,但 CBC returns 空数组。不知道为什么会这样,希望有人能解释一下。
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 实现。对于给定的实现,这可能吗?
我想应该是跟定义的Padding有关吧。如果我在解密时使用 NoPadding,密文会被正确解密,但不会删除填充。如果我在解密时使用 PCS5Padding,则会返回一个空数组或 null。也是先加密returns一个空数组...
Picture of what IntelliJ shows while debugging
按照 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)
在我的程序上下文中,我将通过加密的网络套接字发送和接收数据包。所以我需要独立解密和加密每个数据包。我不想在每个数据包的末尾调用 doFinal,因为这意味着同一个数据包发送两次将以相同的方式加密。如果那是我想要的,那么我可以使用 ECB 模式。 ;)
例如
我想向 EchoServer 发送消息 "Hello World" 两次,服务器应该能够解密第一个收到的数据包,而不知道后面还有更多数据包。此外,客户端应该能够加密和发送消息,不知道用户是否会提供应该发送的额外数据。
不确定在此上下文中必须如何以及在何处添加填充。
Cipher.doFinal 每次调用后调用 Cipher.init 都有这种烦人的影响。因此,如果我将加密 "Hello World" 两次并在每次加密后调用 'doFinal',则两个数据包(如果每个 "Hello World" 都有自己的数据包)看起来是一样的。
你错过了 encrypt_cipher_cbc.doFinal
.
byte[] doFinal()
完成多部分加密或解密操作,具体取决于如何
此密码已初始化。
byte[] doFinal(byte[] input)
在单部分操作中加密或解密数据,或完成多部分操作。
创建了一个新的 class 以在 CBC 和 CTR 模式下使用 AES 测试某些内容。所以使用这段代码,CTR 工作正常,但 CBC returns 空数组。不知道为什么会这样,希望有人能解释一下。
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 实现。对于给定的实现,这可能吗?
我想应该是跟定义的Padding有关吧。如果我在解密时使用 NoPadding,密文会被正确解密,但不会删除填充。如果我在解密时使用 PCS5Padding,则会返回一个空数组或 null。也是先加密returns一个空数组...
Picture of what IntelliJ shows while debugging
按照 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)
在我的程序上下文中,我将通过加密的网络套接字发送和接收数据包。所以我需要独立解密和加密每个数据包。我不想在每个数据包的末尾调用 doFinal,因为这意味着同一个数据包发送两次将以相同的方式加密。如果那是我想要的,那么我可以使用 ECB 模式。 ;)
例如 我想向 EchoServer 发送消息 "Hello World" 两次,服务器应该能够解密第一个收到的数据包,而不知道后面还有更多数据包。此外,客户端应该能够加密和发送消息,不知道用户是否会提供应该发送的额外数据。 不确定在此上下文中必须如何以及在何处添加填充。
Cipher.doFinal 每次调用后调用 Cipher.init 都有这种烦人的影响。因此,如果我将加密 "Hello World" 两次并在每次加密后调用 'doFinal',则两个数据包(如果每个 "Hello World" 都有自己的数据包)看起来是一样的。
你错过了 encrypt_cipher_cbc.doFinal
.
byte[] doFinal()
完成多部分加密或解密操作,具体取决于如何
此密码已初始化。
byte[] doFinal(byte[] input)
在单部分操作中加密或解密数据,或完成多部分操作。