简体   繁体   English

无法使用 Android 中的 apache poi 解密 excel 文件

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM