web-dev-qa-db-fra.com

Comment corriger la longueur de clé AES invalide?

Je travaille sur un projet cryptage et décryptage de texte (suite à Struts 2)

Chaque fois que je saisis le mot de passe et le texte brut, une erreur de longueur de clé AES non valide apparaît.

La classe de service

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

Et c'est l'erreur

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
Rishabh Upadhyay

Choses à savoir en général:

  1. Key! = Mot de passe
    • SecretKeySpec attend une clé, pas un mot de passe. Voir ci-dessous
  2. Cela peut être dû à une restriction de stratégie empêchant l'utilisation de clés de 32 octets. Voir autre réponse à ce sujet

Dans ton cas

Le problème est le numéro 1: vous passez le mot de passe au lieu de la clé.

AES prend uniquement en charge les tailles de clé de 16, 24 ou 32 octets. Soit vous devez fournir exactement ce montant, soit vous extrayez la clé de votre saisie.

Il existe différentes manières de dériver la clé d'une phrase secrète. Java fournit une implémentation PBKDF2 à cette fin.

J'ai utilisé erickson answer pour dessiner une image complète (cryptage uniquement, car le décryptage est similaire, mais inclut le fractionnement du texte crypté):

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;

Autres choses à garder à l'esprit:

  • Utilisez toujours un nom de chiffrement complet. AES n'est pas approprié dans ce cas, car différents fournisseurs JVM/JCE peuvent utiliser des valeurs par défaut différentes pour le mode d'opération et le remplissage. Utilisez AES/CBC/PKCS5Padding. N'utilisez pas le mode ECB, car il n'est pas sécurisé sur le plan sémantique.
  • Si vous n'utilisez pas le mode ECB, vous devez envoyer l'IV avec le texte chiffré. Cela se fait généralement en préfixant le vecteur d'initialisation au tableau d'octets de texte chiffré. Le IV est automatiquement créé pour vous et vous pouvez l’obtenir par cipherInstance.getIV().
  • Chaque fois que vous envoyez quelque chose, vous devez vous assurer qu'il n'a pas été modifié en cours de route. Il est difficile d'implémenter correctement un cryptage avec MAC. Je vous recommande d'utiliser un mode authentifié tel que CCM ou GCM.
58
Artjom B.

Vous pouvez vérifier la limite de longueur de clé:

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

Je faisais face à la même chose alors j'ai fait ma clé 16 octets et cela fonctionne correctement maintenant. Créez votre clé exactement 16 octets. Cela fonctionnera sûrement.

4
vineet patel