[英]Unable to decrypt excel file with apache poi in Android
I hope everybody is healthy in this time of pandemic,疫情期间,希望大家都健健康康
I am successfully able to encrypt Excel file but unable to decrypt.我能够成功加密 Excel 文件但无法解密。 I need help in decrypting excel file in Android.
我需要帮助来解密 Android 中的 excel 文件。 I am using apache poi library.
我正在使用 apache poi 库。 I don't know where I am lacking.
我不知道我缺什么地方。
Password is password密码就是密码
file encrypted with encryptXLSX function is: https://drive.google.com/file/d/1eQV62uFWj5Tg6g7gSmP61mNk_Ta5dMHq/view?usp=sharing用 encryptXLSX function 加密的文件是: https://drive.google.com/file/d/1eQV62uFWj5Tg6g7gSmP61mNk_Ta5dMHq/view?usp=sharing
Encryption code is:加密代码为:
public void encryptXLSX()
throws IOException, GeneralSecurityException, InvalidFormatException {
// input is unprotected excel named as excel.xlsx
String input = "/storage/emulated/0/Android/data/com.protect.excel_protect_example/files/excel.xlsx";
/// output file path
String outputPath = "/storage/emulated/0/Android/data/com.protect.excel_protect_example/files/protected_excel.xlsx";
POIFSFileSystem fs = new POIFSFileSystem();
Biff8EncryptionKey.setCurrentUserPassword("password");
EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
Encryptor enc = info.getEncryptor();
enc.confirmPassword("password");
InputStream fis = new FileInputStream(input);
try (OPCPackage opc = OPCPackage.open(fis); OutputStream os = enc.getDataStream(fs)) {
opc.save(os);
os.close();
}
FileOutputStream fos1 = new FileOutputStream(outputPath);
fs.writeFilesystem(fos1);
fos1.close();
fs.close();
fis.close();
}
Decryption Code is:解密代码为:
public boolean isEncrypted(String path) {
try {
try {
new POIFSFileSystem(new FileInputStream(path));
} catch (IOException ignored) {
}
System.out.println("protected");
return true;
} catch (OfficeXmlFileException e) {
System.out.println("not protected");
return false;
}
}
public byte[] decryptXLSX() throws Exception {
String sourcepath = "/storage/emulated/0/Android/data/com.protect.excel_protect_example/files/protected_excel.xlsx";
InputStream in = null;
FileInputStream fis = new FileInputStream(sourcepath);
if (isEncrypted(sourcepath)) {
org.apache.poi.hssf.record.crypto.Biff8EncryptionKey.setCurrentUserPassword(password);
POIFSFileSystem filesystem = new POIFSFileSystem(fis);
print("Header Block:" + filesystem.getHeaderBlock().toString());
print("property tables:" + filesystem.getRoot().getEntries().toString());
EncryptionInfo info = new EncryptionInfo(filesystem);
//EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
//EncryptionInfo info = new EncryptionInfo(filesystem.getRoot().createDocumentInputStream("EncryptionInfo"), EncryptionMode.agile);
//EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile, CipherAlgorithm.aes256, HashAlgorithm.sha512, 256, 16, ChainingMode.cbc);
Decryptor d = Decryptor.getInstance(info);
if (!d.verifyPassword("password")) {
print("Wrong password");
} else {
print("Good!");
}
in = d.getDataStream(filesystem);
} else {
in = new FileInputStream(sourcepath);
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = in.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] byteArray = buffer.toByteArray();
FileOutputStream fos1 = new FileOutputStream(
"/storage/emulated/0/Android/data/com.protect.excel_protect_example/files/Unprotected_excel.xlsx");
fos1.write(byteArray);
fos1.close();
return byteArray;
}
Error:错误:
org.apache.poi.EncryptedDocumentException: Unable to parse
encryption descriptor
[ ] W/System.err(28825): at
org.apache.poi.poifs.crypt.agile.AgileEncryptionInfoBuilder.parseDescriptor(AgileEncryptionInfoBuilder.java:106)
[ ] W/System.err(28825): at org.apache.poi.poifs.crypt.agile.AgileEncryptionInfoBuilder.initialize(AgileEncryptionInfoBuilder.java:40)
[ ] W/System.err(28825): at org.apache.poi.poifs.crypt.EncryptionInfo.<init>(EncryptionInfo.java:152)
[ ] W/System.err(28825): at org.apache.poi.poifs.crypt.EncryptionInfo.<init>(EncryptionInfo.java:101)
[ +3 ms] W/System.err(28825): at org.apache.poi.poifs.crypt.EncryptionInfo.<init>(EncryptionInfo.java:94)
[ ] W/System.err(28825): at com.protect.excel_protect.decryptXLSX(ExcelProtect.java:182)
The issue on ExcelProtect.java Line 182 in decryption function: ExcelProtect.java 第182行解密function的问题:
EncryptionInfo info = new EncryptionInfo(filesystem);
In my IntelliJ IDEA with Android 10.0 (API-Level 29, Rev. 4) your decryptXLSX-method works like expected so it looks like that your Android version is lower and does not support an internal method or crypto algorithm.在我的带有 Android 10.0(API-Level 29,Rev.4)的 IntelliJ IDEA 中,您的 decryptXLSX 方法按预期工作,因此看起来您的 Android 版本较低,并且不支持内部方法或加密算法。 Maybe you could check the underlying Java version and present it to us.
也许您可以查看底层 Java 版本并将其呈现给我们。 You can do this with:
你可以这样做:
System.out.println("\nJava version:");
String[] javaVersionElements = System.getProperty("java.runtime.version").split("\\.|_|-b");
String discard, major, minor, update, build;
discard = javaVersionElements[0];
major = javaVersionElements[1];
minor = javaVersionElements[2];
update = javaVersionElements[3];
build = javaVersionElements[4];
System.out.println("discard: " + discard + " major: " + major + " minor: " + minor + " update: " + update + " build: " + build);
(Runtime.version isn't running with my Android-build). (Runtime.version 没有与我的 Android 版本一起运行)。
My output is:我的 output 是:
Java version:
discard: 11 major: 0 minor: 5+10 update: 520 build: 17
I didn't check if the the XLSX-encryption needs the unlimited cryptography but just in case you can check that with some codelines:我没有检查 XLSX 加密是否需要无限加密,但以防万一您可以使用一些代码行进行检查:
/**
* Determines if cryptography restrictions apply.
* Restrictions apply if the value of {@link Cipher#getMaxAllowedKeyLength(String)} returns a value smaller than {@link Integer#MAX_VALUE} if there are any restrictions according to the JavaDoc of the method.
* This method is used with the transform <code>"AES/CBC/PKCS5Padding"</code> as this is an often used algorithm that is <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#impl">an implementation requirement for Java SE</a>.
*
* @return <code>true</code> if restrictions apply, <code>false</code> otherwise
*
* code by Maarten Bodewes, https://stackoverflow.com/questions/7953567/checking-if-unlimited-cryptography-is-available#
*/
public static boolean restrictedCryptography() {
try {
return Cipher.getMaxAllowedKeyLength("AES/CBC/PKCS5Padding") < Integer.MAX_VALUE;
} catch (final NoSuchAlgorithmException e) {
throw new IllegalStateException("The transform \"AES/CBC/PKCS5Padding\" is not available (the availability of this algorithm is mandatory for Java SE implementations)", e);
}
}
Just call the method with:只需使用以下方法调用该方法:
System.out.println("Java restricted cryptography: " + restrictedCryptography());
That's my output ("false" means unlimited cryptography):那是我的 output (“假”表示无限加密):
Java restricted cryptography: false
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.