1. ホーム
  2. ジャワ

[解決済み] エラー「java.security.InvalidKeyException」の原因は何ですか?Parameters missing "というエラーは何ですか?[重複しています]。

2022-03-04 21:27:06

質問事項

AESを使って文字列を暗号化・復号化しようとしているのですが、解決方法がわからないエラーが発生します。これはコードです。

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

実行すると、"decription"の値がnullになります。(***)の前に失敗します!

例外が発生します。

java.security.InvalidKeyException: パラメータがありません
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:388)
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:186)
    at javax.crypto.Cipher.implInit(Cipher.java:787)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
    at javax.crypto.Cipher.init(Cipher.java:1213)
    at javax.crypto.Cipher.init(Cipher.java:1153)
    at firma.XmlEncryptionTest.decrypt(EncryptionTest.java:63)
    at firma.XmlEncryptionTest.main(EncryptionTest.java:41)

ここで、63行目は、その前の行です(***)。何が間違っているのか、どうすれば解決するのかわかりません。インターネットでいろいろ調べてみましたが、何が足りないパラメータなのか分かりませんでした。

どのように解決するのですか?

あなたのコードの主な問題は、IV 値の指定に失敗したことに起因しています。CBCモードの暗号化を行う際にはIV値を指定し、CBCモードの復号化を行う際にはその同じ値を使用する必要があります。

また、バイト配列からの文字列作成とbase64エンコーディングが混在していることも問題です。また null を毎回 decrypt メソッドから実行しています。たとえ return original.toString(); というのは、まだ間違っています。 toString() は、バイト配列の場合、あなたが望むようなことはできません)。

以下は、あなたのコードの改良版です。最適とは程遠いですが、コンパイルして動作します。ランダムIVを使用するために、これを改良する必要があります。 また、パスワードから鍵を導出する場合は、単にバイトを取得するだけでなく、PBKDF2などの導出関数を使用するようにしましょう . PBKDF2 を使用した例を 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"));
  }
}