0

I hope everybody is healthy in this time of pandemic,

I am successfully able to encrypt Excel file but unable to decrypt. I need help in decrypting excel file in Android. I am using apache poi library. 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

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:

        EncryptionInfo info = new EncryptionInfo(filesystem);
group work
  • 33
  • 7
  • 1
    It should not matter if it is an excel file or any other type of file. Further we see no -excel- file to begin with. – blackapps Jun 09 '20 at 09:37
  • 2
    You are not showing how you call decryptXLSX() nor why it should have a byte[] parameter nor what would be in it. – blackapps Jun 09 '20 at 09:41
  • I had updated the question with the code and file which is protected from encryption function and can't be decrypted with decryption function. – group work Jun 09 '20 at 09:52
  • I am able to run and decrypt file with the above decryptXLSX function on core java file on desktop directory i.e. outside Android Project but in Android Project I am getting the above issue. I have been trying to change EncryptionInfo from yesterday night but unable to figure it out, Help will save my day bro – group work Jun 09 '20 at 09:58
  • 1
    InputStream fis is not used by fs nor by writing to fos1. So your output file has nothing to do with the input file as far as i can see. – blackapps Jun 09 '20 at 10:05
  • EncryptXLSX code is working fine and it it encrypting the excel.xlsx. It is the exact same code told here on official documentation of apache poi: https://poi.apache.org/encryption.html – group work Jun 09 '20 at 10:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/215571/discussion-between-group-work-and-blackapps). – group work Jun 09 '20 at 10:13
  • FileInputStream fis is the input stream of excel.xlsx and yeah it is used by OPC package.... I had also tried to open this protected_excel.xlsx file with microsoft excel with password as password and it is opening there easily – group work Jun 09 '20 at 10:16
  • I see now indeed. Complicated connection. For the rest i cannot help you. – blackapps Jun 09 '20 at 10:18

1 Answers1

0

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. Maybe you could check the underlying Java version and present it to us. 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).

My output is:

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:

/**
 * 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):

Java restricted cryptography: false
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40
  • Okay I will check it now and will tell you if it works or not. – group work Jun 10 '20 at 11:41
  • @groupwork: if you can debug your program, please check the exception at AgileEncryptionInfoBuilder::parseDescriptor - I have a feeling that XmlBeans can't process the input because of either missing or duplicated jars in your classpath ... i.e. your stacktrace doesn't contain the nested exception – kiwiwings Jun 10 '20 at 22:11