AES-128加密字符串未正确填充

时间:2014-11-14 17:10:10

标签: java encryption aes

使用 AES / CBC / PKCS5Padding 并使用 128位密钥创建加密字符串时遇到问题。我有解密加密字符串的代码。我有一个示例加密的字符串来自另一个成功解密的系统,但是当我尝试创建自己的加密字符串时,由于某种原因它没有正确填充。当我解密我的加密字符串时,它只显示16字节后的字符。

我找到的所有示例都假设加密首先发生,然后在加密期间设置变量之后发生解密,或者它们随机生成密钥,但在我的情况下,我想使用已知密钥。

我真的被困了所以非常感谢任何帮助,非常感谢您的时间和努力!

示例:

原文: 01234567891234565

加密: zmb16qyYrdoW6akBdcJv7DXCzlw0qU7A2ea5q4YQWUo =

密钥长度: 16

解密: 5(这是原始文字字符串中的最后一位数字)

示例代码:

package com.company.encrypt.tests;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class TestEncryptDecrypt {

    private static final String characterEncoding = "UTF-8";
    private static final String cipherTransformation = "AES/CBC/PKCS5Padding";
    private static final String aesEncryptionAlgorithm = "AES";

    public static void main(String[] args) throws Exception {
        String key1 = "1234567812345678";
        String text = "01234567891234565";
        System.out.println("Original Text: " + text);
        String encrypted = encrypt(text, key1);
        System.out.println("Encrypted: " + encrypted);
        String decrypted = decrypt(encrypted, key1);
        System.out.println("Decrypted: " + decrypted);

    }

    public static String decrypt(String encryptedText, String key) throws Exception {
        String plainText = null;

        int keyLength = key.length();
        System.out.println("Key length: " + String.valueOf(keyLength));
        byte[] encryptedTextBytes = Base64.decodeBase64(encryptedText.getBytes());
        byte[] keyBytes = key.getBytes();

        byte[] initialVector = Arrays.copyOfRange(encryptedTextBytes, 0, keyLength);
        byte[] trimmedCipherText = Arrays.copyOfRange(encryptedTextBytes, keyLength, encryptedTextBytes.length);

        try {
            Cipher cipher = Cipher.getInstance(cipherTransformation);
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, aesEncryptionAlgorithm);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

            byte[] clearText;
            clearText = cipher.doFinal(trimmedCipherText);

            plainText = new String(clearText, characterEncoding);
        } catch(NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException
                | InvalidKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return plainText;

    }

    public static String encrypt(String plainText, String encryptionKey) throws Exception {

        SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), aesEncryptionAlgorithm);
        Cipher cipher = Cipher.getInstance(cipherTransformation);
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] plainTextBytes = plainText.getBytes("UTF-8");

        byte[] encrypted = cipher.doFinal(plainTextBytes);

        return new String(Base64.encodeBase64(encrypted));
    }

}

1 个答案:

答案 0 :(得分:2)

我注意到在decrypt()函数中,您将加密的数组分为两部分:前16个字节,其余部分。您使用前16个字节作为解密的IV,但是,您没有在encrypt()中将16字节IV添加到加密消息的开头。这导致明文的前16个字节丢失。我认为你假设doFinal()会自动为你做这件事,但事实并非如此。

要解决此问题,请在返回加密邮件之前添加IV,这可以使用cipher.getIV()进行检索。您可以使用Apache Commons Lang库中的ArrayUtils.addAll()来完成此操作,或者只需编写您自己的函数来完成此操作。需要注意的另一点是,IV将始终是块大小,无论密钥大小如何,AES都是16字节。

希望这个答案有所帮助!