private void SetProtectionAttribute(DocumentProtectionValues value) { var mainDocumentPart = _wordDocument.MainDocumentPart; var settingsPart = mainDocumentPart.DocumentSettingsPart ?? CreateDocumentSettingsPart(mainDocumentPart); var protectionTag = settingsPart.Settings.GetFirstChild <DocumentProtection>() ?? settingsPart.Settings.AppendChild(new DocumentProtection()); protectionTag.Edit = value; }
private void SetProtectionAttribute(DocumentProtectionValues value) { var mainDocumentPart = _wordDocument.MainDocumentPart; var settingsPart = mainDocumentPart.DocumentSettingsPart ?? CreateDocumentSettingsPart(mainDocumentPart); var protectionTag = settingsPart.Settings.GetFirstChild<DocumentProtection>() ?? settingsPart.Settings.AppendChild(new DocumentProtection()); protectionTag.Edit = value; }
public string SetLock(string szFilePath, DocumentProtectionValues objLockType, string strPwd = "") { string strResult = string.Empty; try { using (WordprocessingDocument _objDoc = WordprocessingDocument.Open(szFilePath, true)) { DocumentProtection documentProtection = new DocumentProtection(); documentProtection.Edit = objLockType; // Generate the Salt byte[] arrSalt = new byte[16]; RandomNumberGenerator rand = new RNGCryptoServiceProvider(); rand.GetNonZeroBytes(arrSalt); //Array to hold Key Values byte[] generatedKey = new byte[4]; //Maximum length of the password is 15 chars. int intMaxPasswordLength = 15; if (!string.IsNullOrEmpty(strPwd)) { // Truncate the password to 15 characters strPwd = strPwd.Substring(0, Math.Min(strPwd.Length, intMaxPasswordLength)); // Construct a new NULL-terminated string consisting of single-byte characters: // -- > Get the single-byte values by iterating through the Unicode characters of the truncated Password. // --> For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte. byte[] arrByteChars = new byte[strPwd.Length]; for (int intLoop = 0; intLoop < strPwd.Length; intLoop++) { int intTemp = Convert.ToInt32(strPwd[intLoop]); arrByteChars[intLoop] = Convert.ToByte(intTemp & 0x00FF); if (arrByteChars[intLoop] == 0) { arrByteChars[intLoop] = Convert.ToByte((intTemp & 0xFF00) >> 8); } } // Compute the high-order word of the new key: // --> Initialize from the initial code array (see below), depending on the strPassword’s length. int intHighOrderWord = InitialCodeArray[arrByteChars.Length - 1]; // --> For each character in the strPassword: // --> For every bit in the character, starting with the least significant and progressing to (but excluding) // the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from // the Encryption Matrix for (int intLoop = 0; intLoop < arrByteChars.Length; intLoop++) { int tmp = intMaxPasswordLength - arrByteChars.Length + intLoop; for (int intBit = 0; intBit < 7; intBit++) { if ((arrByteChars[intLoop] & (0x0001 << intBit)) != 0) { intHighOrderWord ^= EncryptionMatrix[tmp, intBit]; } } } // Compute the low-order word of the new key: // Initialize with 0 int intLowOrderWord = 0; // For each character in the strPassword, going backwards for (int intLoopChar = arrByteChars.Length - 1; intLoopChar >= 0; intLoopChar--) { // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[intLoopChar]; } // Lastly,low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B. intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.Length ^ 0xCE4B; // Combine the Low and High Order Word int intCombinedkey = (intHighOrderWord << 16) + intLowOrderWord; // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example], // and that value shall be hashed as defined by the attribute values. for (int intTemp = 0; intTemp < 4; intTemp++) { generatedKey[intTemp] = Convert.ToByte(((uint)(intCombinedkey & (0x000000FF << (intTemp * 8)))) >> (intTemp * 8)); } } // Implementation Notes List: // --> In this third stage, the reversed byte order legacy hash from the second stage shall be converted to Unicode hex // --> string representation StringBuilder sb = new StringBuilder(); for (int intTemp = 0; intTemp < 4; intTemp++) { sb.Append(Convert.ToString(generatedKey[intTemp], 16)); } generatedKey = Encoding.Unicode.GetBytes(sb.ToString().ToUpper()); // Implementation Notes List: //Word appends the binary form of the salt attribute and not the base64 string representation when hashing // Before calculating the initial hash, you are supposed to prepend (not append) the salt to the key byte[] tmpArray1 = generatedKey; byte[] tmpArray2 = arrSalt; byte[] tempKey = new byte[tmpArray1.Length + tmpArray2.Length]; Buffer.BlockCopy(tmpArray2, 0, tempKey, 0, tmpArray2.Length); Buffer.BlockCopy(tmpArray1, 0, tempKey, tmpArray2.Length, tmpArray1.Length); generatedKey = tempKey; // Iterations specifies the number of times the hashing function shall be iteratively run (using each // iteration's result as the input for the next iteration). int iterations = 50000; // Implementation Notes List: //Word requires that the initial hash of the password with the salt not be considered in the count. // The initial hash of salt + key is not included in the iteration count. HashAlgorithm sha1 = new SHA1Managed(); generatedKey = sha1.ComputeHash(generatedKey); byte[] iterator = new byte[4]; for (int intTmp = 0; intTmp < iterations; intTmp++) { //When iterating on the hash, you are supposed to append the current iteration number. iterator[0] = Convert.ToByte((intTmp & 0x000000FF) >> 0); iterator[1] = Convert.ToByte((intTmp & 0x0000FF00) >> 8); iterator[2] = Convert.ToByte((intTmp & 0x00FF0000) >> 16); iterator[3] = Convert.ToByte((intTmp & 0xFF000000) >> 24); generatedKey = concatByteArrays(iterator, generatedKey); generatedKey = sha1.ComputeHash(generatedKey); } DocumentFormat.OpenXml.OnOffValue docProtection = new DocumentFormat.OpenXml.OnOffValue(true); documentProtection.Enforcement = docProtection; documentProtection.CryptographicAlgorithmClass = CryptAlgorithmClassValues.Hash; documentProtection.CryptographicProviderType = CryptProviderValues.RsaFull; documentProtection.CryptographicAlgorithmType = CryptAlgorithmValues.TypeAny; documentProtection.CryptographicAlgorithmSid = 4; // SHA1 // The iteration count is unsigned UInt32 uintVal = new UInt32(); uintVal = (uint)iterations; documentProtection.CryptographicSpinCount = uintVal; documentProtection.Hash = Convert.ToBase64String(generatedKey); documentProtection.Salt = Convert.ToBase64String(arrSalt); _objDoc.MainDocumentPart.DocumentSettingsPart.Settings.AppendChild(documentProtection); _objDoc.MainDocumentPart.DocumentSettingsPart.Settings.Save(); _objDoc.Close(); } } catch (Exception ex) { strResult = ex.Message; } return(strResult); }