我目前正在研究一种解密算法来解密我从服务器接收的用于电子书阅读器应用程序的 PDF。在 iOS 上运行的等效代码可以完美运行,我现在正试图让代码在 Android 上运行。
只是一些细节,解密是AES并以ECB模式运行。加密密钥是一个十六进制字符串数组,我将其转换为字节数组(通过将每两个字符转换为一个字节,例如:“FF”变为 255,等等)。
我正在经历的事情非常有趣。我正在比较从 iOS 和 Android 解密后的结果文件,我注意到 Android 解密文件比 iOS 解密文件短 16 个字节,特别是最后。所有其他字节都是相同的(我将在下面发布一些示例)。
这种差异导致我的电子书阅读器在成功打开 iOS 书籍时拒绝打开 PDF。
这是我的解密代码:
private void performDecryption(DocumentModel document)
{
byte[] keyBytes = generateByteArray(document.getEncryptionKey());
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");
File encryptedDocument = new File(getBookFolderDocumentName(document, document.getFileSuffix()));
File decryptedDocument = new File(BOOK_FOLDER + document.getGeneratedAssetName() + "_decrypted" + "." + document.getFileSuffix());
decryptedDocument.mkdirs();
if (decryptedDocument.exists())
decryptedDocument.delete();
Cipher cipher = null;
try
{
cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
}
catch (NoSuchAlgorithmException noSuchAlgorithmEx)
{
Log.e("Decryption", "NoSuchAlgorithmException: " + noSuchAlgorithmEx.getMessage());
}
catch (NoSuchPaddingException noSuchPaddingEx)
{
Log.e("Decryption", "NoSuchPaddingException: " + noSuchPaddingEx.getMessage());
}
catch (InvalidKeyException invalidKeyEx)
{
Log.e("Decryption", "InvalidKeyException: " + invalidKeyEx.getMessage());
}
FileInputStream encryptedFileStream = null;
FileOutputStream decryptedFileStream = null;
try
{
encryptedFileStream = new FileInputStream(encryptedDocument);
decryptedFileStream = new FileOutputStream(decryptedDocument);
long totalFileSize = encryptedDocument.length();
long totalDecrypted = 0;
int lastPercentage = -1;
int currentPercentage = 0;
byte[] encryptedBuffer = new byte[4096];
byte[] decryptedBuffer = new byte[4096];
int encryptedLength = 0;
int decryptedLength = 0;
while((encryptedLength = encryptedFileStream.read(encryptedBuffer)) > 0)
{
while (encryptedLength % 16 != 0) // the code never lands in this loop
{
encryptedBuffer[encryptedLength] = 0;
encryptedLength++;
}
decryptedLength = cipher.update(encryptedBuffer, 0, encryptedLength, decryptedBuffer);
while (decryptedLength % 16 != 0) // the code never lands in this loop
{
decryptedBuffer[decryptedLength] = 0;
decryptedLength++;
}
decryptedFileStream.write(decryptedBuffer, 0, decryptedLength);
totalDecrypted += encryptedLength;
currentPercentage = (int)(((float)totalDecrypted / (float)totalFileSize) * 100f);
if (currentPercentage != lastPercentage)
{
lastPercentage = currentPercentage;
Log.i("Decryption", "Decrypting... " + currentPercentage + "%");
}
}
Log.i("Decryption", "Finished decrypting!");
}
catch (FileNotFoundException fileNotFoundEx)
{
Log.e("Decryption", "FileNotFoundException: " + fileNotFoundEx.getMessage());
}
catch (IOException ioEx)
{
Log.e("Decryption", "IOException: " + ioEx.getMessage());
}
catch (ShortBufferException e)
{
e.printStackTrace();
}
finally
{
}
try
{
encryptedFileStream.close();
decryptedFileStream.close();
cipherOutputStream.close();
}
catch (IOException e1)
{
}
document.setDecryptedFilePath(decryptedDocument.getAbsolutePath());
Log.i("Decryption", "Finished!");
}
以下是 pdf 文件中的一些示例(我使用十六进制阅读器来获取这些结果):
书 1 (iOS):
0D 0A 3C 3C 2F 53 69 7A 65 20 35 38 31 3E 3E 0D
0A 73 74 61 72 74 78 72 65 66 0D 0A 31 31 36 0D
0A 25 25 45 4F 46 0D 0A 08 08 08 08 08 08 08 08 <-- this block is missing in android.
书 1(安卓):
0D 0A 3C 3C 2F 53 69 7A 65 20 35 38 31 3E 3E 0D
0A 73 74 61 72 74 78 72 65 66 0D 0A 31 31 36 0D
第 2 册(iOS):
65 6E 64 6F 62 6A 0D 73 74 61 72 74 78 72 65 66
0D 0A 34 30 36 32 35 33 36 0D 0A 25 25 45 4F 46
0D 0A 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E 0E <-- this block is missing in android.
第 2 册(安卓):
65 6E 64 6F 62 6A 0D 73 74 61 72 74 78 72 65 66
0D 0A 34 30 36 32 35 33 36 0D 0A 25 25 45 4F 46
我注意到的是最后一个字节最后有几个相同的字节,等于它们出现的次数。在 iOS 的书 1 中,在最后一个块中,字节 08 恰好出现了 8 次。在 iOS 书 2 中,在最后一个块中,字节 0e (14) 恰好出现了 14 次,以此类推。
除此之外,我不确定正在发生什么模式,所以我不确定如何解决这个问题。
我已经尝试过使用以下不同的填充类型:
ZeroBytePadding, NoPadding, PKCS5Padding, PKCS7Padding
任何想法将不胜感激。