private RC4 getRC4(byte[] key, int keyLength) { if (_rc4 == null) { _rc4 = new RC4(key, keyLength); return(_rc4); } _rc4.SetKey(key); return(_rc4); }
// algorithm 3.7, step 1-2 private string calculateUserPasswordFromOwnerPassword(string ownerPassword) { // Step 1: Computer an encryption key from the supplied password string, // as described in steps 1 to 4 of algorithm 3.3. byte[] encryptionKey = calculateOwnerHash(ownerPassword, "", true); // Step 2: start decryption of O byte[] ownerHash = null; if (_revision == 2) { // Step 2 (R == 2): decrypt the value of the encryption dictionary // O entry, using an RC4 encryption function with the encryption // key computed in step 1. RC4 rc4 = new RC4(encryptionKey, encryptionKey.Length); ownerHash = rc4.CryptBuffer(_ownerHash, 0, _ownerHash.Length); } else { // Step 2 (R == 3): Do the following 19 times: Take the output from the previous // invocation of the RC4 function and pass it as input to a new // invocation of the function; use an encryption key generated by taking // each byte of the encryption key in step 4 and performing an XOR // operation between that byte and the single-byte value of the // iteration counter byte[] indexedKey = new byte[encryptionKey.Length]; ownerHash = (byte[])_ownerHash.Clone(); for (int i = 19; i >= 0; i--) { for (int j = 0; j < indexedKey.Length; j++) { indexedKey[j] = (byte)(encryptionKey[j] ^ (byte)i); } RC4 rc4 = new RC4(indexedKey, indexedKey.Length); ownerHash = rc4.CryptBuffer(ownerHash, 0, ownerHash.Length); } } int index = findIndex(ownerHash); string localUserPassword = System.Text.Encoding.Default.GetString(ownerHash, 0, index); return(localUserPassword); }
public void Encrypt(byte[] inputData, int offset, int length, Stream output, DataType dataType) { switch (getFilter(dataType)) { case CryptFilter.Identity: output.Write(inputData, offset, length); return; case CryptFilter.V2: RC4 rc4 = getRC4(_curObjectKey, _curObjectKey.Length); rc4.Crypt(inputData, offset, length, output); return; case CryptFilter.AESV3: case CryptFilter.AESV2: AES aes = getAES(_curObjectKey); aes.Encrypt(inputData, offset, length, output); return; } }
public void Decrypt(Stream input, int length, Stream output, DataType dataType) { switch (getFilter(dataType)) { case CryptFilter.Identity: for (int i = 0; i < length; ++i) { output.WriteByte((byte)input.ReadByte()); } return; case CryptFilter.V2: RC4 rc4 = getRC4(_curObjectKey, _curObjectKey.Length); rc4.Crypt(input, length, output); return; case CryptFilter.AESV2: case CryptFilter.AESV3: AES aes = getAES(_curObjectKey); aes.Decrypt(input, length, output); return; } }
// Computing the encryption dictionary’s U (user password) private byte[] calculateUserHash(String userPassword) { // Step 1: Create an encryption key based on the user password String, // as described in Algorithm 3.2 byte[] encryptionKey = computeEncryptionKey(userPassword, _length); // Algorithm 3.4 steps, 2 - 3 if (_revision == 2) { // Step 2: Encrypt the 32-byte padding string show in step 1, using // an RC4 encryption function with the encryption key from the // preceding step byte[] paddedUserPassword = (byte[])_paddingString.Clone(); byte[] finalData = null; RC4 rc4 = new RC4(encryptionKey, encryptionKey.Length); finalData = rc4.CryptBuffer(paddedUserPassword, 0, paddedUserPassword.Length); // Step 3: return the result of step 2 as the value of the U entry return(finalData); } // algorithm 3.5 steps, 2 - 6 else { // Step 2: Initialize the MD5 hash function and pass the 32-byte // padding string shown in step 1 of Algorithm 3.2 as input to // this function byte[] tmp = new byte[32]; byte[] paddedUserPassword = (byte[])_paddingString.Clone(); MD5 md5 = MD5.Create(); if (!_isDocIDEmpty) { md5.TransformBlock(paddedUserPassword, 0, paddedUserPassword.Length, tmp, 0); } else { md5.TransformFinalBlock(paddedUserPassword, 0, paddedUserPassword.Length); } // Step 3: Pass the first element of the files identify array to the // hash function and finish the hash. if (!_isDocIDEmpty) { md5.TransformFinalBlock(_docID, 0, _docID.Length); } byte[] encryptData = (byte[])md5.Hash.Clone(); // Step 4: Encrypt the 16 byte result of the hash, using an RC4 // encryption function with the encryption key from step 1 RC4 rc4 = new RC4(encryptionKey, encryptionKey.Length); encryptData = rc4.CryptBuffer(encryptData, 0, encryptData.Length); // Step 5: Do the following 19 times: Take the output from the previous // invocation of the RC4 function and pass it as input to a new // invocation of the function; use an encryption key generated by taking // each byte of the encryption key in step 4 and performing an XOR // operation between that byte and the single-byte value of the // iteration counter byte[] indexedKey = new byte[encryptionKey.Length]; for (int i = 1; i <= 19; i++) { for (int j = 0; j < encryptionKey.Length; j++) { indexedKey[j] = (byte)(encryptionKey[j] ^ (byte)i); } rc4 = new RC4(indexedKey, indexedKey.Length); encryptData = rc4.CryptBuffer(encryptData, 0, encryptData.Length); } // Step 6: Append 16 bytes of arbitrary padding to the output from // the final invocation of the RC4 function and return the 32-byte // result as the value of the U entry. byte[] finalData = new byte[32]; Array.Copy(encryptData, finalData, 16); Array.Copy(_paddingString, 0, finalData, 16, 16); return(finalData); } }
// Computing Owner password value, Algorithm 3.3. private byte[] calculateOwnerHash(string ownerPassword, string userPassword, bool isAuthentication) { // Step 1: padd the owner password, use the userPassword if empty. if ("".Equals(ownerPassword) && !"".Equals(userPassword)) { ownerPassword = userPassword; } byte[] paddedOwnerPassword = padPassword(ownerPassword); // Step 2: Initialize the MD5 hash function and pass in step 2. MD5 md5 = MD5.Create(); paddedOwnerPassword = md5.ComputeHash(paddedOwnerPassword); // Step 3: Do the following 50 times: take the output from the previous // MD5 hash and pass it as input into a new MD5 hash; // only for R = 3 if (_revision >= 3) { for (int i = 0; i < 50; ++i) { paddedOwnerPassword = md5.ComputeHash(paddedOwnerPassword, 0, _length / 8); } } // Step 4: Create an RC4 encryption key using the first n bytes of the // final MD5 hash, where n is always 5 for revision 2 and the value // of the encryption dictionary's Length entry for revision 3. int dataSize = 5; if (_revision >= 3) { dataSize = _length / 8; } byte[] encryptionKey = new byte[dataSize]; Array.Copy(paddedOwnerPassword, encryptionKey, dataSize); // Key is needed by algorithm 3.7, Authenticating owner password if (isAuthentication) { return(encryptionKey); } // Step 5: Pad or truncate the user password string byte[] paddedUserPassword = padPassword(userPassword); // Step 6: Encrypt the result of step 4, using the RC4 encryption // function with the encryption key obtained in step 4 RC4 rc4 = new RC4(encryptionKey, dataSize); byte[] finalData = rc4.CryptBuffer(paddedUserPassword, 0, paddedUserPassword.Length); // Step 7: Do the following 19 times: Take the output from the previous // invocation of the RC4 function and pass it as input to a new // invocation of the function; use an encryption key generated by taking // each byte of the encryption key in step 4 and performing an XOR // operation between that byte and the single-byte value of the // iteration counter if (_revision >= 3) { byte[] indexedKey = new byte[encryptionKey.Length]; for (int i = 1; i <= 19; i++) { for (int j = 0; j < encryptionKey.Length; j++) { indexedKey[j] = (byte)(encryptionKey[j] ^ i); } rc4 = new RC4(indexedKey, indexedKey.Length); finalData = rc4.CryptBuffer(finalData, 0, finalData.Length); } } return(finalData); }