gpt4 book ai didi

java - 将 Java 应用程序移植到 OS X 后发生 BadPaddingException

转载 作者:行者123 更新时间:2023-11-30 04:14:34 24 4
gpt4 key购买 nike

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

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

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 com.degoo.backend.security.Crypto.processCipher(Crypto.java:56) ... 25 more

这是加密类。

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);
}

最佳答案

我想我已经找到了。由于某种原因,上面的代码通过使用现有加密 key 播种 SecureRandom 实例来获取新的 byte[] 来派生加密 key (不要问我为什么,这是很久以前编写的)。然后将其提供给 SecretKeySpec 构造函数。如果我跳过所有这些,只向 SecretKeySpec 构造函数提供我们已有的加密 key ,则单元测试将通过。执行加密的代码现在如下所示:

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 会附加到种子,而 Windows 则会替换它。

更新:发现了有关 SecureRandom 实现差异的更多详细信息:http://www.cigital.com/justice-league-blog/2009/08/14/proper-use-of-javas-securerandom/

关于java - 将 Java 应用程序移植到 OS X 后发生 BadPaddingException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18742733/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com