Skip to content

Conversation

@manisocgen
Copy link

Added the encryption support with multiple algorithms, including Standard, BinaryRC4, RC4CipherApi and Agile.

For .xls files, the default encryption algorithm used for password protection is RC4CipherApi. For .xlsx and .xlsm files, Agile encryption/decryption is applied by default. Even Standard encryption and decryption was validated and it worked.

Encryption and decryption functionality has been validated through unit tests, and results have been satisfactory so far.

Below test cases are validated,

// 97 Binary file (xls)
 [TestCase("97_plain.xls", "97_plain_protected.xls", true)] // plain -> protect (default)
 [TestCase("97_password.xls", "97_password_unprotected.xls", false, false)] // protect -> plain
 [TestCase("97_rc4cryptoapi_password.xls", "97_rc4cryptoapi_password_unprotected.xls", false, false)] // protect -> plain
 [TestCase("97_password.xls", "97_password_protected.xls", false)] // protect -> protect
 [TestCase("97_rc4cryptoapi_password.xls", "97_rc4cryptoapi_password_protected.xls", false)] // protect -> protect
 //2007 Office Open XML file (xlsx)
 [TestCase("2007_plain.xlsx", "2007_plain_protected.xlsx", true)] // plain -> protect
 [TestCase("2007_password.xlsx", "2007_password_unprotected.xlsx", false, false)] // protect -> plain
 [TestCase("2007_password.xlsx", "2007_password_protected.xlsx", false)] // protect -> protect
 //2007 Macro enabled file (xlsm)
 [TestCase("2007macro_plain.xlsm", "2007macro_plain_protected.xlsm", true)] // plain -> protect
 [TestCase("2007macro_password.xlsm", "2007macro_password_unprotected.xlsm", false, false)] // protect -> plain
 [TestCase("2007macro_password.xlsm", "2007macro_password_protected.xlsm", false)] // protect -> protect

 public void TestWriteAndReadPasswordEncryption(
           string inputFileName,
           string outputFileName,
           bool isPlain = false,
           bool protectOutput = true,
           string openPassword = "Password1234_")

Save the workbook

private void SaveWorkbook(IWorkbook workbook, Stream outStream, string password = null)
{
    if(string.IsNullOrEmpty(password))
    {
        var leaveStreamOpen = outStream is not FileStream;
        workbook.Write(outStream, leaveStreamOpen);
    }
    else
    {
        if(workbook is HSSFWorkbook hssfWorkbook)
        {
            Biff8EncryptionKey.CurrentUserPassword = password;
            try
            {
                workbook.Write(outStream);
            }
            finally
            {
                //Make sure to clear the password after saving to avoid affecting other operations
                Biff8EncryptionKey.CurrentUserPassword = null;
            }
        }
        else if(workbook is XSSFWorkbook xssfWorkbook)
        {
            // Set up encryption
            var fs = new POIFSFileSystem();
            var info = new EncryptionInfo(EncryptionMode.Agile);
            var encryptor = info.Encryptor;
            encryptor.ConfirmPassword(password);

            // Save workbook to encrypted output stream
            using(var outputStream = encryptor.GetDataStream(fs))
            {
                xssfWorkbook.Write(outputStream);
            }

            // Write out the encrypted version
            fs.WriteFileSystem(outStream);
        }
        else
        {
            throw new NotSupportedException("Workbook type not supported for password protection.");
        }
    }
}

private IWorkbook LoadWorkbook(Stream stream, string openPassword)
{
    if(stream == null)
    {
        throw new ArgumentNullException(nameof(stream));
    }

    if(stream.CanSeek)
    {
        stream.Seek(0, SeekOrigin.Begin);
    }

    return WorkbookFactory.Create(stream, openPassword);
}

In repository, all unit tested are passed except below too as it was recurring issue in origin branch too.
BaseTestBugzillaIssues.Test52684() 
BaseTestDataFormat.Test55265()

…dard, BinaryRC4, RC4CipherApi and Agile.

For .xls files, the default encryption algorithm used for password protection is RC4CipherApi.
For .xlsx and .xlsm files, Agile encryption/decryption is applied by default. Even Standard encryption and decryption was validated and  it worked.

Encryption and decryption functionality has been validated through unit tests, and results have been satisfactory so far.

In repository, all unit tested are passed except below too as it was recurring issue in origin branch too.
 BaseTestBugzillaIssues.Test52684() 
 BaseTestDataFormat.Test55265()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant