it-swarm.com.de

Wie behebe ich eine ungültige AES-Schlüssellänge?

Ich arbeite an einem Textverschlüsselung und -entschlüsselung Projekt (nach Struts 2)

Immer wenn ich das Passwort und den Klartext eingebe, erhalte ich einen Fehler mit ungültiger AES-Schlüssellänge.

Die Serviceklasse

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();
    }
}

Und das ist der Fehler

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)
30

Wissenswertes im Allgemeinen:

  1. Schlüssel! = Passwort
    • SecretKeySpec erwartet einen Schlüssel, kein Passwort. Siehe unten
  2. Dies kann an einer Richtlinieneinschränkung liegen, die die Verwendung von 32-Byte-Schlüsseln verhindert. Siehe andere Antworten dazu

In Ihrem Fall

Das Problem ist Nummer 1: Sie übergeben das Passwort anstelle des Schlüssels.

AES unterstützt nur Schlüsselgrößen von 16, 24 oder 32 Byte. Entweder müssen Sie genau diesen Betrag angeben oder Sie leiten den Schlüssel von dem ab, was Sie eingeben.

Es gibt verschiedene Möglichkeiten, den Schlüssel von einer Passphrase abzuleiten. Java stellt zu diesem Zweck eine PBKDF2-Implementierung bereit.

Ich habe Ericksons Antwort verwendet, um ein vollständiges Bild zu zeichnen (nur Verschlüsselung, da die Entschlüsselung ähnlich ist, aber das Aufteilen des Chiffretexts beinhaltet):

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;

Andere Dinge zu beachten:

  • Verwenden Sie immer einen vollständig qualifizierten Cipher-Namen. AES ist in einem solchen Fall nicht geeignet, da verschiedene JVMs/JCE-Anbieter unterschiedliche Standardeinstellungen für den Betriebsmodus und das Auffüllen verwenden können. Verwenden Sie AES/CBC/PKCS5Padding. Verwenden Sie den EZB-Modus nicht, da er semantisch nicht sicher ist.
  • Wenn Sie den EZB-Modus nicht verwenden, müssen Sie die IV zusammen mit dem Chiffretext senden. Dies geschieht normalerweise, indem das IV dem Chiffretext-Byte-Array vorangestellt wird. Die IV wird automatisch für Sie erstellt und kann über cipherInstance.getIV() abgerufen werden.
  • Wann immer Sie etwas senden, müssen Sie sicherstellen, dass es auf dem Weg nicht verändert wurde. Es ist schwierig, eine Verschlüsselung mit MAC korrekt zu implementieren. Ich empfehle Ihnen, einen authentifizierten Modus wie CCM oder GCM zu verwenden.
58
Artjom B.

Sie können das Schlüssellängenlimit überprüfen:

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

Ich hatte das gleiche Problem, als ich meinen Schlüssel auf 16 Byte gebracht habe und er funktioniert jetzt einwandfrei. Erstellen Sie Ihren Schlüssel genau 16 Byte. Es wird sicher funktionieren.

4
vineet patel