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