OpenXML 使用密码保护电子表格工作簿

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

我正在尝试使用 OpenXML SDK 创建受保护的电子表格文档。但是,生成的

WorkbookHashValue
不正确,因此工作簿无法取消保护。

var password = Encoding.UTF8.GetBytes("123");
var salt = new byte[16];
new RNGCryptoServiceProvider().GetNonZeroBytes(salt);
var spinCount = 100000U;

using (var document = SpreadsheetDocument.Create("text.xlsx", SpreadsheetDocumentType.Workbook))
{
    var workbookPart = document.AddWorkbookPart();
    var workbook = new Workbook();
    WorkbookProtection workbookProtection = new WorkbookProtection()
    {
        LockStructure = true,
        WorkbookAlgorithmName = "SHA-512",
        WorkbookHashValue = Convert.ToBase64String(GetPasswordHash(password, salt, spinCount)),
        WorkbookSaltValue = Convert.ToBase64String(salt),
        WorkbookSpinCount = spinCount
    };
    var sheets = new Sheets();
    var sheet = new Sheet
    {
        Name = "Sheet 1",
        SheetId = 1U,
        Id = "rId1"
    };
    sheets.Append(sheet);
    workbook.Append(workbookProtection);
    workbook.Append(sheets);
    workbookPart.Workbook = workbook;

    var worksheetPart = workbookPart.AddNewPart<WorksheetPart>("rId1");
    var worksheet = new Worksheet();
    var sheetData = new SheetData();
    worksheet.Append(sheetData);
    worksheetPart.Worksheet = worksheet;
}
private byte[] GetPasswordHash(byte[] password, byte[] salt, uint spinCount)
{
    using (var sha512 = SHA512.Create())
    {
        var buffer = new byte[salt.Length + password.Length];
        Array.Copy(salt, buffer, salt.Length);
        Array.Copy(password, 0, buffer, salt.Length, password.Length);
        byte[] hash = sha512.ComputeHash(buffer);
        buffer = new byte[hash.Length + 4];
        for (var i = 0U; i < spinCount; i++)
        {
            Array.Copy(hash, buffer, hash.Length);
            Array.Copy(BitConverter.GetBytes(i), 0, buffer, hash.Length, 4);
            hash = sha512.ComputeHash(buffer);
        }
        return hash;
    }
}

密码

123
加盐
VAQd0dyl7U67APquHio1lQ==
的正确哈希值应该是
2ZwXmW83qax0iUfzSkbhwAOVSDHAm6S/v9irWWTzdoFDgzO2Kc82P3Z9BAwbWqFLzN4rKaL0APOMzQ5tA7TBDw==
,但上面的代码生成了
z5ebojaXN/sD4ps9yurRCpSTDp+kSuTz+HN2PyKmGuicNgszAPKxfsE+kTgOEbGhT/VqSbwTd++oyAJxJh0L3A==

c# .net excel openxml
1个回答
1
投票

用于获取密码字节的编码应该是UTF16LE

Encoding.Unicode.GetBytes("123");
© www.soinside.com 2019 - 2024. All rights reserved.