Как исправить неверную длину ключа AES?

Я работаю над проектом шифрования и дешифрования текста (после Struts 2)

Всякий раз, когда я ввожу пароль и простой текст, я получаю ошибку Invalid AES Key Length.

Сервисный класс

package com.anoncrypt.services;

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class SymAES
{
    private static final String ALGORITHM = "AES";
    private static byte[] keyValue= new byte[] { 'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y' };

     public  String encode(String valueToEnc) throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGORITHM);
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encValue = c.doFinal(valueToEnc.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encValue);
        return encryptedValue;
    }

    public  String decode(String encryptedValue) throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGORITHM);
        Cipher c = Cipher.getInstance(ALGORITHM);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }

    public  void start(String passcode)throws Exception
    {
        keyValue = passcode.getBytes();
    }
}

И это ошибка

java.security.InvalidKeyException: Invalid AES key length: 6 bytes
    com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:87)
    com.sun.crypto.provider.ElectronicCodeBook.init(ElectronicCodeBook.java:93)
    com.sun.crypto.provider.CipherCore.init(CipherCore.java:582)
    com.sun.crypto.provider.CipherCore.init(CipherCore.java:458)
    com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:307)
    javax.crypto.Cipher.implInit(Cipher.java:797)
    javax.crypto.Cipher.chooseProvider(Cipher.java:859)
    javax.crypto.Cipher.init(Cipher.java:1229)
    javax.crypto.Cipher.init(Cipher.java:1166)
    com.anoncrypt.services.SymAES.encode(SymAES.java:35)
    com.anoncrypt.actions.SymEncrypt.execute(SymEncrypt.java:24)

Ответ 1

Что нужно знать в общем:

  1. Ключ! = Пароль
    • SecretKeySpec ожидает ключ, а не пароль. Увидеть ниже
  2. Это может быть связано с ограничением политики, которое не позволяет использовать 32-байтовые ключи. Смотрите другой ответ на этот вопрос

В твоем случае

Проблема № 1: вы передаете пароль вместо ключа.

AES поддерживает только размеры ключей 16, 24 или 32 байта. Вам нужно либо указать именно эту сумму, либо вы получаете ключ от того, что вы вводите.

Существуют разные способы получения ключа из ключевой фразы. Java предоставляет реализацию PBKDF2 для этой цели.

Я использовал ответ erickson, чтобы нарисовать полную картину (только шифрование, поскольку расшифровка похожа, но включает разделение зашифрованного текста):

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 256); // AES-256
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = f.generateSecret(spec).getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] encValue = c.doFinal(valueToEnc.getBytes());

byte[] finalCiphertext = new byte[encValue.length+2*16];
System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
System.arraycopy(salt, 0, finalCiphertext, 16, 16);
System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);

return finalCiphertext;

Другие вещи, которые нужно иметь в виду:

  • Всегда используйте полное имя шифра. AES не подходит в таком случае, потому что разные поставщики JVM/JCE могут использовать разные значения по умолчанию для режима работы и заполнения. Используйте AES/CBC/PKCS5Padding. Не используйте режим ECB, потому что он не является семантически безопасным.
  • Если вы не используете режим ECB, вам нужно отправить IV вместе с зашифрованным текстом. Обычно это делается путем добавления префикса IV к массиву байтов зашифрованного текста. IV автоматически создается для вас, и вы можете получить его через cipherInstance.getIV().
  • Всякий раз, когда вы отправляете что-то, вы должны быть уверены, что это не было изменено по пути. Трудно правильно реализовать шифрование с помощью MAC. Я рекомендую вам использовать режим аутентификации, такой как CCM или GCM.

Ответ 2

Вы можете проверить ограничение длины ключа:

int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
System.out.println("MaxAllowedKeyLength=[" + maxKeyLen + "].");

Ответ 3

У меня возникла такая же проблема, после чего я сделал свой 16-байтовый ключ и теперь он работает нормально. Создайте свой ключ ровно по 16 байт. Это, безусловно, будет работать.