用AES CBC Java进行加密

3

我遇到了一些问题。当我尝试加密文本并解密文本时,我会得到以下错误:

javax.crypto.IllegalBlockSizeException: 在使用填充密码解密时,输入长度必须是16的倍数

这是我的代码:

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
 *
 * @author Grzesiek
 */
public class SymmethricCipherCBC {


    /* Klucz: */
    private byte[] keyBytes = new byte[] {
            0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
            0x00,0x01,0x02,0x03,0x04,0x05
        };

   /* Wektor inicjalizacyjny: */
   private byte[] ivBytes = new byte[] {
            0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
            0x00,0x01,0x02,0x03,0x04,0x05
        };

   private Cipher cipher;
   private SecretKeySpec keySpec;
   private IvParameterSpec ivSpec;



   public SymmethricCipherCBC() throws NoSuchAlgorithmException, NoSuchPaddingException{
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Utworzenie obiektu dla operacji szyfrowania/deszyfrowania algorytmem AES w trybie CBC.
        keySpec = new SecretKeySpec(keyBytes, "AES"); // Utworzenie obiektu klucza dla algorytmu AES z tablicy bajtow
        ivSpec = new IvParameterSpec(ivBytes); // // Utworzenie obiektu dla wektora inicjalizacyjnego
   }


   public String encryptText(String plainText) throws NoSuchAlgorithmException, 
                                                    InvalidKeyException, 
                                                    NoSuchPaddingException, 
                                                    InvalidAlgorithmParameterException, 
                                                    ShortBufferException, 
                                                    IllegalBlockSizeException, 
                                                    BadPaddingException,
                                                    UnsupportedEncodingException{

       int cipherTextLength;
       byte[] cipherText; // Bufor dla szyfrogramu

       byte[] plainTextBytes = plainText.getBytes(); // Reprezentacja tekstu jawnego w bajtach

       cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); //Inicjalizacja obiektu dla operacji szyfrowania z kluczem okreslonym przez keySpec:   

       cipherText = new byte[cipher.getOutputSize(plainTextBytes.length)]; //Utworzenie buforu dla szyfrogramu

       cipherTextLength = cipher.update(plainTextBytes, 0, plainTextBytes.length, cipherText, 0); // Szyfrowanie tekstu jawnego

       cipherTextLength += cipher.doFinal(cipherText, cipherTextLength); //Zakonczenie szyfrowania

       return new BigInteger(1, cipherText).toString(16); // zapisanie 16 

   }


   public String decryptText(String ciptherTextString) throws InvalidKeyException, InvalidAlgorithmParameterException, ShortBufferException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{

       byte[] cipherTextBytes = ciptherTextString.getBytes();

       cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);  //Inicjalizacja obiektu cipher dla odszyfrowywania z kluczem okreslonym przez keySpec

       byte[] plainTextBytes = new byte[cipher.getOutputSize(cipherTextBytes.length)];  // Utworzenie wyzerowanej tablicy

       int plainTextLength = cipher.update(cipherTextBytes, 0, cipherTextBytes.length, plainTextBytes, 0);
       plainTextLength += cipher.doFinal(plainTextBytes, plainTextLength);

       return new String(plainTextBytes); //Odtworzona wiadomosc
   }
}

你有什么想法应该做什么?


请提供堆栈跟踪。 - tckmn
与此处相同的问题:http://stackoverflow.com/questions/14109626/javax-crypto-badpaddingexception-unknown-block-type/14109701#14109701 - Henry
你的encryptText和decryptText方法明显不兼容,而且你的encryptText方法使用的编码大约每256次加密就会失败。提示:在密码中前导零是有意义的。 - President James K. Polk
请查看我的答案这里,它展示了如何处理字符串和加密/解密。 - Maarten Bodewes
2个回答

4

您做的比必要还要困难,并且在执行时加密了您的密码文本。

cipher.doFinal(cipherText, cipherTextLength);

我会按原样重写它:

我会按原样重写它:

public String encryptText(String plainText) throws ... {
    byte[] plainTextBytes = plainText.getBytes("UTF8");
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); 
    byte[] encrypted = cipher.doFinal(plainTextBytes);
    return toHex(encrypted);
}

public String decryptText(String cipherTextString) throws ... {
    byte[] cipherTextBytes = fromHex(cipherTextString);
    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
    byte[] plainTextBytes = cipher.doFinal(cipherTextBytes);
    return new String(plainTextBytes, "UTF8");
}

0
据我所知,您正在使用 BigInteger 将加密算法的字节数组输出转换为十六进制字符串。然后解密算法将十六进制字符串转换为 ASCII 字符在十六进制字符串中的字节表示,使用 .toString()
这就是您的代码出错的地方(还有其他地方)。与其将十六进制字符串输出“FFFF”转换为字节数组[0xff, 0xff],它将其转换为字节数组[0x46,0x46,0x46,0x46](即大写 F 的 ASCII 字节表示)。这意味着您转换中的所有字节都将是错误的,并且字节数组的长度也会是错误的(这导致您在问题中列出的异常)。
相反,您应该从加密方法返回 byte[],并在解密方法中使用 byte[] 作为参数。如果无法实现,您应该使用类似 Apache Commons Codec 的 Hex 类来可靠地在字节数组和十六进制字符串之间进行转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接