BadPaddingException:GCMにおけるMACチェックに失敗しました

デクスター:

私は、暗号化/復号化AES-GCMおよびJDK 1.8 CipherOutputStreamを使用しようとしている、しかし、復号時のBadPaddingExceptionを取得しています。私は、暗号化と復号化時に同じIVと秘密鍵を使用していますが、必ず何が間違って起こっているではありません。以下のコードを参照してください。

 static String AES_GCM_MODE = "AES/GCM/NoPadding";

    SecretKey secretKey;

    public SymmetricFileEncryption(){

        Security.insertProviderAt( new BouncyCastleProvider(), 1);
        setSecretKey();
    }

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

        File inputFile = new File("test.txt");
        File outputFile = new File("test-crypt.txt");
        File out = new File("test-decrypt.txt");

        SymmetricFileEncryption sym = new SymmetricFileEncryption();
        sym.encrypt(inputFile, outputFile);
        sym.decrypt(outputFile, out);
    }

    public Cipher getEncryptionCipher() throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException {

        Cipher cipher = Cipher.getInstance(AES_GCM_MODE, "BC");
        GCMParameterSpec parameterSpec = new GCMParameterSpec(128, getInitializationVector());
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(), new IvParameterSpec(getInitializationVector()) );
        return cipher;
    }

    private Cipher getDecryptionCipher(File inputFile) throws InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, IOException, NoSuchProviderException {
        //initialize cipher
        Cipher cipher = Cipher.getInstance(AES_GCM_MODE, "BC");
        GCMParameterSpec parameterSpec = new GCMParameterSpec(128, getInitializationVector());
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(),new IvParameterSpec(getInitializationVector()) );
        return cipher;
    }

    public void encrypt(File inputFile, File outputFile) throws Exception {
        Cipher cipher = getEncryptionCipher();
        FileOutputStream fos = null;
        CipherOutputStream cos = null;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(inputFile);
            fos = new FileOutputStream(outputFile);
            cos = new CipherOutputStream(fos, cipher);
            byte[] data = new byte[16];
            int read = fis.read(data);
            while (read != -1) {
                cos.write(data, 0, read);
                read = fis.read(data);
            }
            cos.flush();
        }catch (Exception e){
            e.printStackTrace();
        }
        finally {
            fos.close();
            cos.close();
            fis.close();
        }
        String iv = new String(cipher.getIV());
    }

    public void decrypt(File inputFile, File outputFile) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, NoSuchProviderException {

        Cipher cipher = getDecryptionCipher(inputFile);
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        CipherInputStream cipherInputStream = null;

        try{
            inputStream = new FileInputStream(inputFile);
            cipherInputStream = new CipherInputStream(inputStream, cipher);
            outputStream = new FileOutputStream(outputFile);
            byte[] data = new byte[16];
            int read = cipherInputStream.read(data);
            while(read != -1){
                outputStream.write(data);
                read = cipherInputStream.read(data);
            }
            outputStream.flush();
        }catch (Exception e){
            e.printStackTrace();
        }
        finally {
            cipherInputStream.close();
            inputStream.close();
            outputStream.close();
        }
    }

    public void setSecretKey(){
        SecureRandom secureRandom = new SecureRandom();
        byte[] key = new byte[16];
        secureRandom.nextBytes(key);
        secretKey =  new SecretKeySpec(key, "AES");
    }

    public SecretKey getSecretKey(){
        return secretKey;
    }

public byte[] getInitializationVector(){

        String ivstr = "1234567890ab"; //12 bytes
        byte[] iv =  ivstr.getBytes();//new byte[12];
        return iv;
 }

線INT読み取り= cipherInputStream.read(データ)に復号化中にエラーが次のコードの結果、上記。

javax.crypto.BadPaddingException: mac check in GCM failed
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:128)
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:246)
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:222)
    at com.rocketsoftware.abr.encryption.SymmetricFileEncryption.decrypt(SymmetricFileEncryption.java:107)
Topaco:
  • 中:暗号化は正常に動作しないencryptCipherOutputStream#closeと呼ばれなければならない前に FileOutputStream#closeこれは、あるCipherOutputStream#close呼び出しCipher#doFinalタグを生成し、暗号文に追加します。この部分だけに書き込むことができるFileOutputStream場合-instance FileOutputStream#closeまだ呼び出されていません。ところで、CipherOutputStream#flush呼び出す必要はありません。

  • 復号化に問題がある:ではdecryptoutputStream.write(data)置き換える必要がありますoutputStream.write(data, 0, read)それ以外の場合は通常、あまりにも多くのデータが書き込まれますFileOutputStream-instance。

  • クラスjavax.crypto.CipherInputStreamおよびjavax.crypto.CipherOutputStream認証を実行する偽陽性を、したがって、あるではないのドキュメント(Javaの12)からGCMモードに適した、例えばCipherInputStream

    このクラスは、BadPaddingExceptionおよび復号化時に失敗した整合性チェックによってスローされた他の例外をキャッチすることがあります。これらの例外は、スロー再されていないので、クライアントは、整合性チェックが失敗したことを知らされないことがあります。この動作のため、このクラスは、操作の認証済みモード(例えばGCM)での復号化での使用に適しないかもしれません。認証済みの暗号化を必要とするアプリケーションは、このクラスを使用する代わりに直接暗号APIを使用することができます。

    そのため、暗号APIのいずれかは、ドキュメント、またははBouncyCastle-実装で推奨されているように、直接使用されなければならないorg.bouncycastle.crypto.io.CipherInputStreamorg.bouncycastle.crypto.io.CipherOutputStream暗号化のために、例えば:

    import org.bouncycastle.crypto.io.CipherInputStream;
    import org.bouncycastle.crypto.io.CipherOutputStream;
    import org.bouncycastle.crypto.engines.AESEngine;
    import org.bouncycastle.crypto.modes.AEADBlockCipher;
    import org.bouncycastle.crypto.modes.GCMBlockCipher;
    import org.bouncycastle.crypto.params.AEADParameters;
    import org.bouncycastle.crypto.params.KeyParameter;
    ...
    public void encrypt(File inputFile, File outputFile) throws Exception {
    
        AEADBlockCipher cipher = getEncryptionCipher();
        // Following code as before (but with fixes described above)
        ...
    }
    
    public AEADBlockCipher getEncryptionCipher() throws Exception {
    
        AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
        cipher.init(true, // encryption 
            new AEADParameters(
                new KeyParameter(getSecretKey().getEncoded()),  
                128, // tag length
                getInitializationVector(),                      
                "Optional Associated Data".getBytes()));                    
        return cipher;
    }
    ...
    

    そして、復号用のアナログ。

    認証が失敗した場合でも、復号化が行われるので、開発者は、結果を破棄し、この場合に使用されていないことを確認しなければならないことに注意してください。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=335682&siteId=1