private static extern bool CryptUnprotectData(ref DPAPINativeDataBlob cipherText, ref string description, ref DPAPINativeDataBlob entropy, IntPtr reserved, ref DPAPINativeCryptPotectPromptStruct prompt, int flags, ref DPAPINativeDataBlob plainText);
///<summary> /// Creates the structure that holds byte[] data to be encrypted. ///</summary> ///<param name="data">Data to be encrypted.</param> ///<returns>Structure that holds byte[] data to be encrypted.</returns> ///<exception cref="MemberAccessException">Unable to allocate data buffer for BLOB structure</exception> public static DPAPINativeDataBlob Init(byte[] data) { // Use empty array for null parameter. if (data == null) { data = new byte[0]; } var blob = new DPAPINativeDataBlob { DataPointer = Marshal.AllocHGlobal(data.Length), DataLength = data.Length }; // Make sure that memory allocation was successful. // With the null check on the data parameter, I don't think this is needed. //if (blob.pbData == IntPtr.Zero) // throw new MemberAccessException("Unable to allocate data buffer for BLOB structure."); // Copy data from original source to the BLOB structure. Marshal.Copy(data, 0, blob.DataPointer, data.Length); return blob; }
private static byte[] DPAPIDecrypt(byte[] cipherText, byte[] entropy) { // Create BLOBs to hold data. var plainTextBlob = new DPAPINativeDataBlob(); var cipherTextBlob = new DPAPINativeDataBlob(); var entropyBlob = new DPAPINativeDataBlob(); // We only need prompt structure because it is a required parameter. var prompt = DPAPINativeCryptPotectPromptStruct.Default(); byte[] plainTextBytes; try { // Convert ciphertext bytes into a BLOB structure. cipherTextBlob = DPAPINativeDataBlob.Init(cipherText); // Convert entropy bytes into a BLOB structure. entropyBlob = DPAPINativeDataBlob.Init(entropy); // Initialize description string. var description = String.Empty; // Call DPAPI to decrypt data. var success = CryptUnprotectData(ref cipherTextBlob, ref description, ref entropyBlob, IntPtr.Zero, ref prompt, CRYPTPROTECT_UI_FORBIDDEN, ref plainTextBlob); // Check the result. if (!success) { // If operation failed, retrieve last Win32 error. var errCode = Marshal.GetLastWin32Error(); // Win32Exception will contain error message corresponding // to the Windows error code. throw new CryptographicException("CryptUnprotectData failed.", new Win32Exception(errCode)); } // Allocate memory to hold plaintext. plainTextBytes = new byte[plainTextBlob.DataLength]; // Copy ciphertext from the BLOB to a byte array. Marshal.Copy(plainTextBlob.DataPointer, plainTextBytes, 0, plainTextBlob.DataLength); } catch (Exception ex) { throw new CryptographicException("DPAPI was unable to decrypt data.", ex); } finally { // Free all memory allocated for BLOBs. plainTextBlob.Dispose(); cipherTextBlob.Dispose(); entropyBlob.Dispose(); prompt.Dispose(); } // Return the result. return plainTextBytes; }