/// <summary>
        /// Encrypts the data in a specified byte array and returns a byte array that contains the encrypted data.
        /// </summary>
        /// <param name="userData">A byte array that contains data to encrypt.</param>
        /// <param name="optionalEntropy">An optional additional byte array used to increase the complexity of the encryption, or Nothing for no additional complexity.</param>
        /// <returns>A byte array representing the encrypted data.</returns>
        /// <remarks>This method can be used to encrypt data such as passwords, keys, or connection strings.
        /// The optionalEntropy parameter enables you to add data to increase the complexity of the encryption; specify Nothing for no additional complexity.
        /// If provided, this information must also be used when decrypting the data using the <see cref="Unprotect"/> method.</remarks>
        /// <exception cref="ArgumentNullException">The userData parameter is Nothing.</exception>
        /// <exception cref="CryptographicException">The encryption failed.</exception>
        /// <exception cref="OutOfMemoryException">The system ran out of memory while encrypting the data.</exception>
        public static byte[] Protect(byte[] userData, byte[] optionalEntropy)
        {
            if (userData == null)
            {
                throw new ArgumentNullException("userData");
            }

            GCHandle hIn      = System.Runtime.InteropServices.GCHandle.Alloc(userData, GCHandleType.Pinned);
            GCHandle hEntropy = (optionalEntropy == null) ? GCHandle.Alloc(0, GCHandleType.Pinned) :GCHandle.Alloc(optionalEntropy, GCHandleType.Pinned);

            byte[] result = null;
            try
            {
                NativeMethods.DATA_BLOB inBlob = new NativeMethods.DATA_BLOB();
                inBlob.cbData = userData.Length;
                inBlob.pbData = hIn.AddrOfPinnedObject();
                NativeMethods.DATA_BLOB entropyBlob = new NativeMethods.DATA_BLOB();
                if (optionalEntropy != null)
                {
                    entropyBlob.cbData = optionalEntropy.Length;
                    entropyBlob.pbData = hEntropy.AddrOfPinnedObject();
                }

                NativeMethods.DATA_BLOB outBlob = new NativeMethods.DATA_BLOB();
                bool success = NativeMethods.CryptProtectData(ref inBlob, "", ref entropyBlob, IntPtr.Zero, IntPtr.Zero, 0, ref outBlob);

                if (success)
                {
                    result = new byte[outBlob.cbData];
                    Marshal.Copy(outBlob.pbData, result, 0, result.Length);
                    Marshal.FreeHGlobal(outBlob.pbData);
                }
                else
                {
                    if (Marshal.GetLastWin32Error() == 14)
                    {
                        throw new OutOfMemoryException();
                    }
                    else
                    {
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                    }
                }
            }
            finally
            {
                if (hIn.IsAllocated)
                {
                    hIn.Free();
                }

                if (hEntropy.IsAllocated)
                {
                    hEntropy.Free();
                }
            }

            return(result);
        }
Пример #2
0
        private static string DecryptPassword(string ciphertext)
        {
            if (string.IsNullOrEmpty(ciphertext))
            {
                return(null);
            }

            GCHandle gcHandle = new GCHandle();

            NativeMethods.DATA_BLOB plaintextData = new NativeMethods.DATA_BLOB();
            try
            {
                byte[] ciphertextArray = Convert.FromBase64String(ciphertext);
                gcHandle = GCHandle.Alloc(ciphertextArray, GCHandleType.Pinned);

                NativeMethods.DATA_BLOB ciphertextData = new NativeMethods.DATA_BLOB();
                ciphertextData.cbData = ciphertextArray.Length;
                ciphertextData.pbData = gcHandle.AddrOfPinnedObject();

                NativeMethods.DATA_BLOB temp_optionalEntropy = new NativeMethods.DATA_BLOB();
                IntPtr temp_promptStruct = IntPtr.Zero;
                if (!NativeMethods.CryptUnprotectData(ref ciphertextData, null, ref temp_optionalEntropy, IntPtr.Zero, ref temp_promptStruct, 0, ref plaintextData))
                {
                    return(null);
                }

                int    plaintextLength = (int)((double)plaintextData.cbData / 2);                // Char = 2 bytes
                char[] plaintextArray  = new char[plaintextLength - 1 + 1];
                Marshal.Copy(plaintextData.pbData, plaintextArray, 0, plaintextLength);

                return(new string(plaintextArray));
            }
            catch (Exception ex)
            {
                Runtime.MessageCollector.AddExceptionMessage(message: "RemoteDesktopConnectionManager.DecryptPassword() failed.", ex: ex, logOnly: true);
                return(null);
            }
            finally
            {
                if (gcHandle.IsAllocated)
                {
                    gcHandle.Free();
                }
                if (!(plaintextData.pbData == IntPtr.Zero))
                {
                    NativeMethods.LocalFree(plaintextData.pbData);
                }
            }
        }