在安卓系统中无法用apache poi解密excel文件。

问题描述 投票:0回答:1

希望大家在这个流行病的时候,身体健康。

我已经成功加密了Excel文件,但无法解密,我需要帮助在Android中解密excel文件,我使用的是apache poi库,我不知道我哪里不足。我使用的是apache poi库,不知道自己哪里不足。

密码是密码

用 encryptXLSX 函数加密的文件是 。https:/drive.google.comfiled1eQV62uFWj5Tg6g7gSmP61mNk_Ta5dMHqview?usp=sharing。

加密码是:

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();
}

解密码是:

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;
}

错误:

    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)

问题出在ExcelProtect.java的解密函数第182行。

        EncryptionInfo info = new EncryptionInfo(filesystem);
java android excel encryption apache-poi
1个回答
0
投票

在我的IntelliJ IDEA with Android 10.0 (API-Level 29, Rev. 4)中,你的decryptXLSX-method的工作原理和预期一样,所以看起来你的Android版本较低,不支持内部方法或加密算法。也许你可以检查一下底层的Java版本,然后告诉我们。你可以通过以下方法来实现。

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在我的安卓版本中没有运行).

我的输出是。

Java version:
discard: 11 major: 0 minor: 5+10 update: 520 build: 17

我没有检查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);
    }
}

只需调用该方法:

System.out.println("Java restricted cryptography: " + restrictedCryptography());

这就是我的输出("false "意味着无限加密)。

Java restricted cryptography: false
© www.soinside.com 2019 - 2024. All rights reserved.