我正在将我们的 Java 应用程序移植到 OS X (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) 的 com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811) 正确填充:676) 在 com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.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);
}