web-dev-qa-db-ja.com

javax.crypto.IllegalBlockSizeException:埋め込まれた暗号で復号化する場合、入力の長さは16の倍数でなければなりません

Javaクラスで解読エラーが発生しています:

javax.crypto.IllegalBlockSizeException : 
    Input length must be multiple of 16 when decrypting with padded cipher.

この問題を解決するにはどうすればよいですか?

更新:

私はそれが一度働いていることを忘れていて、2回目にもう一度実行しようとすると、上記のエラーがスローされます。

package com.tb.module.service;
import Java.security.Key;
import Java.security.spec.InvalidKeySpecException;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import Sun.misc.*;

/**
 * This class is used for encrypt and decrypt the  password field.
 *
 */
public class PswdEnc {

    private static final String ALGO = "AES";
    private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };

    public static String encrypt(String Data) throws Exception {
        Key key = generateKey();
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.ENCRYPT_MODE, key);
        byte[] encVal = c.doFinal(Data.getBytes());
        String encryptedValue = new BASE64Encoder().encode(encVal);
        return encryptedValue;
    }

    public static String decrypt(String encryptedData) throws Exception {
        Key key = generateKey(); 
        Cipher c = Cipher.getInstance(ALGO);
        c.init(Cipher.DECRYPT_MODE, key);
        byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
        byte[] decValue = c.doFinal(decordedValue);
        String decryptedValue = new String(decValue);
        return decryptedValue;
    }


    private static Key generateKey() throws Exception {
        Key key = new SecretKeySpec(keyValue, ALGO);
        return key;
    }

}
24
baburao113

使用しているアルゴリズム「AES」は、「AES/ECB/NoPadding」の短縮形です。これは、 AESアルゴリズムを使用していることを意味します 128ビットキーサイズと ブロックサイズ[〜#〜] ecb [〜#〜]モード操作 および パディングなし

つまり、128ビットまたは16バイトのブロックのデータのみを暗号化できます。そのため、IllegalBlockSizeException例外が発生します。

16バイトの倍数ではないサイズのデータ​​を暗号化する場合は、何らかのパディングまたは暗号ストリームを使用する必要があります。たとえば、アルゴリズムとして「AES/CBC/NoPadding」を指定することにより CBCモード (ブロック暗号を ストリーム暗号に効果的に変換する操作モード )を指定するか、PKCS5パディングを指定する「AES/ECB/PKCS5」。これは、暗号化テキストのサイズを16バイトの倍数にするために、非常に特定の形式でデータの最後にいくつかのバイトを自動的に追加します。一部のデータを無視します。

いずれにせよ、今あなたがやっていることを今すぐやめて、暗号に関する非常に入門的な資料を勉強することを強くお勧めします。たとえば、Courseraの Crypto Iをチェックします 。あるモードまたは別のモードを選択することの意味、それらの長所、そして最も重要なことにはそれらの弱点を十分に理解する必要があります。この知識がなければ、壊れやすいシステムを簡単に構築できます。


更新:質問に対するコメントに基づいて、データベースにパスワードを保存するときにパスワードを暗号化しないでください!!!!!これを絶対にしないでください。正しくソルトされたパスワードを[〜#〜] hash [〜#〜]する必要があります。これは暗号化とはまったく異なります。本当に、あなたがしようとしていることをしないでください...パスワードを暗号化することによって、それらを解読することができます。これが意味することは、データベース管理者であり、秘密鍵を知っているあなたは、データベースに保存されているすべてのパスワードを読み取ることができるということです。あなたはこれを知っていて非常に悪いことをしている、またはあなたはこれを知らなかったので、ショックを受けてそれを止めるべきです。

74
Bruno Reis

いくつかのコメント:

_import Sun.misc.*;_これをしないでください。これは非標準であり、実装間で同じであることが保証されていません。 Base64変換が利用可能な他のライブラリがあります。

byte[] encVal = c.doFinal(Data.getBytes());ここでは、デフォルトの文字エンコーディングに依存しています。使用している文字エンコードを常に指定します。byte[] encVal = c.doFinal(Data.getBytes("UTF-8"));デフォルトは場所によって異なる場合があります。

@thegrinnerが指摘したように、バイト配列の長さを明示的に確認する必要があります。矛盾がある場合は、それらをバイトごとに比較して、違いがどこに忍び込んでいるかを確認します。

3
rossum

まあそれは

128ビットまたは16バイトのブロックのデータのみを暗号化できます。そのため、IllegalBlockSizeException例外が発生します。 1つの方法は、そのデータを文字列に直接暗号化することです。

これを見て。試してみて、あなたはこれを解決することができます

public static String decrypt(String encryptedData) throws Exception {

    Key key = generateKey();
    Cipher c = Cipher.getInstance(ALGO);
    c.init(Cipher.DECRYPT_MODE, key);
    String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
    System.out.println("This is Data to be Decrypted" + decordedValue);
    return decordedValue;
}

それが役立つことを願っています。

0
Krishna