如何使用Open XML保护Excel文档密码

6

目前,我正在使用Open XML的SpreadsheetDocument类通过传递MemoryStream参数创建一个新的Excel文档。现在我需要在这个SpreadsheetDocument对象上设置密码,但是我的尝试似乎没有起作用。Excel文档打开时不会要求输入密码。 以下是我目前尝试过的代码(memMemoryStream参数):

using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(mem, true))
{
    foreach (var sheet in spreadsheet.WorkbookPart.WorksheetParts)
    {
        sheet.Worksheet.Append(new SheetProtection() { Password = "test" });
    }
}

我尝试了以下方法,但都没有成功:
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(mem, true))
{
    spreadsheet.WorkbookPart.Workbook.WorkbookProtection = new WorkbookProtection
    {
        LockStructure = true,
        LockWindows = true,
        WorkbookPassword = "test"
    }
}

请问我错过了什么?


可能是Excel File Password Protection with Open XML SDK的重复问题。 - M O'Connell
是的,这就是我第一次尝试获取代码示例的地方,但没有成功。 - Rudolf Lamprecht
你有没有注意到,另一个SO帖子的答案建议在不起作用的情况下调用Save()方法? // add this in case it still doesn’t work. This makes sure the data is saved. //worksheet.Worksheet.Save(); 你试过了吗?这也没帮助吗? - Michael
是的,我确实尝试为每个工作表部分实现“Save()”方法。它唯一的影响是使Excel文档损坏。 - Rudolf Lamprecht
3个回答

9

Openxml表格保护密码的数据类型为“HexBinaryValue”。因此,输入密码必须从字符串转换为十六进制二进制。

foreach (var worksheetPart in spreadsheet.WorkbookPart.WorksheetParts)
     {
         //Call the method to convert the Password string "MyPasswordfor sheet" to hexbinary type
         string hexConvertedPassword =  HexPasswordConversion("MyPasswordfor sheet");
//passing the Converted password to sheet protection
          SheetProtection sheetProt = new SheetProtection() { Sheet = true, Objects = true, Scenarios = true, Password = hexConvertedPassword };
          worksheetPart.Worksheet.InsertAfter(sheetProt,worksheetPart.Worksheet.Descendants<SheetData>().LastOrDefault());
worksheetPart.Worksheet.Save();
     }


/* This method will convert the string password to hexabinary value */
 protected string HexPasswordConversion(string password)
        {
            byte[] passwordCharacters = System.Text.Encoding.ASCII.GetBytes(password);
            int hash = 0;
            if (passwordCharacters.Length > 0)
            {
                int charIndex = passwordCharacters.Length;

                while (charIndex-- > 0)
                {
                    hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
                    hash ^= passwordCharacters[charIndex];
                }
                // Main difference from spec, also hash with charcount
                hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
                hash ^= passwordCharacters.Length;
                hash ^= (0x8000 | ('N' << 8) | 'K');
            }

            return Convert.ToString(hash, 16).ToUpperInvariant();
        }

3
你从哪里获取计算散列密码的算法? - Francois Botha

1
你可以尝试这个:
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(mem, true))
{
     foreach (var worksheetPart in spreadsheet.WorkbookPart.WorksheetParts)
     {
          SheetProtection sheetProt = new SheetProtection() { Sheet = true, Objects = true, Scenarios = true, Password = "test" };
          worksheetPart.Worksheet.InsertAfter(sheetProt, worksheetPart.Worksheet.Descendants<SheetData>().LastOrDefault());
     }
}

0

好的,这不是我想做的事情,但最终我放弃了Open XML SDK并使用Office.Interop程序集来保护文档。一开始使用Open XML的原因是因为似乎无法使用流打开Interop工作簿,需要一个实际的文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接