0

我在 ECB 中需要一个简单的 AES 密码系统。我目前有一个工作,因为连续两次给定相同的密钥,它将正确加密和解​​密消息。

但是,如果我使用两个不同的密钥进行加密/解密,程序会抛出一个javax.crypto.BadPaddingException: Given final block not properly padded. 我需要该程序提供不正确的解密,大概看起来像一些加密字符串。这是我的代码:

    public static byte[] encrypt(byte[] plaintext, String key) throws Exception {
        char[] password = key.toCharArray();
        byte[] salt = "12345678".getBytes();
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        byte[] ciphertext = cipher.doFinal(plaintext);  
        return ciphertext;
    }

    public static byte[] decrypt(byte[] ciphertext, String key) throws Exception {
        char[] password = key.toCharArray();
        byte[] salt = "12345678".getBytes();
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secret);
        byte[] plaintext = cipher.doFinal(ciphertext);  
        return plaintext;
    }

(注意:我知道使用 ECB、salt = "12345678" 等的缺点,但这不是我目前关心的问题。)感谢您的任何帮助。

4

1 回答 1

1

PKCS#5 填充具有非常特殊的结构,因此如果您希望使用错误的密钥完成解密而不会出错,则无法继续使用它。

实现目标的一个好方法可能是使用流操作模式,而不是块模式。在流模式中,输入密钥用于生成看似随机数据的永无止境的流,与密文进行异或以生成明文(反之亦然)。如果您使用了错误的密钥,您会得到与原始明文大小相同的无意义数据。

这是一个基于您的原始代码的简单示例。我使用全零的 IV,但您可能希望在适当的时候将其改进为随机值(注意:您需要将此值与密文一起存储)。

public static void main(String[] args) throws Exception {  
  byte[] plaintext = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  byte[] ciphertext = encrypt(plaintext, "foo");

  byte[] goodDecryption = decrypt(ciphertext, "foo");
  byte[] badDecryption = decrypt(ciphertext, "bar");  

  System.out.println(DatatypeConverter.printHexBinary(goodDecryption));
  System.out.println(DatatypeConverter.printHexBinary(badDecryption));
}

public static SecretKey makeKey(String key) throws GeneralSecurityException {
  char[] password = key.toCharArray();
  byte[] salt = "12345678".getBytes();
  SecretKeyFactory factory =
      SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
  KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
  SecretKey tmp = factory.generateSecret(spec);
  return new SecretKeySpec(tmp.getEncoded(), "AES");
}

public static byte[] encrypt(byte[] plaintext, String key) throws Exception {
  SecretKey secret = makeKey(key);
  Cipher cipher = Cipher.getInstance("AES/OFB8/NoPadding");
  cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
  return cipher.doFinal(plaintext);
}

public static byte[] decrypt(byte[] ciphertext, String key) throws Exception {
  SecretKey secret = makeKey(key);
  Cipher cipher = Cipher.getInstance("AES/OFB8/NoPadding");
  cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
  return cipher.doFinal(ciphertext);
}

输出:

00010203040506070809
5F524D4A8D977593D34C
于 2014-11-28T09:07:22.477 回答