Источник:
http://axforum.info/forums/blog.php?b=8172
==============
<div>Защита книги и/или листа Excel паролем оказалась занимательной задачей.
Статья на MSDN говорит, что для защиты книги требуется указать целых четыре параметра - workbookAlgorithmName, workbookHashValue, workbookSaltValue, workbookSpinCount. Excel при установке защиты через интерфейс использует алгоритм SHA-512 и 100000 раундов, будем использовать аналогичные параметры.
Для установки защиты книги на класс Oxml_RU достаточно добавить два метода:
X++:
public void protect(
str _password =
"", boolean _structure =
false, boolean _windows =
false){ DocumentFormat.OpenXml.Spreadsheet.WorkbookProtection workbookProtection;
str hashValue, saltValue;
int spinCount; workbookProtection = workbook.get_WorkbookProtection();
if (!workbookProtection) { workbookProtection =
new DocumentFormat.OpenXml.Spreadsheet.WorkbookProtection(); workbook.set_WorkbookProtection(workbookProtection); } [hashValue, saltValue, spinCount] = Oxml_RU::calcHash(_password, saltValue, spinCount); workbookProtection.set_WorkbookAlgorithmName(OXML_RU::setStringValue(
"SHA-512")); workbookProtection.set_WorkbookHashValue(DocumentFormat.OpenXml.Base64BinaryValue::FromString(hashValue)); workbookProtection.set_WorkbookSaltValue(DocumentFormat.OpenXml.Base64BinaryValue::FromString(saltValue)); workbookProtection.set_WorkbookSpinCount(DocumentFormat.OpenXml.UInt32Value::FromUInt32(System.Convert::ToUInt32(spinCount))); workbookProtection.set_LockStructure(OXML_RU::setBooleanValue(_structure)); workbookProtection.set_LockWindows(OXML_RU::setBooleanValue(_windows));}
<div class="xpp">X++:
private static server container calcHash(
container _params){ System.Text.Encoding encoding = System.Text.Encoding::GetEncoding(
"UTF-16LE"); System.Security.Cryptography.SHA512Managed sha512 =
new System.Security.Cryptography.SHA512Managed(); System.Byte[] buffer, hash, salt; System.UInt32 uint32;
str password, hashValue, saltValue;
int i, spinCount, hashLength, bufferLength, saltLength;
str createSalt() { System.DateTime randomValue = System.DateTime::get_Now(); buffer = encoding.GetBytes(randomValue.ToString()); hash = sha512.ComputeHash(buffer); buffer =
new System.Byte[16](); System.Array::Copy(hash, 0, buffer, 0, buffer.get_Length()); saltValue = System.Convert::ToBase64String(buffer);
return saltValue; } [password, saltValue, spinCount] = _params; saltValue = saltValue ? saltValue : createSalt(); spinCount = spinCount > 0 ? spinCount : 100000; salt = System.Convert::FromBase64String(saltValue); saltLength = salt.get_Length(); buffer = encoding.GetBytes(password); bufferLength = buffer.get_Length(); hash =
new System.Byte[bufferLength + saltLength](); System.Array::Copy(salt, 0, hash, 0, salt.get_Length()); System.Array::Copy(buffer, 0, hash, salt.get_Length(), buffer.get_Length()); hashLength = hash.get_Length(); buffer =
new System.Byte[hashLength](); bufferLength = buffer.get_Length(); System.Array::Copy(hash, 0, buffer, 0, buffer.get_Length()); sha512.Initialize(); hash =
new System.Byte[0]();
for (i = 0; i