我目前工作的一個解密算法來解密一個PDF我從服務器接收的電子書閱讀器應用程序。 在iOS上運行的等效代碼非常完美,我現在試圖讓代碼在Android上運行。安卓解密:最後塊(16個字節)中缺少結果文件
只是一些細節,解密是AES和ECB模式下運行。加密密鑰是一個十六進制字符串數組,我將其轉換爲一個字節數組(通過將每兩個字符轉換爲一個字節,例如:「FF」變爲255等)。
我正在經歷非常有趣。我比較iOS和Android解密後的結果文件,我注意到Android解密文件比iOS解密文件短16個字節,特別是最後。所有其他字節是相同的(我會在下面的一些例子)。
這種差異是造成我的電子書閱讀器拒絕打開PDF文件,而它成功打開iOS圖書。
這裏是我的解密代碼:
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(的Android):
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
什麼我注意到的是,最後一個字節都在最後幾個相同的字節數,等於量他們出現的時間。在第1冊iOS中,在最後一個塊中,字節08正好出現8次。在書2的iOS,在最後的塊,字節0E(14)出現整整14倍,等等
除此之外,我不知道什麼花樣的現象發生,所以我不知道我怎麼能解決此問題。
我使用以下不同的填充類型已經嘗試過:
ZeroBytePadding, NoPadding, PKCS5Padding, PKCS7Padding
任何想法,將不勝感激。
其實我會懷疑你也有一個錯誤的iPhone實現,因爲你似乎在輸出中得到填充。你有沒有填充選項的iPhone解密?使用填充選項時,解密方法無法知道解密數據是實際數據還是最終填充,直到調用最終方法爲止。它將保持緩衝區中的最後一塊數據,直到它知道它的填充或真實數據。 –
解密由第三方圖書供應商完成。我們從他們那裏收到了解密指南,以及樣本解密書籍與之比較。根據他們,最後的額外字節應該在那裏。 –
那麼,巧合(!),看起來像一個[PKCS#7填充](http://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7)看起來... –