public byte[] Unprotect(byte[] encryptedData) { // Make sure we were given some encrypted data if (encryptedData == null) { throw new ArgumentNullException("encryptedData"); } // See if the derived class has set PrependHashedPurposeToPlaintext to true. // If so, we have to verify that the first bytes of the plain text are the HashedPurpose // Then, return the remaining bytes as the original data. if (PrependHashedPurposeToPlaintext) { // Get the plainText that includes the hash of the purpose byte[] plainTextWithHashedPurpose = ProviderUnprotect(encryptedData); byte[] hashedPurpose = GetHashedPurpose(); //////////////////////////////////////////////////////////////////////////////////////// // In this code block, we don't want any timing differences between success and failure // Don't touch this code block without crypto board review { if (!SignedXml.CryptographicEquals(hashedPurpose, plainTextWithHashedPurpose, hashedPurpose.Length)) { throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_DataProtector_InvalidPurpose")); } } // Now we've verified that the expected hash was at the start of the plain text. The original // plain text specified by the user appears after these bytes. Create a new array and copy // what the caller is expecting into this array byte[] plainText = new byte[plainTextWithHashedPurpose.Length - hashedPurpose.Length]; Array.Copy(plainTextWithHashedPurpose, hashedPurpose.Length, plainText, 0, plainText.Length); return(plainText); } else { return(ProviderUnprotect(encryptedData)); } }