Spring Security Crypto最终块没有正确填充

时间:2016-07-06 16:00:08

标签: java encryption spring-security

我试图使用spring security crypto创建文件加密概念证明。根据我发现的其他一些帖子,我已经下载了Unlimited JCE Policy并将jar文件添加到我的java_home / jre / lib / security文件夹中。

调用bytesEncryptor.decrypt时发生错误。加密可能正在工作,因为执行后文件中存在加密内容,但我不确定是否有办法确认问题所在。关于这个错误的一些其他帖子并没有使用Spring说关键是不对的,但这不是因为我使用相同的bytesEncryptor对象? (Given final block not properly padded

堆栈:

Exception in thread "main" java.lang.IllegalStateException: Unable to invoke Cipher due to bad padding
at org.springframework.security.crypto.encrypt.CipherUtils.doFinal(CipherUtils.java:142)
    at org.springframework.security.crypto.encrypt.AesBytesEncryptor.decrypt(AesBytesEncryptor.java:128)
    at com.test.encryption.MyTest.crypt(MyTest.java:45)
    at com.test.encryption.MyTest.decryptFile(MyTest.java:31)
    at com.test.encryption.MyTest.main(MyTest.java:21)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at org.springframework.security.crypto.encrypt.CipherUtils.doFinal(CipherUtils.java:135)
... 4 more

代码:

public static void main(String args[]) throws Exception {
    String salt = KeyGenerators.string().generateKey();
    BytesEncryptor bytesEncryptor = Encryptors.standard("password", salt);

    encryptFile(bytesEncryptor, "C:/test/testIn.txt", "C:/test/testOut.txt");
    decryptFile(bytesEncryptor, "C:/test/testOut.txt", "C:/test/testOutDecode.txt");
}


private static void encryptFile (BytesEncryptor bytesEncryptor, String in, String out) throws Exception {
    crypt(bytesEncryptor, in, out, true);
}

private static void decryptFile (BytesEncryptor bytesEncryptor, String in, String out) throws Exception {
    crypt(bytesEncryptor, in, out, false);
}

private static void crypt (BytesEncryptor bytesEncryptor, String in, String out, boolean encrypt) throws Exception {
    byte[] buffer = new byte[1024];
    int numRead;
    byte[] bytes = null;
    InputStream input = new FileInputStream(in);
    OutputStream output = new FileOutputStream(out);

    while ((numRead = input.read(buffer)) > 0) {
        if(encrypt) {
            bytes = bytesEncryptor.encrypt(buffer);
        } else {
            bytes = bytesEncryptor.decrypt(buffer);
        }

        if (bytes != null) {
            output.write(bytes, 0, numRead);
        }
    }

    input.close();
    output.close();
}

3 个答案:

答案 0 :(得分:0)

我怀疑问题来自于他们以1024字节的块读取文件的方式。 AES是一种分组密码,因此可以对特定大小的数据块进行操作。当它加密时,它将填充输出以确保它适合适当大小的块。当你将数据提供给解密时,它希望在必要时对数据进行类似的填充。

尝试将整个文件读入字节数组,然后加密和解密。或者,您可以尝试使用与您用于AES的块大小相匹配的块大小(它将是128,192或256位)。

答案 1 :(得分:0)

原则上你需要为FileInputStreams和FileOutputStreams使用CipherInputStream和CipherOutputStream。

以下内容或多或少取自此http://www.programcreek.com/java-api-examples/index.php?source_dir=cube-master/cube-common/src/main/java/ch/admin/vbs/cube/common/crypto/AESEncrypter.java

更新的代码:

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;

public class MyTest {

    private static String algorithm = "AES/CBC/PKCS5Padding";

    public static void main(String args[]) throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256);
        SecretKey secretKey = keyGen.generateKey();

        final int AES_KEYLENGTH = 256;
        byte[] iv = new byte[AES_KEYLENGTH / 16];
        SecureRandom prng = new SecureRandom();
        prng.nextBytes(iv);

        Cipher aesCipherForEncryption = Cipher.getInstance(algorithm);
        Cipher aesCipherForDecryption = Cipher.getInstance(algorithm);
        aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
        aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));

        encryptFile(aesCipherForEncryption, "C:/test/testIn.txt", "C:/test/testOut.txt");
        decryptFile(aesCipherForDecryption, "C:/test/testOut.txt", "C:/test/testOutDecode.txt");
    }


    private static void encryptFile (Cipher cipher, String in, String out) throws Exception {
        crypt(cipher, in, out, true);
    }

    private static void decryptFile (Cipher cipher, String in, String out) throws Exception {
        crypt(cipher, in, out, false);
    }

    private static void crypt (Cipher cipher, String in, String out, boolean encrypt) throws Exception {
        byte[] buffer = new byte[256];
        int numRead;
        InputStream input = new FileInputStream(in);
        OutputStream output = new FileOutputStream(out);

        if(encrypt) {
            output = new CipherOutputStream(output, cipher);
        } else {
            input = new CipherInputStream(input, cipher);
        }

        while ((numRead = input.read(buffer)) >= 0) {
            output.write(buffer, 0, numRead);
        }

        input.close();
        output.close();
    }
}

注意 - 我最终没有使用Spring Security Crypto实现。

答案 2 :(得分:0)

对于它的价值,当我使用错误的密码/盐解密(虽然长度相同)时,我得到了此消息