简体   繁体   English

带密码的OpenXML Protect Spreadsheet Workbook

[英]OpenXML Protect Spreadsheet Workbook with Password

I am trying to create a protected spreadsheet document with OpenXML SDK. 我正在尝试使用OpenXML SDK创建受保护的电子表格文档。 However, the WorkbookHashValue generated is not correct and thus the workbook cannot be unprotected. 但是,生成的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;
    }
}

The correct hash for password 123 with salt VAQd0dyl7U67APquHio1lQ== should be 2ZwXmW83qax0iUfzSkbhwAOVSDHAm6S/v9irWWTzdoFDgzO2Kc82P3Z9BAwbWqFLzN4rKaL0APOMzQ5tA7TBDw== , but the above code generated z5ebojaXN/sD4ps9yurRCpSTDp+kSuTz+HN2PyKmGuicNgszAPKxfsE+kTgOEbGhT/VqSbwTd++oyAJxJh0L3A== . 正确的散列密码123与盐VAQd0dyl7U67APquHio1lQ==2ZwXmW83qax0iUfzSkbhwAOVSDHAm6S/v9irWWTzdoFDgzO2Kc82P3Z9BAwbWqFLzN4rKaL0APOMzQ5tA7TBDw== ,但所产生的上述代码z5ebojaXN/sD4ps9yurRCpSTDp+kSuTz+HN2PyKmGuicNgszAPKxfsE+kTgOEbGhT/VqSbwTd++oyAJxJh0L3A==

I tried comparing the source code of Apache POI and didn't found any mistakes 我尝试比较Apache POI的源代码,但没有发现任何错误

public static byte[] hashPassword(String password, HashAlgorithm hashAlgorithm, byte[] salt, int spinCount, boolean iteratorFirst) {
    // If no password was given, use the default
    if (password == null) {
        password = Decryptor.DEFAULT_PASSWORD;
    }

    MessageDigest hashAlg = getMessageDigest(hashAlgorithm);

    hashAlg.update(salt);
    byte[] hash = hashAlg.digest(StringUtil.getToUnicodeLE(password));
    byte[] iterator = new byte[LittleEndianConsts.INT_SIZE];

    byte[] first = (iteratorFirst ? iterator : hash);
    byte[] second = (iteratorFirst ? hash : iterator);

    try {
        for (int i = 0; i < spinCount; i++) {
            LittleEndian.putInt(iterator, 0, i);
            hashAlg.reset();
            hashAlg.update(first);
            hashAlg.update(second);
            hashAlg.digest(hash, 0, hash.length); // don't create hash buffer everytime new
        }
    } catch (DigestException e) {
        throw new EncryptedDocumentException("error in password hashing");
    }

    return hash;
}

( iteratorFirst is false for workbook protection) iteratorFirst对于工作簿保护为false)

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

Encoding.Unicode.GetBytes("123");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM