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;
        }