1

I'm trying to apply encryption to a binary xls file with Apache POI. While I can successfully encrypt xml based files, if I encrypt a binary one I can't open it and I get the wrong password error.

This is my code:

@Test
public void testEncryption() throws Exception {

    File file = new File("file.xls");

    Workbook workbook = new HSSFWorkbook();
    setData(workbook);
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    workbook.write(fileOutputStream);
    fileOutputStream.close();

    encryptFile(file, "pass");
}

public void encryptFile(File file, String encryptKey) throws Exception {

    FileInputStream fileInput = new FileInputStream(file.getPath());
    BufferedInputStream bufferInput = new BufferedInputStream(fileInput);
    POIFSFileSystem poiFileSystem = new POIFSFileSystem(bufferInput);
    Biff8EncryptionKey.setCurrentUserPassword(encryptKey);

    HSSFWorkbook workbook = new HSSFWorkbook(poiFileSystem, true);
    FileOutputStream fileOut = new FileOutputStream(file.getPath());
    workbook.writeProtectWorkbook(Biff8EncryptionKey.getCurrentUserPassword(), "");
    workbook.write(fileOut);
    bufferInput.close();
    fileOut.close();

    Biff8EncryptionKey.setCurrentUserPassword(null);
}
firegloves
  • 5,581
  • 2
  • 29
  • 50
  • 1
    Your code is similar to but does not entirely match https://github.com/ahaleemnka/ExcelProtection -- could try that sample? – PJ Fanning Mar 13 '21 at 23:23
  • 1
    With [#65192](https://bz.apache.org/bugzilla/show_bug.cgi?id=65192) you can change the EncryptionMode of the HSSFWorkbook to binaryRC4 which allows it to be opened in LibreOffice. Of course the prefered way of encryption would be agile encryption on a XSSFWorkbook. This will be available in the upcoming POI 5.0.1 (or 6.0.0) – kiwiwings Mar 17 '21 at 22:56

1 Answers1

1

To encrypt HSSF you simply do Biff8EncryptionKey.setCurrentUserPassword before writing the HSSFWorkbook.

Simplest example is as this:

import java.io.FileOutputStream;

import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

public class EncryptHSSF {
    
 static void setData(HSSFWorkbook workbook) {
   Sheet sheet = workbook.createSheet();
   Row row = sheet.createRow(0);
   Cell cell = row.createCell(0);
   cell.setCellValue("Test");
 }

 public static void main(String[] args) throws Exception {
  try (HSSFWorkbook workbook = new HSSFWorkbook();
       FileOutputStream out = new FileOutputStream("file.xls") ) {
    
   setData(workbook);       

   Biff8EncryptionKey.setCurrentUserPassword("pass");
   workbook.write(out);
   
  }
 }
}

This works for me. If I open file.xls using Excel it asks me for password and if I type pass there, the workbook opens.

If the aim is encrypting an existing unencrypted workbook, then this would be as so:

import java.io.FileOutputStream;
import java.io.FileInputStream;

import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

public class EncryptHSSFExistingFile {
    
 public static void main(String[] args) throws Exception {
  try (HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream("Unencrypted.xls"));
       FileOutputStream out = new FileOutputStream("Encrypted.xls") ) {
    
   Biff8EncryptionKey.setCurrentUserPassword("pass");
   workbook.write(out);
   
  }
 }
}

So same solution. Simply do Biff8EncryptionKey.setCurrentUserPassword before writing the HSSFWorkbook.

This code only creates correct encrypted workbooks for usage with Microsoft Excel. LibreOffice Calc is not able to open those files. So seems encrypting method used is unknown for LibreOffice Calc. But I have not found a way to change encrypting method for HSSF. So HSSF encryption seems not be fully provided in apache poi. Apache POI - Encryption support also not shows an example. So you are able opening and rewriting encrypted HSSFWorkbook. The new written workbook is encrypted too then if Biff8EncryptionKey.setCurrentUserPassword is not set null. But you cannot write an encrypted HSSFWorkbook from scratch.

Axel Richter
  • 56,077
  • 6
  • 60
  • 87
  • I'm not sure, but I think the ops problem is a combination of encrypting an existing file and preserving the old records. So the from-scratch solution might not apply here. – kiwiwings Mar 14 '21 at 09:20
  • @kiwiwings: Maybe, but same solution though: Simply do `Biff8EncryptionKey.setCurrentUserPassword` before writing the `HSSFWorkbook`. – Axel Richter Mar 14 '21 at 09:32
  • My problem was that I was opening it with LibreOffice and I was getting an error! Thanks, your response gave me the confirm that helped me to figure out the problem – firegloves Mar 16 '21 at 09:22
  • 2
    @firegloves: You are correct. There is a problem using `LibreOffice Calc`. See my supplements. – Axel Richter Mar 16 '21 at 16:39
  • @AxelRichter: I have an unfinished fix for the trunk version. The reason for the Libre Office failure is, that POI by default generates a CryptoAPI encryption info and this seems not to be supported by LO. It's possible to force binaryRC4, but it will fail when writing the document properties. I'll try to refactor and document it in a nicer way. – kiwiwings Mar 17 '21 at 00:02