Esempio n. 1
0
        /// <summary>
        /// Enumerate the specified stored credentials in the Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application or URL for which the credential is used</param>
        /// <returns>Return a <see cref="List{ICredential}"/> if success, null if target not found, throw if failed to read stored credentials</returns>
        public static List <ICredential> EnumerateICredentials(string target = null)
        {
            IntPtr pCredentials = IntPtr.Zero;
            uint   count        = 0;

            var success = NativeCode.CredEnumerate(target, 0, out count, out pCredentials);

            if (!success)
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == (int)NativeCode.CredentialUIReturnCodes.NotFound)
                {
                    return(null);
                }

                throw new CredentialAPIException($"Unable to Enumerate Credential store", "CredEnumerate", lastError);
            }

            List <NetworkCredential> networkCredentials = new List <NetworkCredential>();

            Credential[] credentials;

            try
            {
                using var criticalSection = new CriticalCredentialHandle(pCredentials);
                credentials = criticalSection.EnumerateCredentials(count);
            }
            catch (Exception)
            {
                return(null);
            }

            return(credentials.Select(c => c as ICredential).ToList());
        }
Esempio n. 2
0
        /// <summary>
        /// Extract the stored credential from Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application/Url where the credential is used for</param>
        /// <param name="type">Credential type</param>
        /// <returns>return the ICredential if success, null if target not found, throw if failed to read stored credentials</returns>
        public static ICredential GetICredential(string target, CredentialType type = CredentialType.Generic)
        {
            IntPtr nCredPtr;

            // Make the API call using the P/Invoke signature
            bool isSuccess = NativeCode.CredRead(target, (UInt32)type, 0, out nCredPtr);

            if (!isSuccess)
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == (int)NativeCode.CredentialUIReturnCodes.NotFound)
                {
                    return(null);
                }
                throw new CredentialAPIException($"Unable to Read Credential", "CredRead", lastError);
            }

            try
            {
                using var critCred = new CriticalCredentialHandle(nCredPtr);
                Credential cred = critCred.GetCredential();
                return(cred);
            }
            catch (Exception)
            {
                return(null);
            }
        }
        public NetworkCredential ToNetworkCredential()
        {
            if (!string.IsNullOrEmpty(UserName))
            {
                var userBuilder   = new StringBuilder(UserName.Length + 2);
                var domainBuilder = new StringBuilder(UserName.Length + 2);

                var returnCode = NativeCode.CredUIParseUserName(UserName, userBuilder, userBuilder.Capacity, domainBuilder, domainBuilder.Capacity);
                var lastError  = Marshal.GetLastWin32Error();

                //assuming invalid account name to be not meeting condition for CredUIParseUserName
                //"The name must be in UPN or down-level format, or a certificate"
                if (returnCode == NativeCode.CredentialUIReturnCodes.InvalidAccountName)
                {
                    userBuilder.Append(UserName);
                }
                else if (returnCode != 0)
                {
                    throw new CredentialAPIException($"Unable to Parse UserName", "CredUIParseUserName", lastError);
                }

                return(new NetworkCredential(userBuilder.ToString(), this.CredentialBlob, domainBuilder.ToString()));
            }
            else
            {
                return(new NetworkCredential(UserName, this.CredentialBlob));
            }
        }
Esempio n. 4
0
        private static void GetCredentialsFromOutputBuffer(ref string user, ref string password, ref string domain, IntPtr outCredBuffer, uint outCredSize)
        {
            int maxUserName = 100;
            int maxDomain   = 100;
            int maxPassword = 100;
            var usernameBuf = new StringBuilder(maxUserName);
            var passwordBuf = new StringBuilder(maxDomain);
            var domainBuf   = new StringBuilder(maxPassword);

            if (NativeCode.CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf, ref maxUserName,
                                                          domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
            {
                user     = usernameBuf.ToString();
                password = passwordBuf.ToString();
                domain   = domainBuf.ToString();
                if (string.IsNullOrWhiteSpace(domain))
                {
                    Debug.WriteLine("Domain null");
                    if (!ParseUserName(usernameBuf.ToString(), usernameBuf.Capacity, domainBuf.Capacity, out user, out domain))
                    {
                        user = usernameBuf.ToString();
                    }
                    password = passwordBuf.ToString();
                }
            }

            //mimic SecureZeroMem function to make sure buffer is zeroed out. SecureZeroMem is not an exported function, neither is RtlSecureZeroMemory
            var zeroBytes = new byte[outCredSize];

            Marshal.Copy(zeroBytes, 0, outCredBuffer, (int)outCredSize);

            //clear the memory allocated by CredUIPromptForWindowsCredentials
            NativeCode.CoTaskMemFree(outCredBuffer);
        }
        /// <summary>
        /// Extract the stored credential from Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application/Url where the credential is used for</param>
        /// <param name="type">Credential type</param>
        /// <returns>return the credentials if success, null if target not found, throw if failed to read stored credentials</returns>
        public static NetworkCredential GetCredentials(string target, CredentialType type = CredentialType.Generic)
        {
            IntPtr nCredPtr;
            var    username = String.Empty;
            var    passwd   = String.Empty;
            var    domain   = String.Empty;

            // Make the API call using the P/Invoke signature
            bool isSuccess = NativeCode.CredRead(target, (NativeCode.CredentialType)type, 0, out nCredPtr);

            if (!isSuccess)
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == (int)NativeCode.CredentialUIReturnCodes.NotFound)
                {
                    return(null);
                }
                throw new Win32Exception(lastError,
                                         String.Format("'CredRead' call throw an error (Error code: {0})", lastError));
            }

            try
            {
                using (var critCred = new CriticalCredentialHandle(nCredPtr))
                {
                    Credential cred = critCred.GetCredential();

                    return(cred.ToNetworkCredential());
                }
            }
            catch (Exception)
            {
                return(null);
            }
        }
        /// <summary>
        /// Extract the stored credential from Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application/Url where the credential is used for</param>
        /// <param name="type">Credential type</param>
        /// <returns>return the credentials if success, null if target not found, throw if failed to read stored credentials</returns>
        public static NetworkCredential GetCredentials(string target, CredentialType type = CredentialType.Generic)
        {
            IntPtr nCredPtr;
            var    username = String.Empty;
            var    passwd   = String.Empty;
            var    domain   = String.Empty;

            // Make the API call using the P/Invoke signature
            bool isSuccess = NativeCode.CredRead(target, (NativeCode.CredentialType)type, 0, out nCredPtr);

            if (!isSuccess)
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == (int)NativeCode.CredentialUIReturnCodes.NotFound)
                {
                    return(null);
                }
                throw new Win32Exception(lastError,
                                         String.Format("'CredRead' call throw an error (Error code: {0})", lastError));
            }

            try
            {
                using (var critCred = new CriticalCredentialHandle(nCredPtr))
                {
                    Credential cred = critCred.GetCredential();
                    passwd = cred.CredentialBlob;
                    if (!String.IsNullOrEmpty(cred.UserName))
                    {
                        var           user          = cred.UserName;
                        StringBuilder userBuilder   = new StringBuilder(cred.UserName.Length + 2);
                        StringBuilder domainBuilder = new StringBuilder(cred.UserName.Length + 2);

                        var returnCode = NativeCode.CredUIParseUserName(user, userBuilder, userBuilder.Capacity, domainBuilder, domainBuilder.Capacity);
                        var lastError  = Marshal.GetLastWin32Error();

                        //assuming invalid account name to be not meeting condition for CredUIParseUserName
                        //"The name must be in UPN or down-level format, or a certificate"
                        if (returnCode == NativeCode.CredentialUIReturnCodes.InvalidAccountName)
                        {
                            userBuilder.Append(user);
                        }
                        else if (returnCode != 0)
                        {
                            throw new Win32Exception(lastError, String.Format("CredUIParseUserName throw an error (Error code: {0})", lastError));
                        }

                        username = userBuilder.ToString();
                        domain   = domainBuilder.ToString();
                    }
                    return(new NetworkCredential(username, passwd, domain));
                }
            }
            catch (Exception)
            {
                return(null);
            }
        }
        /// <summary>
        /// Extract the stored credential from Windows Credential store
        /// </summary>
        /// <param name="Target">Name of the application/Url where the credential is used for</param>
        /// <returns>null if target not found, else stored credentials</returns>
        public static NetworkCredential GetCredentials(string Target, CredentialType type = CredentialType.Generic)
        {
            IntPtr nCredPtr;
            var    username = String.Empty;
            var    passwd   = String.Empty;
            var    domain   = String.Empty;

            // Make the API call using the P/Invoke signature

            bool ret       = NativeCode.CredRead(Target, (NativeCode.CredentialType)type, 0, out nCredPtr);
            int  lastError = Marshal.GetLastWin32Error();

            if (!ret)
            {
                throw new Win32Exception(lastError, "CredDelete throw an error");
            }
            // If the API was successful then...
            if (ret)
            {
                try
                {
                    using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr))
                    {
                        Credential cred = critCred.GetCredential();
                        passwd = cred.CredentialBlob;
                        if (!String.IsNullOrEmpty(cred.UserName))
                        {
                            var           user          = cred.UserName;
                            StringBuilder userBuilder   = new StringBuilder(cred.UserName.Length + 2);
                            StringBuilder domainBuilder = new StringBuilder(cred.UserName.Length + 2);

                            var ret1 = NativeCode.CredUIParseUserName(user, userBuilder, userBuilder.Capacity, domainBuilder, domainBuilder.Capacity);
                            lastError = Marshal.GetLastWin32Error();

                            //assuming invalid account name to be not meeting condition for CredUIParseUserName
                            //"The name must be in UPN or down-level format, or a certificate"
                            if (ret1 == NativeCode.CredentialUIReturnCodes.InvalidAccountName)
                            {
                                userBuilder.Append(user);
                            }
                            else if ((uint)ret1 > 0)
                            {
                                throw new Win32Exception(lastError, "CredUIParseUserName throw an error");
                            }

                            username = userBuilder.ToString();
                            domain   = domainBuilder.ToString();
                        }
                        return(new NetworkCredential(username, passwd, domain));
                    }
                }
                catch (Exception e)
                {
                    return(null);
                }
            }
            return(null);
        }
        /// <summary>
        /// Remove stored credentials from windows credential store
        /// </summary>
        /// <param name="Target">Name of the application/Url where the credential is used for</param>
        /// <returns>True: Success, False: Failure</returns>
        public static bool RemoveCredentials(string Target)
        {
            // Make the API call using the P/Invoke signature
            var ret       = NativeCode.CredDelete(Target, NativeCode.CredentialType.Generic, 0);
            int lastError = Marshal.GetLastWin32Error();

            if (!ret)
            {
                throw new Win32Exception(lastError, "CredDelete throw an error");
            }
            return(ret);
        }
        public bool RemoveCredential()
        {
            // Make the API call using the P/Invoke signature
            var isSuccess = NativeCode.CredDelete(TargetName, (uint)Type, 0);

            if (isSuccess)
            {
                return(true);
            }

            int lastError = Marshal.GetLastWin32Error();

            throw new CredentialAPIException($"Unable to Delete Credential", "CredDelete", lastError);
        }
        /// <summary>
        /// Remove stored credentials from windows credential store
        /// </summary>
        /// <param name="target">Name of the application/Url where the credential is used for</param>
        /// <returns>True: Success, throw if failed</returns>
        public static bool RemoveCredentials(string target)
        {
            // Make the API call using the P/Invoke signature
            var isSuccess = NativeCode.CredDelete(target, NativeCode.CredentialType.Generic, 0);

            if (isSuccess)
            {
                return(true);
            }

            int lastError = Marshal.GetLastWin32Error();

            throw new Win32Exception(lastError, String.Format("'CredDelete' call throw an error (Error code: {0})", lastError));
        }
        /// <summary>
        /// Remove stored credentials from windows credential store
        /// </summary>
        /// <param name="target">Name of the application/Url where the credential is used for</param>
        /// <returns>True: Success, throw if failed</returns>
        public static bool RemoveCredentials(string target, CredentialType type = CredentialType.Generic)
        {
            // Make the API call using the P/Invoke signature
            var isSuccess = NativeCode.CredDelete(target, (UInt32)type, 0);

            if (isSuccess)
            {
                return(true);
            }

            int lastError = Marshal.GetLastWin32Error();

            throw new CredentialAPIException($"Unable to Delete Credential", "CredDelete", lastError);
        }
        private static bool PromptForCredentials(string target, NativeCode.CredentialUIInfo credUI, ref bool save, ref string user, out string password, out string domain)
        {
            password = string.Empty;
            domain   = string.Empty;

            // Setup the flags and variables
            credUI.cbSize = Marshal.SizeOf(credUI);
            int  errorcode   = 0;
            uint authPackage = 0;

            var  outCredBuffer = new IntPtr();
            uint outCredSize;
            var  flags = NativeCode.PromptForWindowsCredentialsFlags.GenericCredentials |
                         NativeCode.PromptForWindowsCredentialsFlags.EnumerateCurrentUser;

            flags = save ? flags | NativeCode.PromptForWindowsCredentialsFlags.ShowCheckbox : flags;

            // Prefill username
            IntPtr inCredBuffer;
            int    inCredSize;

            GetInputBuffer(user, out inCredBuffer, out inCredSize);

            // Setup the flags and variables
            int result = NativeCode.CredUIPromptForWindowsCredentials(ref credUI,
                                                                      errorcode,
                                                                      ref authPackage,
                                                                      inCredBuffer,
                                                                      inCredSize,
                                                                      out outCredBuffer,
                                                                      out outCredSize,
                                                                      ref save,
                                                                      flags);

            if (inCredBuffer != IntPtr.Zero)
            {
                NativeCode.CoTaskMemFree(inCredBuffer);
            }

            if (result == 0)
            {
                GetCredentialsFromOutputBuffer(ref user, ref password, ref domain, outCredBuffer, outCredSize);
                return(true);
            }

            user   = null;
            domain = null;
            return(false);
        }
Esempio n. 13
0
        // Perform any specific actions to release the handle in the ReleaseHandle method.
        // Often, you need to use Pinvoke to make a call into the Win32 API to release the
        // handle. In this case, however, we can use the Marshal class to release the unmanaged memory.

        override protected bool ReleaseHandle()
        {
            // If the handle was set, free it. Return success.
            if (!IsInvalid)
            {
                // NOTE: We should also ZERO out the memory allocated to the handle, before free'ing it
                // so there are no traces of the sensitive data left in memory.
                NativeCode.CredFree(handle);
                // Mark the handle as invalid for future users.
                SetHandleAsInvalid();
                return(true);
            }
            // Return false.
            return(false);
        }
Esempio n. 14
0
        internal static bool ParseUserName(string usernameBuf, int maxUserName, int maxDomain, out string user, out string domain)
        {
            var userBuilder   = new StringBuilder(maxUserName);
            var domainBuilder = new StringBuilder(maxDomain);

            user   = String.Empty;
            domain = String.Empty;

            var returnCode = NativeCode.CredUIParseUserName(usernameBuf, userBuilder, maxUserName, domainBuilder, maxDomain);

            Debug.WriteLine(returnCode);
            switch (returnCode)
            {
            case NativeCode.CredentialUIReturnCodes.Success:     // The username is valid.
                user   = userBuilder.ToString();
                domain = domainBuilder.ToString();
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// Accepts credentials in a console window
        /// </summary>
        /// <param name="Target">A descriptive text for where teh credentials being asked are used for</param>
        /// <returns>NetworkCredential object containing the user name, </returns>
        public static NetworkCredential PromptForCredentialsConsole(string target)
        {
            var user     = String.Empty;
            var password = String.Empty;
            var domain   = String.Empty;

            // Setup the flags and variables
            StringBuilder userPassword = new StringBuilder(), userID = new StringBuilder();
            bool          save = true;

            NativeCode.CredentialUIFlags flags = NativeCode.CredentialUIFlags.CompleteUsername | NativeCode.CredentialUIFlags.ExcludeCertificates | NativeCode.CredentialUIFlags.GenericCredentials;

            // Prompt the user
            NativeCode.CredentialUIReturnCodes returnCode = NativeCode.CredUICmdLinePromptForCredentials(target, IntPtr.Zero, 0, userID, 100, userPassword, 100, ref save, flags);

            password = userPassword.ToString();

            StringBuilder userBuilder   = new StringBuilder();
            StringBuilder domainBuilder = new StringBuilder();

            returnCode = NativeCode.CredUIParseUserName(userID.ToString(), userBuilder, int.MaxValue, domainBuilder, int.MaxValue);
            switch (returnCode)
            {
            case NativeCode.CredentialUIReturnCodes.Success:     // The username is valid.
                user   = userBuilder.ToString();
                domain = domainBuilder.ToString();
                break;

            case NativeCode.CredentialUIReturnCodes.InvalidAccountName:     // The username is not valid.
                user   = userID.ToString();
                domain = null;
                break;

            case NativeCode.CredentialUIReturnCodes.InsufficientBuffer:     // One of the buffers is too small.
                throw new OutOfMemoryException();

            case NativeCode.CredentialUIReturnCodes.InvalidParameter:     // ulUserMaxChars or ulDomainMaxChars is zero OR userName, user, or domain is NULL.
                throw new ArgumentNullException("userName");
            }
            return(new NetworkCredential(user, password, domain));
        }
        /// <summary>
        /// Saves the given Network Credential into Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application/Url where the credential is used for</param>
        /// <param name="credential">Credential to store</param>
        /// <returns>True:Success, throw if failed</returns>
        public static bool SaveCredentials(string target, NetworkCredential credential)
        {
            // Go ahead with what we have are stuff it into the CredMan structures.
            var cred = new Credential(credential)
            {
                TargetName = target, Persist = NativeCode.Persistance.Entrprise
            };

            NativeCode.NativeCredential ncred = cred.GetNativeCredential();

            // Write the info into the CredMan storage.
            if (NativeCode.CredWrite(ref ncred, 0))
            {
                return(true);
            }

            int    lastError = Marshal.GetLastWin32Error();
            string message   = String.Format("'CredWrite' call throw an error (Error code: {0})", lastError);

            throw new Win32Exception(lastError, message);
        }
        /// <summary>
        /// Saves the given Network Credential into Windows Credential store
        /// </summary>
        /// <param name="Target">Name of the application/Url where the credential is used for</param>
        /// <param name="credential">Credential to store</param>
        /// <returns>True:Success, False:Failure</returns>
        public static bool SaveCredentials(string Target, NetworkCredential credential)
        {
            // Go ahead with what we have are stuff it into the CredMan structures.
            Credential cred = new Credential(credential);

            cred.TargetName = Target;
            cred.Persist    = NativeCode.Persistance.Entrprise;
            NativeCode.NativeCredential ncred = cred.GetNativeCredential();
            // Write the info into the CredMan storage.
            bool written   = NativeCode.CredWrite(ref ncred, 0);
            int  lastError = Marshal.GetLastWin32Error();

            if (written)
            {
                return(true);
            }
            else
            {
                string message = string.Format("CredWrite failed with the error code {0}.", lastError);
                throw new Exception(message);
            }
        }
Esempio n. 18
0
        private static void GetInputBuffer(string user, out IntPtr inCredBuffer, out int inCredSize)
        {
            if (!string.IsNullOrEmpty(user))
            {
                var usernameBuf = new StringBuilder(user);
                var passwordBuf = new StringBuilder();

                inCredSize   = 1024;
                inCredBuffer = Marshal.AllocCoTaskMem(inCredSize);
                if (NativeCode.CredPackAuthenticationBuffer(0x00, usernameBuf, passwordBuf, inCredBuffer, ref inCredSize))
                {
                    return;
                }

                if (inCredBuffer != IntPtr.Zero)
                {
                    NativeCode.CoTaskMemFree(inCredBuffer);
                }
            }

            inCredBuffer = IntPtr.Zero;
            inCredSize   = 0;
        }
Esempio n. 19
0
        internal static NetworkCredential ToNetworkCredential(this Credential cred)
        {
            if (cred == null)
            {
                return(null);
            }

            string username = string.Empty;
            string domain   = string.Empty;

            var passwd = cred.CredentialBlob;

            if (!string.IsNullOrEmpty(cred.UserName))
            {
                var user          = cred.UserName;
                var userBuilder   = new StringBuilder(cred.UserName.Length + 2);
                var domainBuilder = new StringBuilder(cred.UserName.Length + 2);

                var returnCode = NativeCode.CredUIParseUserName(user, userBuilder, userBuilder.Capacity, domainBuilder, domainBuilder.Capacity);
                var lastError  = Marshal.GetLastWin32Error();

                //assuming invalid account name to be not meeting condition for CredUIParseUserName
                //"The name must be in UPN or down-level format, or a certificate"
                if (returnCode == NativeCode.CredentialUIReturnCodes.InvalidAccountName)
                {
                    userBuilder.Append(user);
                }
                else if (returnCode != 0)
                {
                    throw new Win32Exception(lastError, String.Format("CredUIParseUserName throw an error (Error code: {0})", lastError));
                }

                username = userBuilder.ToString();
                domain   = domainBuilder.ToString();
            }
            return(new NetworkCredential(username, passwd, domain));
        }
        /// <summary>
        /// Enumerate the specified stored credentials in the Windows Credential store
        /// </summary>
        /// <param name="target">Name of the application or URL for which the credential is used</param>
        /// <returns>Return a <see cref="List{NetworkCredential}"/> if success, null if target not found, throw if failed to read stored credentials</returns>
        public static List <NetworkCredential> EnumerateCredentials(string target = null)
        {
            IntPtr pCredentials = IntPtr.Zero;
            uint   count        = 0;

            var success = NativeCode.CredEnumerate(target, 0, out count, out pCredentials);

            if (!success)
            {
                var lastError = Marshal.GetLastWin32Error();
                if (lastError == (int)NativeCode.CredentialUIReturnCodes.NotFound)
                {
                    return(null);
                }

                throw new Win32Exception(lastError,
                                         string.Format("'CredEnumerate' call throw an error (Error code: {0})", lastError));
            }

            List <NetworkCredential> networkCredentials = new List <NetworkCredential>();

            Credential[] credentials;

            try
            {
                using (var criticalSection = new CriticalCredentialHandle(pCredentials))
                {
                    credentials = criticalSection.EnumerateCredentials(count);
                }
            }
            catch (Exception)
            {
                return(null);
            }

            return(credentials.Select(c => c.ToNetworkCredential()).ToList());
        }
Esempio n. 21
0
        public bool SaveCredential(bool AllowBlankPassword = false)
        {
            IntPtr   buffer = default(IntPtr);
            GCHandle pinned = default(GCHandle);

            if (!String.IsNullOrEmpty(this.Comment) && Encoding.Unicode.GetBytes(this.Comment).Length > 256)
            {
                throw new ArgumentException("Comment can't be more than 256 bytes long", "Comment");
            }

            if (String.IsNullOrEmpty(this.TargetName))
            {
                throw new ArgumentNullException("TargetName", "TargetName can't be Null or Empty");
            }
            else if (this.TargetName.Length > 32767)
            {
                throw new ArgumentNullException("TargetName can't be more than 32kB", "TargetName");
            }

            if (!AllowBlankPassword && String.IsNullOrEmpty(this.CredentialBlob))
            {
                throw new ArgumentNullException("CredentialBlob", "CredentialBlob can't be Null or Empty");
            }

            NativeCode.NativeCredential ncred = new NativeCode.NativeCredential
            {
                Comment            = this.Comment,
                TargetAlias        = null,
                Type               = (UInt32)this.Type,
                Persist            = (UInt32)this.Persistance,
                UserName           = this.UserName,
                TargetName         = this.TargetName,
                CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(this.CredentialBlob).Length
            };
            if (ncred.CredentialBlobSize > MaxCredentialBlobSize)
            {
                throw new ArgumentException($"Credential can't be more than {MaxCredentialBlobSize} bytes long", "CredentialBlob");
            }

            ncred.CredentialBlob = Marshal.StringToCoTaskMemUni(this.CredentialBlob);
            if (this.LastWritten != DateTime.MinValue)
            {
                var fileTime = this.LastWritten.ToFileTimeUtc();
                ncred.LastWritten.dwLowDateTime  = (int)(fileTime & 0xFFFFFFFFL);
                ncred.LastWritten.dwHighDateTime = (int)((fileTime >> 32) & 0xFFFFFFFFL);
            }

            NativeCode.NativeCredentialAttribute[] nativeAttribs = null;
            try
            {
                if (Attributes == null || Attributes.Count == 0)
                {
                    ncred.AttributeCount = 0;
                    ncred.Attributes     = IntPtr.Zero;
                }
                else
                {
                    if (Attributes.Count > 64)
                    {
                        throw new ArgumentException("Credentials can't have more than 64 Attributes!!");
                    }

                    ncred.AttributeCount = (UInt32)Attributes.Count;
                    nativeAttribs        = new NativeCode.NativeCredentialAttribute[Attributes.Count];
                    var    attribSize = Marshal.SizeOf(typeof(NativeCode.NativeCredentialAttribute));
                    byte[] rawData    = new byte[Attributes.Count * attribSize];
                    buffer = Marshal.AllocHGlobal(attribSize);
                    var formatter = new BinaryFormatter();

                    var i = 0;
                    foreach (var a in Attributes)
                    {
                        if (a.Key.Length > 256)
                        {
                            throw new ArgumentException($"Attribute names can't be more than 256 bytes long. Error with key:{a.Key}", a.Key);
                        }
                        if (a.Value == null)
                        {
                            throw new ArgumentNullException(a.Key, $"Attribute value cant'be null. Error with key:{a.Key}");
                        }
                        if (!a.Value.GetType().IsSerializable)
                        {
                            throw new ArgumentException($"Attribute value must be Serializable. Error with key:{a.Key}", a.Key);
                        }

                        using var stream = new MemoryStream();
                        formatter.Serialize(stream, a.Value);
                        var value = stream.ToArray();

                        if (value.Length > 256)
                        {
                            throw new ArgumentException($"Attribute values can't be more than 256 bytes long after serialization. Error with Value for key:{a.Key}", a.Key);
                        }

                        var attrib = new NativeCode.NativeCredentialAttribute
                        {
                            Keyword   = a.Key,
                            ValueSize = (UInt32)value.Length
                        };

                        attrib.Value = Marshal.AllocHGlobal(value.Length);
                        Marshal.Copy(value, 0, attrib.Value, value.Length);
                        nativeAttribs[i] = attrib;

                        Marshal.StructureToPtr(attrib, buffer, false);
                        Marshal.Copy(buffer, rawData, i * attribSize, attribSize);
                        i++;
                    }
                    pinned           = GCHandle.Alloc(rawData, GCHandleType.Pinned);
                    ncred.Attributes = pinned.AddrOfPinnedObject();
                }
                // Write the info into the CredMan storage.

                if (NativeCode.CredWrite(ref ncred, 0))
                {
                    return(true);
                }
                else
                {
                    int lastError = Marshal.GetLastWin32Error();
                    throw new CredentialAPIException($"Unable to Save Credential", "CredWrite", lastError);
                }
            }

            finally
            {
                if (ncred.CredentialBlob != default(IntPtr))
                {
                    Marshal.FreeCoTaskMem(ncred.CredentialBlob);
                }
                if (nativeAttribs != null)
                {
                    foreach (var a in nativeAttribs)
                    {
                        if (a.Value != default(IntPtr))
                        {
                            Marshal.FreeHGlobal(a.Value);
                        }
                    }
                    if (pinned.IsAllocated)
                    {
                        pinned.Free();
                    }
                    if (buffer != default(IntPtr))
                    {
                        Marshal.FreeHGlobal(buffer);
                    }
                }
            }
        }
        private static bool PromptForCredentials(string target, NativeCode.CredentialUIInfo credUI, ref bool save, out string user, out string password, out string domain)
        {
            user     = String.Empty;
            password = String.Empty;
            domain   = String.Empty;

            // Setup the flags and variables
            credUI.cbSize = Marshal.SizeOf(credUI);
            int  errorcode   = 0;
            uint authPackage = 0;

            IntPtr outCredBuffer = new IntPtr();
            uint   outCredSize;
            var    flags = NativeCode.PromptForWindowsCredentialsFlags.GenericCredentials |
                           NativeCode.PromptForWindowsCredentialsFlags.EnumerateCurrentUser;

            flags = save ? flags | NativeCode.PromptForWindowsCredentialsFlags.ShowCheckbox : flags;

            // Setup the flags and variables
            int result = NativeCode.CredUIPromptForWindowsCredentials(ref credUI,
                                                                      errorcode,
                                                                      ref authPackage,
                                                                      IntPtr.Zero,
                                                                      0,
                                                                      out outCredBuffer,
                                                                      out outCredSize,
                                                                      ref save,
                                                                      flags);

            var usernameBuf = new StringBuilder(100);
            var passwordBuf = new StringBuilder(100);
            var domainBuf   = new StringBuilder(100);

            int maxUserName = 100;
            int maxDomain   = 100;
            int maxPassword = 100;

            if (result == 0)
            {
                if (NativeCode.CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf, ref maxUserName,
                                                              domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
                {
                    user     = usernameBuf.ToString();
                    password = passwordBuf.ToString();
                    domain   = domainBuf.ToString();
                    if (String.IsNullOrWhiteSpace(domain))
                    {
                        Debug.WriteLine("Domain null");
                        if (!ParseUserName(usernameBuf.ToString(), usernameBuf.Capacity, domainBuf.Capacity, out user, out domain))
                        {
                            user = usernameBuf.ToString();
                        }
                        password = passwordBuf.ToString();
                    }
                }

                //mimic SecureZeroMem function to make sure buffer is zeroed out. SecureZeroMem is not an exported function, neither is RtlSecureZeroMemory
                var zeroBytes = new byte[outCredSize];
                Marshal.Copy(zeroBytes, 0, outCredBuffer, (int)outCredSize);

                //clear the memory allocated by CredUIPromptForWindowsCredentials
                NativeCode.CoTaskMemFree(outCredBuffer);
                return(true);
            }

            user   = null;
            domain = null;
            return(false);
        }