Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将Java应用程序移植到OS X后出现BadPaddingException_Java_Macos_Aes_Jce_Badpaddingexception - Fatal编程技术网

将Java应用程序移植到OS X后出现BadPaddingException

将Java应用程序移植到OS X后出现BadPaddingException,java,macos,aes,jce,badpaddingexception,Java,Macos,Aes,Jce,Badpaddingexception,我正在将Java应用程序移植到OSX(10.8)。我们的一个单元测试在加密时失败(它在Windows上工作)。这两个版本都运行Java 7 Update 21,但Windows版本使用32位JDK,Mac版本使用64位JDK 在Mac上运行时,尝试解密加密数据时出现以下异常: 原因:javax.crypto.BadPaddingException:给定的最终块不是 适当地填充在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:

我正在将Java应用程序移植到OSX(10.8)。我们的一个单元测试在加密时失败(它在Windows上工作)。这两个版本都运行Java 7 Update 21,但Windows版本使用32位JDK,Mac版本使用64位JDK

在Mac上运行时,尝试解密加密数据时出现以下异常:

原因:javax.crypto.BadPaddingException:给定的最终块不是 适当地填充在 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)位于 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)位于 com.sun.crypto.provider.aesciper.engineDoFinal(aesciper.java:313) 位于javax.crypto.Cipher.doFinal(Cipher.java:2087) com.degoo.backend.security.Crypto.processCipher(Crypto.java:56)。。。 25多

这是加密类

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public final class Crypto {

    private final static String CIPHER_ALGORITHM = "AES";
    private final static String CIPHER_TRANSFORMATION = "AES/CBC/PKCS5Padding";

    public final static int CRYPTO_KEY_SIZE = 16;    

    public static byte[] encryptByteArray(byte[] blockToEncrypt, int maxLengthToEncrypt, byte[] encryptionKey, byte[] ivBytes) {
        return processCipher(blockToEncrypt, maxLengthToEncrypt, Cipher.ENCRYPT_MODE, ivBytes, encryptionKey);
    }

    public static byte[] decryptByteArray(byte[] encryptedData, byte[] encryptionKey, byte[] ivBytes) {
        return processCipher(encryptedData, encryptedData.length, Cipher.DECRYPT_MODE, ivBytes, encryptionKey);
    }

    private static byte[] processCipher(byte[] blockToEncrypt, int maxLength, int cryptionMode, byte[] ivBytes, byte[] encryptionKey) {
        try {
            IvParameterSpec iv = new IvParameterSpec(ivBytes);
            final Cipher cipher = initCipher(cryptionMode, iv, encryptionKey);
            return cipher.doFinal(blockToEncrypt, 0, maxLength);
        } catch (Exception e) {
            throw new RuntimeException("Failure", e);
        }
    }

    private static Cipher initCipher(int cryptionMode, IvParameterSpec iv, byte[] encryptionKey) {
        KeyGenerator keyGen;
        try {
            keyGen = KeyGenerator.getInstance(CIPHER_ALGORITHM);

            final SecureRandom randomSeed = new SecureRandom();
            randomSeed.setSeed(encryptionKey);
            keyGen.init(CRYPTO_KEY_SIZE * 8, randomSeed);

            // Generate the secret key specs.
            final SecretKey secretKey = keyGen.generateKey();

            final SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), CIPHER_ALGORITHM);

            // Instantiate the cipher
            final Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);

            cipher.init(cryptionMode, secretKeySpec, iv);
            return cipher;

        } catch (Exception e) {
            throw new RuntimeException("Failure", e);
        }
    }
}
测试代码如下所示:

public void testEncryption() throws Exception {
        int dataLength = TestUtil.nextInt(applicationParameters.getDataBlockMinSize());
        byte[] dataToEncrypt = new byte[dataLength];
        TestUtil.nextBytes(dataToEncrypt);

        int keyLength = 16;
        byte[] key = new byte[keyLength];
        TestUtil.nextBytes(key);

        byte[] ivBytes = new byte[16];
        TestUtil.nextBytes(key);

        long startTime = System.nanoTime();
        byte[] encryptedBlock = Crypto.encryptByteArray(dataToEncrypt, dataToEncrypt.length, key, ivBytes);
        long endTime = System.nanoTime();
        System.out.println("Encryption-speed: " + getMBPerSecond(dataLength, startTime, endTime));

        startTime = System.nanoTime();
        byte[] decryptedData = Crypto.decryptByteArray(encryptedBlock, key, ivBytes);
        endTime = System.nanoTime();
        System.out.println("Decryption-speed: " + getMBPerSecond(dataLength, startTime, endTime));

        if (encryptedBlock.length == decryptedData.length) {
            boolean isEqual = true;
            //Test that the encrypted data is not equal to the decrypted data.
            for (int i = 0; i < encryptedBlock.length; i++) {
                if (encryptedBlock[i] != decryptedData[i]) {
                    isEqual = false;
                    break;
                }
            }
            if (isEqual) {
                throw new RuntimeException("Encrypted data is equal to decrypted data!");
            }
        }

        Assert.assertArrayEquals(dataToEncrypt, decryptedData);
    }
final SecretKeySpec secretKeySpec = new SecretKeySpec(encryptionKey, CIPHER_ALGORITHM);

// Instantiate the cipher
final Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);

cipher.init(cryptionMode, secretKeySpec, iv);
return cipher;
public void testEncryption()引发异常{
int dataLength=TestUtil.nextInt(applicationParameters.getDataBlockMinSize());
字节[]dataToEncrypt=新字节[dataLength];
TestUtil.nextBytes(数据加密);
int keyLength=16;
字节[]键=新字节[keyLength];
TestUtil.nextBytes(键);
字节[]ivBytes=新字节[16];
TestUtil.nextBytes(键);
long startTime=System.nanoTime();
byte[]encryptedBlock=Crypto.encryptByteArray(dataToEncrypt,dataToEncrypt.length,key,ivBytes);
long-endTime=System.nanoTime();
System.out.println(“加密速度:+getMBPerSecond(数据长度、开始时间、结束时间));
startTime=System.nanoTime();
byte[]decryptedData=Crypto.decryptByteArray(encryptedBlock,key,ivBytes);
endTime=System.nanoTime();
System.out.println(“解密速度:+getMBPerSecond(数据长度、开始时间、结束时间));
if(encryptedBlock.length==decryptedData.length){
布尔相等=真;
//测试加密数据是否与解密数据不相等。
对于(int i=0;i
我想我找到了。出于某种原因,上面的代码通过将现有加密密钥植入SecureRandom实例以获得新的字节[](不要问我为什么,它是很久以前编写的)。然后将其提供给SecretKeySpec构造函数。如果我跳过所有这些,只向SecretKeySpec构造函数提供我们已经拥有的加密密钥,那么单元测试就通过了。现在执行加密的代码如下所示:

public void testEncryption() throws Exception {
        int dataLength = TestUtil.nextInt(applicationParameters.getDataBlockMinSize());
        byte[] dataToEncrypt = new byte[dataLength];
        TestUtil.nextBytes(dataToEncrypt);

        int keyLength = 16;
        byte[] key = new byte[keyLength];
        TestUtil.nextBytes(key);

        byte[] ivBytes = new byte[16];
        TestUtil.nextBytes(key);

        long startTime = System.nanoTime();
        byte[] encryptedBlock = Crypto.encryptByteArray(dataToEncrypt, dataToEncrypt.length, key, ivBytes);
        long endTime = System.nanoTime();
        System.out.println("Encryption-speed: " + getMBPerSecond(dataLength, startTime, endTime));

        startTime = System.nanoTime();
        byte[] decryptedData = Crypto.decryptByteArray(encryptedBlock, key, ivBytes);
        endTime = System.nanoTime();
        System.out.println("Decryption-speed: " + getMBPerSecond(dataLength, startTime, endTime));

        if (encryptedBlock.length == decryptedData.length) {
            boolean isEqual = true;
            //Test that the encrypted data is not equal to the decrypted data.
            for (int i = 0; i < encryptedBlock.length; i++) {
                if (encryptedBlock[i] != decryptedData[i]) {
                    isEqual = false;
                    break;
                }
            }
            if (isEqual) {
                throw new RuntimeException("Encrypted data is equal to decrypted data!");
            }
        }

        Assert.assertArrayEquals(dataToEncrypt, decryptedData);
    }
final SecretKeySpec secretKeySpec = new SecretKeySpec(encryptionKey, CIPHER_ALGORITHM);

// Instantiate the cipher
final Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION);

cipher.init(cryptionMode, secretKeySpec, iv);
return cipher;
奇怪的是,它在Windows上工作。看起来SecureRandom实现在OS X和Windows上的行为有所不同。在OS X上调用setSeed会附加到seed,而Windows会替换它


更新:找到有关SecureRandom实现差异的更多详细信息:

是的,该代码是正确的。作者可能试图(徒劳地)创建一个基于键的键派生函数。如果
encryptionKey
数组具有足够的熵,但不是完全随机的,或者
encryptionKey
的大小不正确,这将非常有用。在这种情况下,您应该真正使用真正的KDF,如HKDF(实现,例如在Bouncy Castle中,最新版本)或NIST KDF之一(实现,例如在Bouncy Castle中,但仅在最新源代码中)。哦,谢谢您的回复。否则我会给你这个答案的。请注意,上有一个臭名昭著的示例使用了这个“密钥派生函数”,许多代码都基于它。我无法将其删除,也无法登录该站点(典型的情况是,Google openID由于服务器上的实现错误而失败)。阅读页面底部的评论并哭泣。感谢您的澄清!是的,encryptionKey已经有了足够的熵,并且大小正确,所以绝对不需要代码。我发现互联网上有那么多真正糟糕的加密代码示例,这很有趣。我想我见过更多使用ECB而不是CBC的示例代码。:)同样有趣的是,文档明确指出“给定的种子补充,而不是替换现有的种子。因此,重复调用保证永远不会减少随机性。”。奇怪的是,Windows实现的如此基本和重要的功能与文档不匹配。这并不是不正确的,因为它是唯一的种子。然而,问题是RNG是否已自动播种。您可以通过获取随机数据来触发此操作。以这种方式使用PRNG可能很有用,但在我看来,他们应该简单地使用
“SHA1PRNG/unseed”
选项,而不是一些神奇的、特定于提供商的技巧。