18

tomcatを使用して、2つのWebアプリケーション(app1とapp2)があります。暗号化された形式で(以下のコードを使用して)app1からapp2にURLを送信しました。次に、app2で、この暗号化されたURLを復号化しました。decrypしかし、メソッドの50行目で例外を下回っています。

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

app1で暗号化されたURLを(同じコードを使用して)復号化しようとするとデバッグできますが、正常に機能します。しかし、app2でこの例外の原因を特定できませんか?

これがコードです

import java.security.Key;

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

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class AESEncryptionDecryptionTest {

    private static final String ALGORITHM       = "AES";
    private static final String myEncryptionKey = "ThisIsFoundation";
    private static final String UNICODE_FORMAT  = "UTF8";

    public static String encrypt(String valueToEnc) throws Exception {
        Key key = generateKey();
        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 static String decrypt(String encryptedValue) throws Exception {
         Key key = generateKey();
         Cipher c = Cipher.getInstance(ALGORITHM);
         c.init(Cipher.DECRYPT_MODE, key);
         byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
         byte[] decValue = c.doFinal(decordedValue);//////////LINE 50
         String decryptedValue = new String(decValue);
         return decryptedValue;
    }

    private static Key generateKey() throws Exception {
         byte[] keyAsBytes;
         keyAsBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
         Key key = new SecretKeySpec(keyAsBytes, ALGORITHM);
         return key;
    }

    public static void main(String[] args) throws Exception {

         String value = "password1";
         String valueEnc = AESEncryptionDecryptionTest.encrypt(value);
         String valueDec = AESEncryptionDecryptionTest.decrypt(valueEnc);

         System.out.println("Plain Text : " + value);
         System.out.println("Encrypted : " + valueEnc);
         System.out.println("Decrypted : " + valueDec);
    }

}
4

4 に答える 4

11

私のマシンで動作します。バイトを文字列に、またはその逆に変換するすべてのインスタンスで `UNICODE_FORMAT'を使用すると、役に立ちますか?この行は問題になる可能性があります。

byte[] encValue = c.doFinal(valueToEnc.getBytes()); 

する必要があります

byte[] encValue = c.doFinal(valueToEnc.getBytes(UNICODE_FORMAT));

とにかく、アルゴリズムとして「AES」を使用し、JCEを使用する場合、実際に使用されるアルゴリズムは「AES / ECB/PKCS5Padding」になります。自分が何をしているかについて100%確信が持てない限り、ECBを何にも使用しないでください。このような混乱を避けるために、常にアルゴリズムを明示的に指定することをお勧めします。「AES/CBC/PKCS5Padding」が適切な選択です。ただし、適切なアルゴリズムを使用すると、IVを提供および管理する必要があることに注意してください。

ECB暗号を使用することは、パスワードの暗号化のコンテキストではさらに望ましくありません。これは、例を正しく解釈すると、暗号化で行っているように見えます。その目的のためにPKCS#5で指定されているパスワードベースの暗号化を使用する必要があります。Javaでは、これはSecretKeyFactoryで提供されます。パスワードを使用して対称鍵を導出するには、反復回数が十分に多い「PBKDF2WithHmacSHA1」(ターゲットマシンによって異なりますが、5〜20000の範囲)を使用してください。

達成しようとしているのがパスワード暗号化ではなく、実際にパスワードストレージである場合は、同じ手法を使用できます。

于 2012-05-31T16:13:44.710 に答える
-1

値を二重に復号化するときに、このエラーが発生していました(ここで言うようにパスワードは問題なく通過します)。復号化を複数回行っているかどうかを必ず確認してください。(エラーでは8の倍数でしたが、そこで別のスキームを使用していました...)私の場合、ファイルを読み取るときに復号化し、フィールドに入力するときに再度復号化しました。(デスクトップアプリ)

于 2015-10-08T02:10:40.380 に答える
-1

文字列を操作する代わりに、byte[]自体を操作することをお勧めします。文字列に変換すると、一部のバイトが変更されると思います。次のコードは私のために働きます-

public static final String ENC_KEY = "abcdefghijklmnop";
public static final String DATA = "Hello World";

public static void test(){

    try {
        Cipher c = Cipher.getInstance("AES");

        SecretKeySpec secretKeySpec = new SecretKeySpec(ENC_KEY.getBytes("UTF-8"), "AES");

        c.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encBytes = c.doFinal(DATA.getBytes("UTF-8"));
        String encStr =  new String(encBytes, "UTF-8");
        System.out.println("Encrypted String: " + encStr);

        c.init(Cipher.DECRYPT_MODE, secretKeySpec);
        String decStr = new String(c.doFinal(encBytes),"UTF-8");
        System.out.println("Decrypted String: " + decStr);

    } catch (Exception ex) {
        System.out.println("Error in encrypting data");
        ex.printStackTrace();
    }
}

しかし、それを-に変更すると

public static void test(){

    try {
        Cipher c = Cipher.getInstance("AES");

        SecretKeySpec secretKeySpec = new SecretKeySpec(ENC_KEY.getBytes("UTF-8"), "AES");

        c.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encBytes = c.doFinal(DATA.getBytes("UTF-8"));
        String encStr =  new String(encBytes, "UTF-8");
        System.out.println("Encrypted String: " + encStr);

        c.init(Cipher.DECRYPT_MODE, secretKeySpec);
        String decStr = new String(c.doFinal(encStr.getBytes("UTF-8")),"UTF-8");
        System.out.println("Decrypted String: " + decStr);

    } catch (Exception ex) {
        System.out.println("Error in encrypting data");
        ex.printStackTrace();
    }
}

あなたは得るでしょう

javax.crypto.IllegalBlockSizeException:com.sun.crypto.provider.CipherCore.doFinal(com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)でパディングされた暗号を使用して復号化する場合、入力長は16の倍数である必要があります。 CipherCore.java:847)at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)at javax.crypto.Cipher.doFinal(Cipher.java:2164)at com.osfg.HelloWorld.test(HelloWorld .java:38)com.osfg.HelloWorld.main(HelloWorld.java:22)

知らせ

String decStr = new String(c.doFinal(encBytes),"UTF-8");
VRS
String decStr = new String(c.doFinal(encStr.getBytes("UTF-8")),"UTF-8");
于 2018-07-21T15:09:24.663 に答える
-3

このエラーは、選択の組み合わせを使用した場合、16文字のソーステキストのみが必要であることを示しています。パスワードを暗号化する場合は、暗号化のために元のパスワードを16文字に切り捨てるかパディングし、復号化後にトリミングすることができます。この方法では、実際のパスワードを16文字以下に制限する必要がありますが、使用時間の長いパスワードを適用して、パスワードを知らない人を混乱させる可能性があります。

于 2013-05-22T14:04:45.980 に答える