internal IntPtr ToUniStr(bool allocateFromHeap) { IntPtr ptr; EnsureNotDisposed(); // Demand Permission new CryptographicPermission(CryptographicPermissionFlags.Decrypt).Demand(); if (allocateFromHeap) { ptr = Marshal.AllocHGlobal((m_length + 1) * 2); } else { ptr = Marshal.AllocCoTaskMem((m_length + 1) * 2); } try { this.UnProtectMemory(); Win32Native.ZeroMemory(ptr, (uint)((m_length + 1) * 2)); Marshal.Copy(m_buffer, 0, ptr, m_length * 2); return(ptr); } finally { // Assert Permission new CryptographicPermission(CryptographicPermissionFlags.Encrypt).Assert(); ProtectMemory(); } }
/// <summary> /// This will the allocated memory from method <see cref="SecureStringToGlobalAllocUni"/>. /// </summary> /// <remarks> /// This method is located in the <see cref="Marshal"/> class in .NET Framework v2.0 /// </remarks> public static void ZeroFreeGlobalAllocUni(IntPtr s) { // Demand Permission new CryptographicPermission(CryptographicPermissionFlags.Decrypt).Demand(); Win32Native.ZeroMemory(s, (uint)Win32Native.lstrlenW(s) * 2); Marshal.FreeHGlobal(s); }
private void ClearBuffer() { // Clear the byte array Array.Clear(m_buffer, 0, m_buffer.Length); // Zero out the memory buffer Win32Native.ZeroMemory(m_bh.AddrOfPinnedObject(), (uint)m_buffer.Length); // Release the allocated memory if (m_bh.IsAllocated) { m_bh.Free(); } }
/// <summary> /// This method creates and displays a configurable dialog box that accepts credentials information from a user. /// </summary> /// <param name="targetName">Contains the name of the target for the credentials, /// typically a server name. For distributed file system (DFS) connections, /// this string is of the form "servername\sharename". /// This parameter is used to identify Target Information when storing and retrieving credentials. /// </param> /// <param name="caption">String containing the title for the dialog box.</param> /// <param name="message">String containing a brief message to display in the dialog box.</param> /// <param name="owner">Specifies the handle to the parent window of the dialog box. /// If this member is NULL, the desktop will be the parent window of the dialog box. /// </param> /// <returns><see cref="SecureCredential"/> object with the supplied credentials.</returns> /// <permission cref="UIPermission">Demand for <see cref="UIPermissionWindow.SafeTopLevelWindows"/> permission.</permission> public static SecureCredential PromptForSecureCredentials(string targetName, string caption, string message, IntPtr owner) { // Parameter validation if (targetName == null) { throw new ArgumentNullException("targetName"); } if (caption == null) { caption = String.Empty; } if (message == null) { message = String.Empty; } new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); // Uncommment this lines to use custom bitmap // Bitmap credBMP = new Bitmap(@"..\credui.bmp"); // replace IntPtr.Zero by credBMP.GetHbitmap() Win32Native.CREDUI_INFO creditUI = new Win32Native.CREDUI_INFO(owner, caption, message, IntPtr.Zero); int saveCredentials = 0; StringBuilder user = new StringBuilder(Win32Native.MAX_USER_NAME); byte[] pwd = new byte[Win32Native.MAX_PASSWORD]; GCHandle pwdHandle = GCHandle.Alloc(pwd, GCHandleType.Pinned); try { Win32Native.CredUiFlags flags = Win32Native.CredUiFlags.GENERIC_CREDENTIALS | Win32Native.CredUiFlags.SHOW_SAVE_CHECK_BOX | Win32Native.CredUiFlags.ALWAYS_SHOW_UI | Win32Native.CredUiFlags.EXPECT_CONFIRMATION | Win32Native.CredUiFlags.INCORRECT_PASSWORD; //For more info see: //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/creduipromptforcredentials.asp //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp?frame=true Win32Native.CredUIReturnCodes result = Win32Native.CredUIPromptForCredentialsW( ref creditUI, targetName, IntPtr.Zero, 0, user, Win32Native.MAX_USER_NAME, pwdHandle.AddrOfPinnedObject(), pwd.Length, ref saveCredentials, flags); switch (result) { case Win32Native.CredUIReturnCodes.NO_ERROR: StringBuilder usr = new StringBuilder(Win32Native.MAX_USER_NAME); StringBuilder domain = new StringBuilder(Win32Native.MAX_DOMAIN); result = Win32Native.CredUIParseUserNameW(user.ToString(), usr, Win32Native.MAX_USER_NAME, domain, Win32Native.MAX_DOMAIN); if (result == Win32Native.CredUIReturnCodes.NO_ERROR) { if (saveCredentials == 1) { ConfirmCredentials(targetName, true); } unsafe { return(new SecureCredential(usr.ToString(), (char *)pwdHandle.AddrOfPinnedObject().ToPointer(), Win32Native.lstrlenW(pwdHandle.AddrOfPinnedObject()), domain.ToString())); } } else { throw new SecurityException(TranslateReturnCode(result)); } case Win32Native.CredUIReturnCodes.ERROR_CANCELLED: return(null); default: throw new SecurityException(TranslateReturnCode(result)); } } finally { // Clear pwd data. Array.Clear(pwd, 0, pwd.Length); // Zero out the memory buffer Win32Native.ZeroMemory(pwdHandle.AddrOfPinnedObject(), (uint)pwd.Length); // Free the allocated handle if (pwdHandle.IsAllocated) { pwdHandle.Free(); } } }
/// <summary> /// See <see cref="ProtectedData"/>. /// </summary> /// <param name="encryptedData">Data to unprotect.</param> /// <param name="optionalEntropy">Additional material to be added to the symmetric key used for encryption.</param> /// <param name="scope">See <see cref="DataProtectionScope"/>.</param> /// <returns>Plain text data.</returns> /// <exception cref="ArgumentNullException">The specified parameter is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="CryptographicException">Exception when executing unmanaged code.</exception> /// <permission cref="CryptographicPermission">Demand for decryption permission.</permission> public static byte[] Unprotect(byte[] encryptedData, byte[] optionalEntropy, DataProtectionScope scope) { // Verify input if (encryptedData == null || encryptedData.Length == 0) { throw new ArgumentNullException("encryptedData"); } if (!IsValidScope(scope)) { throw new ArgumentException(Resource.ResourceManager[Resource.MessageKey.InvalidDataProtectionScope]); } // Demand Permission new CryptographicPermission(CryptographicPermissionFlags.Decrypt).Demand(); // Assert UnamanagedCode (replaced by the SuppressUnmanagedCodeSecurity attribute of the Win32Native class // Initialize vars. // Check to see if the entropy is null if (optionalEntropy == null) { // Allocate something optionalEntropy = new byte[0]; } Win32Native.CRYPTOAPI_BLOB plainTextBlob = new Win32Native.CRYPTOAPI_BLOB(); GCHandle encryptedDataHandle = GCHandle.Alloc(encryptedData, GCHandleType.Pinned); GCHandle entropyHandle = GCHandle.Alloc(optionalEntropy, GCHandleType.Pinned); try { Win32Native.CRYPTPROTECT_PROMPTSTRUCT prompt = new Win32Native.CRYPTPROTECT_PROMPTSTRUCT(0); Win32Native.CRYPTOAPI_BLOB encryptedDataBlob = new Win32Native.CRYPTOAPI_BLOB(); encryptedDataBlob.cbData = (uint)encryptedData.Length; encryptedDataBlob.pbData = encryptedDataHandle.AddrOfPinnedObject(); Win32Native.CRYPTOAPI_BLOB entropyBlob = new Win32Native.CRYPTOAPI_BLOB(); entropyBlob.cbData = (uint)optionalEntropy.Length; entropyBlob.pbData = entropyHandle.AddrOfPinnedObject(); if (!Win32Native.CryptUnprotectData(ref encryptedDataBlob, null, ref entropyBlob, IntPtr.Zero, ref prompt, (uint)scope, ref plainTextBlob)) { throw new CryptographicException(Resource.ResourceManager[Resource.MessageKey.UnprotectDataException], new Win32Exception(Marshal.GetLastWin32Error())); } if (plainTextBlob.pbData == IntPtr.Zero) { throw new OutOfMemoryException(Resource.ResourceManager[Resource.MessageKey.OutOfMemoryException, "plainTextBlob"]); } byte[] plainText = new byte[plainTextBlob.cbData]; Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainText.Length); return(plainText); } finally { // Free handles if (encryptedDataHandle.IsAllocated) { encryptedDataHandle.Free(); } if (entropyHandle.IsAllocated) { entropyHandle.Free(); } //Free the unmanaged resource ... // Free and erase the plainTextBlob if (plainTextBlob.pbData != IntPtr.Zero) { Win32Native.ZeroMemory(plainTextBlob.pbData, plainTextBlob.cbData); Win32Native.LocalFree(plainTextBlob.pbData); } } }
/// <summary> /// This function performs encryption on the data in a byte array input data. /// If <see cref="DataProtectionScope.CurrentUser"/> is specified, only a user /// with the same logon credentials as the encrypter can decrypt the data. /// <b>Warning</b>If the logon credentials are lost or forgotten, the data is usually unrecoverable. /// If the <see cref="DataProtectionScope.LocalMachine"/> is used, the encryption and decryption must be done on the same computer /// therefore any user on the same computer where the data was encrypted can recover the data. /// </summary> /// <remarks> /// The function creates a session key to perform the encryption. /// The session key is rederived when the data is to be decrypted. /// The function also adds a message authentication code (MAC), which is a keyed integrity check, to the encrypted data to guard against data tampering. /// </remarks> /// <param name="userData">Data to be protected. This array should be erased after use with <see cref="Array.Clear"/>.</param> /// <param name="optionalEntropy">Additional material to be added to the symmetric key used for encryption.</param> /// <param name="scope">See <see cref="DataProtectionScope"/>.</param> /// <returns>Protected data.</returns> /// <exception cref="ArgumentNullException">The specified parameter is a null reference (Nothing in Visual Basic).</exception> /// <exception cref="CryptographicException">Exception when executing unmanaged code.</exception> /// <permission cref="CryptographicPermission">Demand for encryption permission.</permission> public static byte[] Protect(byte[] userData, byte[] optionalEntropy, DataProtectionScope scope) { // Verify input if (userData == null) { throw new ArgumentNullException("userData"); } if (!IsValidScope(scope)) { throw new ArgumentException(Resource.ResourceManager[Resource.MessageKey.InvalidDataProtectionScope]); } // Demand Permission new CryptographicPermission(CryptographicPermissionFlags.Encrypt).Demand(); // Assert UnamanagedCode (replaced by the SuppressUnmanagedCodeSecurity attribute of the Win32Native class // Check to see if the entropy is null if (optionalEntropy == null) { // Allocate something optionalEntropy = new byte[0]; } Win32Native.CRYPTOAPI_BLOB cipherTextBlob = new Win32Native.CRYPTOAPI_BLOB(); // This prevents the garbage collector from moving the object and hence // undermines the efficiency of the garbage collector. We 'll release // the reference on the finally block. GCHandle userDataHandle = GCHandle.Alloc(userData, GCHandleType.Pinned); GCHandle entropyHandle = GCHandle.Alloc(optionalEntropy, GCHandleType.Pinned); try { Win32Native.CRYPTPROTECT_PROMPTSTRUCT prompt = new Win32Native.CRYPTPROTECT_PROMPTSTRUCT(0); Win32Native.CRYPTOAPI_BLOB plainTextBlob = new Win32Native.CRYPTOAPI_BLOB(); plainTextBlob.cbData = (uint)userData.Length; plainTextBlob.pbData = userDataHandle.AddrOfPinnedObject(); Win32Native.CRYPTOAPI_BLOB entropyBlob = new Win32Native.CRYPTOAPI_BLOB(); entropyBlob.cbData = (uint)optionalEntropy.Length; entropyBlob.pbData = entropyHandle.AddrOfPinnedObject(); if (!Win32Native.CryptProtectData(ref plainTextBlob, null, ref entropyBlob, IntPtr.Zero, ref prompt, (uint)scope, ref cipherTextBlob)) { throw new CryptographicException(Resource.ResourceManager[Resource.MessageKey.ProtectDataException], new Win32Exception(Marshal.GetLastWin32Error())); } //Check returned data if (cipherTextBlob.pbData == IntPtr.Zero) { throw new OutOfMemoryException(Resource.ResourceManager[Resource.MessageKey.OutOfMemoryException, "cipherTextBlob"]); } // Move encrypted data to the returned array byte[] cipherText = new byte[cipherTextBlob.cbData]; Marshal.Copy(cipherTextBlob.pbData, cipherText, 0, cipherText.Length); return(cipherText); } finally { // Free the allocated handles if (userDataHandle.IsAllocated) { userDataHandle.Free(); } if (entropyHandle.IsAllocated) { entropyHandle.Free(); } //Free the unmanaged resource ... // Free and erase the cipherTextBlob if (cipherTextBlob.pbData != IntPtr.Zero) { Win32Native.ZeroMemory(cipherTextBlob.pbData, cipherTextBlob.cbData); Win32Native.LocalFree(cipherTextBlob.pbData); } } }