我正在尝试使用 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==
。
用于获取密码字节的编码应该是UTF16LE
Encoding.Unicode.GetBytes("123");