Advertisement
vilgelmbb

DocumentProtection class

Jan 20th, 2015
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.01 KB | None | 0 0
  1. using System;
  2. using System.Security.Cryptography;
  3. using System.Text;
  4. using DocumentFormat.OpenXml;
  5. using DocumentFormat.OpenXml.Packaging;
  6. using DocumentFormat.OpenXml.Wordprocessing;
  7.  
  8. namespace DigDes.Helpers.Common
  9. {
  10.     public static class DocumentProtection
  11.     {
  12.         static int[] InitialCodeArray = { 0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3 };
  13.  
  14.         private static int[,] EncryptionMatrix = new int[15, 7]
  15.         {
  16.  
  17.             /* char 1  */ {0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09},
  18.             /* char 2  */ {0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF},
  19.             /* char 3  */ {0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0},
  20.             /* char 4  */ {0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40},
  21.             /* char 5  */ {0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5},
  22.             /* char 6  */ {0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A},
  23.             /* char 7  */ {0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9},
  24.             /* char 8  */ {0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0},
  25.             /* char 9  */ {0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC},
  26.             /* char 10 */ {0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10},
  27.             /* char 11 */ {0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168},
  28.             /* char 12 */ {0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C},
  29.             /* char 13 */ {0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD},
  30.             /* char 14 */ {0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC},
  31.             /* char 15 */ {0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4}
  32.         };
  33.  
  34.         private static byte[] concatByteArrays(byte[] array1, byte[] array2)
  35.         {
  36.             byte[] result = new byte[array1.Length + array2.Length];
  37.             Buffer.BlockCopy(array2, 0, result, 0, array2.Length);
  38.             Buffer.BlockCopy(array1, 0, result, array2.Length, array1.Length);
  39.             return result;
  40.         }
  41.  
  42.         public static void ApplyDocumentProtection(WordprocessingDocument wdDocument, string strPassword, DocumentProtectionValues documentProtectionValues)
  43.         {
  44.             // Generate the Salt
  45.             byte[] arrSalt = new byte[16];
  46.             RandomNumberGenerator rand = new RNGCryptoServiceProvider();
  47.             rand.GetNonZeroBytes(arrSalt);
  48.  
  49.             //Array to hold Key Values
  50.             byte[] generatedKey = new byte[4];
  51.  
  52.             //Maximum length of the password is 15 chars.
  53.             int intMaxPasswordLength = 15;
  54.  
  55.  
  56.             if (!String.IsNullOrEmpty(strPassword))
  57.             {
  58.                 // Truncate the password to 15 characters
  59.                 strPassword = strPassword.Substring(0, Math.Min(strPassword.Length, intMaxPasswordLength));
  60.  
  61.                 // Construct a new NULL-terminated string consisting of single-byte characters:
  62.                 //  -- > Get the single-byte values by iterating through the Unicode characters of the truncated Password.
  63.                 //   --> For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte.
  64.  
  65.                 byte[] arrByteChars = new byte[strPassword.Length];
  66.  
  67.                 for (int intLoop = 0; intLoop < strPassword.Length; intLoop++)
  68.                 {
  69.                     int intTemp = Convert.ToInt32(strPassword[intLoop]);
  70.                     arrByteChars[intLoop] = Convert.ToByte(intTemp & 0x00FF);
  71.                     if (arrByteChars[intLoop] == 0)
  72.                         arrByteChars[intLoop] = Convert.ToByte((intTemp & 0xFF00) >> 8);
  73.                 }
  74.  
  75.                 // Compute the high-order word of the new key:
  76.  
  77.                 // --> Initialize from the initial code array (see below), depending on the strPassword’s length.
  78.                 int intHighOrderWord = InitialCodeArray[arrByteChars.Length - 1];
  79.  
  80.                 // --> For each character in the strPassword:
  81.                 //      --> For every bit in the character, starting with the least significant and progressing to (but excluding)
  82.                 //          the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from
  83.                 //          the Encryption Matrix
  84.  
  85.                 for (int intLoop = 0; intLoop < arrByteChars.Length; intLoop++)
  86.                 {
  87.                     int tmp = intMaxPasswordLength - arrByteChars.Length + intLoop;
  88.                     for (int intBit = 0; intBit < 7; intBit++)
  89.                     {
  90.                         if ((arrByteChars[intLoop] & (0x0001 << intBit)) != 0)
  91.                         {
  92.                             intHighOrderWord ^= EncryptionMatrix[tmp, intBit];
  93.                         }
  94.                     }
  95.                 }
  96.  
  97.                 // Compute the low-order word of the new key:
  98.  
  99.                 // Initialize with 0
  100.                 int intLowOrderWord = 0;
  101.  
  102.                 // For each character in the strPassword, going backwards
  103.                 for (int intLoopChar = arrByteChars.Length - 1; intLoopChar >= 0; intLoopChar--)
  104.                 {
  105.                     // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character
  106.                     intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[intLoopChar];
  107.                 }
  108.  
  109.                 // Lastly,low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B.
  110.                 intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.Length ^ 0xCE4B;
  111.  
  112.                 // Combine the Low and High Order Word
  113.                 int intCombinedkey = (intHighOrderWord << 16) + intLowOrderWord;
  114.  
  115.                 // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example],
  116.                 // and that value shall be hashed as defined by the attribute values.
  117.  
  118.                 for (int intTemp = 0; intTemp < 4; intTemp++)
  119.                 {
  120.                     generatedKey[intTemp] = Convert.ToByte(((uint)(intCombinedkey & (0x000000FF << (intTemp * 8)))) >> (intTemp * 8));
  121.                 }
  122.             }
  123.  
  124.             // Implementation Notes List:
  125.             // --> In this third stage, the reversed byte order legacy hash from the second stage shall be converted to Unicode hex
  126.             // --> string representation
  127.             StringBuilder sb = new StringBuilder();
  128.             for (int intTemp = 0; intTemp < 4; intTemp++)
  129.             {
  130.                 sb.Append(Convert.ToString(generatedKey[intTemp], 16));
  131.             }
  132.             generatedKey = Encoding.Unicode.GetBytes(sb.ToString().ToUpper());
  133.  
  134.             // Implementation Notes List:
  135.             //Word appends the binary form of the salt attribute and not the base64 string representation when hashing
  136.             // Before calculating the initial hash, you are supposed to prepend (not append) the salt to the key
  137.             byte[] tmpArray1 = generatedKey;
  138.             byte[] tmpArray2 = arrSalt;
  139.             byte[] tempKey = new byte[tmpArray1.Length + tmpArray2.Length];
  140.             Buffer.BlockCopy(tmpArray2, 0, tempKey, 0, tmpArray2.Length);
  141.             Buffer.BlockCopy(tmpArray1, 0, tempKey, tmpArray2.Length, tmpArray1.Length);
  142.             generatedKey = tempKey;
  143.  
  144.  
  145.             // Iterations specifies the number of times the hashing function shall be iteratively run (using each
  146.             // iteration's result as the input for the next iteration).
  147.             int iterations = 50000;
  148.  
  149.             // Implementation Notes List:
  150.             //Word requires that the initial hash of the password with the salt not be considered in the count.
  151.             //    The initial hash of salt + key is not included in the iteration count.
  152.             HashAlgorithm sha1 = new SHA1Managed();
  153.             generatedKey = sha1.ComputeHash(generatedKey);
  154.             byte[] iterator = new byte[4];
  155.             for (int intTmp = 0; intTmp < iterations; intTmp++)
  156.             {
  157.  
  158.                 //When iterating on the hash, you are supposed to append the current iteration number.
  159.                 iterator[0] = Convert.ToByte((intTmp & 0x000000FF) >> 0);
  160.                 iterator[1] = Convert.ToByte((intTmp & 0x0000FF00) >> 8);
  161.                 iterator[2] = Convert.ToByte((intTmp & 0x00FF0000) >> 16);
  162.                 iterator[3] = Convert.ToByte((intTmp & 0xFF000000) >> 24);
  163.  
  164.                 generatedKey = concatByteArrays(iterator, generatedKey);
  165.                 generatedKey = sha1.ComputeHash(generatedKey);
  166.             }
  167.  
  168.             // Apply the element
  169.             DocumentFormat.OpenXml.Wordprocessing.DocumentProtection documentProtection = new DocumentFormat.OpenXml.Wordprocessing.DocumentProtection();
  170.             documentProtection.Edit = documentProtectionValues;
  171.  
  172.             OnOffValue docProtection = new OnOffValue(true);
  173.             documentProtection.Enforcement = docProtection;
  174.  
  175.             documentProtection.CryptographicAlgorithmClass = CryptAlgorithmClassValues.Hash;
  176.             documentProtection.CryptographicProviderType = CryptProviderValues.RsaFull;
  177.             documentProtection.CryptographicAlgorithmType = CryptAlgorithmValues.TypeAny;
  178.             documentProtection.CryptographicAlgorithmSid = 4; // SHA1
  179.             //    The iteration count is unsigned
  180.             UInt32Value uintVal = new UInt32Value();
  181.             uintVal.Value = (uint)iterations;
  182.             documentProtection.CryptographicSpinCount = uintVal;
  183.             documentProtection.Hash = Convert.ToBase64String(generatedKey);
  184.             documentProtection.Salt = Convert.ToBase64String(arrSalt);
  185.             wdDocument.MainDocumentPart.DocumentSettingsPart.Settings.AppendChild(documentProtection);
  186.             wdDocument.MainDocumentPart.DocumentSettingsPart.Settings.Save();
  187.  
  188.         }
  189.     }
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement