web-dev-qa-db-fra.com

Qu'est-ce qui provoque l'erreur "Java.security.InvalidKeyException: Paramètres manquants"?

J'essaie de chiffrer et de déchiffrer une chaîne à l'aide d'AES mais j'obtiens une erreur que je ne sais pas comment résoudre. Voici le code:

public class EncryptionTest{

public static void main(String[] args) {        
    String encrypt = new String(encrypt("1234567890123456"));
    System.out.println("decrypted value:" + (decrypt("ThisIsASecretKey",encrypt)));
}

public static String encrypt(String value) {
    try {
        byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        System.out.println("encrypted string:" + (new String(encrypted)));
        return new String(skeySpec.getEncoded());
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public static String decrypt(String key, String encrypted) {
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(Base64.decodeBase64(key), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(skeySpec.getEncoded(),"AES"));
            (*)
        byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
        original.toString();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}  
}

Lorsque je l'exécute, les valeurs de "description" sont nulles. Il échoue avant le (***) !!

Cela me donne une exception:

 Java.security.InvalidKeyException: paramètres manquants 
 Sur com.Sun.crypto.provider.CipherCore.init (CipherCore.Java:388) 
 Sur com.Sun.crypto.provider .AESCipher.engineInit (AESCipher.Java:186) 
 Sur javax.crypto.Cipher.implInit (Cipher.Java:787) 
 Sur javax.crypto.Cipher.chooseProvider (Cipher.Java:849 ) 
 sur javax.crypto.Cipher.init (Cipher.Java:1213) 
 sur javax.crypto.Cipher.init (Cipher.Java:1153) 
 sur firma.XmlEncryptionTest .decrypt (EncryptionTest.Java:63) 
 sur firma.XmlEncryptionTest.main (EncryptionTest.Java:41) 

où la ligne 63 est la précédente (***). Je ne sais pas ce que je fais mal et comment résoudre. J'ai regardé autour de moi sur Internet mais sans savoir quel pouvait être ce paramètre manquant

18
Igr

Le problème principal dans votre code a été causé par un échec de spécification d'une valeur IV. Vous devez spécifier une valeur IV lors du chiffrement en mode CBC et utiliser cette même valeur lors de l'exécution du déchiffrement en mode CBC.

Un autre problème est le mélange et la correspondance de création de chaînes à partir de tableaux d'octets et d'encodage base64. Vous retournez également à chaque fois null à partir de votre méthode de décryptage. Même si vous vouliez dire return original.toString();, c'est toujours faux (parce que toString() ne fait pas ce que vous souhaitez qu'il fasse sur un tableau d'octets).

Vous trouverez ci-dessous une version améliorée de votre code. C'est loin d'être optimal, mais cela compile et fonctionne. Vous devez améliorer cela pour utiliser une IV aléatoire. De plus, si vous prévoyez de dériver des clés à partir de mots de passe, ne vous contentez pas d'obtenir les octets, utilisez une fonction de dérivation telle que PBKDF2 . Vous pouvez voir un exemple d'utilisation de PBKDF2 dans la source JNCryptor .

public class EncryptionTest {

  public static void main(String[] args) {
    try {

      String key = "ThisIsASecretKey";
      byte[] ciphertext = encrypt(key, "1234567890123456");
      System.out.println("decrypted value:" + (decrypt(key, ciphertext)));

    } catch (GeneralSecurityException e) {
      e.printStackTrace();
    }
  }

  public static byte[] encrypt(String key, String value)
      throws GeneralSecurityException {

    byte[] raw = key.getBytes(Charset.forName("UTF-8"));
    if (raw.length != 16) {
      throw new IllegalArgumentException("Invalid key size.");
    }

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec,
        new IvParameterSpec(new byte[16]));
    return cipher.doFinal(value.getBytes(Charset.forName("UTF-8")));
  }

  public static String decrypt(String key, byte[] encrypted)
      throws GeneralSecurityException {

    byte[] raw = key.getBytes(Charset.forName("UTF-8"));
    if (raw.length != 16) {
      throw new IllegalArgumentException("Invalid key size.");
    }
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec,
        new IvParameterSpec(new byte[16]));
    byte[] original = cipher.doFinal(encrypted);

    return new String(original, Charset.forName("UTF-8"));
  }
}
35
Duncan Jones

Si vous utilisez un mode de chaînage de blocs comme CBC, vous devez également fournir une IvParameterSpec au chiffrement.

public class EncryptionTest {

static byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};

static SecureRandom rnd = new SecureRandom();

static IvParameterSpec iv = new IvParameterSpec(rnd.generateSeed(16));

public static void main(String[] args) {
    String encrypt = encrypt("1234567890123456");
    System.out.println("decrypted value:" + (decrypt("ThisIsASecretKey", encrypt)));
}

public static String encrypt(String value) {
    try {

        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec,iv);
        byte[] encrypted = cipher.doFinal(value.getBytes());
        System.out.println("encrypted string:" + Base64.encodeBase64String(encrypted));
        return Base64.encodeBase64String(encrypted);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public static String decrypt(String key, String encrypted) {
    try {
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec,iv);
        byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));

        return new String(original);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

}

12
dijkstra

Même si c'est trop tard, mais je donne quand même ma solution pour les autres.Veuillez vous référer ci-dessous au code de travail pour crypter et décrypter les données.

public static byte[] encrypt(String value) {
        byte[] encrypted = null;
        try {

            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = new byte[cipher.getBlockSize()];

            IvParameterSpec ivParams = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams);
            encrypted  = cipher.doFinal(value.getBytes());
            System.out.println("encrypted string:" + encrypted.length);

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return encrypted;
    }

    public static  byte[]  decrypt(byte[] encrypted) {
         byte[] original = null;
         Cipher cipher = null;
        try {
            byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'};
            Key key = new SecretKeySpec(raw, "AES");
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher
            byte[] ivByte = new byte[cipher.getBlockSize()];
            //This class specifies an initialization vector (IV). Examples which use
            //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation.
            IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
            cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
            original= cipher.doFinal(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return original;
    }  
8
Arpana