現在、eBook リーダー アプリ用にサーバーから受信している PDF を復号化するための復号化アルゴリズムに取り組んでいます。完全に動作する iOS で動作する同等のコードがあります。現在、コードを Android で実行しようとしています。
詳細については、復号化は AES であり、ECB モードで実行されます。暗号化キーは、バイト配列に変換する 16 進文字列配列です (2 文字ごとに 1 バイトに変換します。たとえば、「FF」は 255 になります)。
私が経験していることは非常に興味深いものです。iOS と Android の両方から復号化した後の結果ファイルを比較していますが、一貫して、Android 復号化ファイルは iOS 復号化ファイルよりも 16 バイト短いことに気付きました。他のすべてのバイトは同じです (いくつかの例を以下に掲載します)。
この違いにより、私の eBook リーダーは 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 ファイルのサンプルをいくつか示します (これらの結果を得るために 16 進リーダーを使用しました)。
ブック 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 (Android):
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
私が気づいているのは、最後のバイトの最後に、それらが出現する回数と同じ数の同一のバイトがあることです。book 1 iOS では、最後のブロックでバイト 08 がちょうど 8 回出現します。book 2 iOS では、最後のブロックで、バイト 0e (14) がちょうど 14 回出現します。
それ以外は、どのようなパターンで発生しているのかわからないので、どうすれば解決できるのかわかりません。
私はすでに次の異なるパディングタイプを使用してみました:
ZeroBytePadding, NoPadding, PKCS5Padding, PKCS7Padding
どんなアイデアでも大歓迎です。