Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using the Windows Credential API (CredRead, CredWrite, CredDelete, CredEnumerate).
// The most up to date version is available
// on GitHub: https://github.com/meziantou/Meziantou.Framework/tree/master/src/Meziantou.Framework.Win32.CredentialManager
// NuGet package: https://www.nuget.org/packages/Meziantou.Framework.Win32.CredentialManager/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
public static class CredentialManager
{
public static Credential ReadCredential(string applicationName)
{
IntPtr nCredPtr;
bool read = CredRead(applicationName, CredentialType.Generic, 0, out nCredPtr);
if (read)
{
using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr))
{
CREDENTIAL cred = critCred.GetCredential();
return ReadCredential(cred);
}
}
return null;
}
private static Credential ReadCredential(CREDENTIAL credential)
{
string applicationName = Marshal.PtrToStringUni(credential.TargetName);
string userName = Marshal.PtrToStringUni(credential.UserName);
string secret = null;
if (credential.CredentialBlob != IntPtr.Zero)
{
secret = Marshal.PtrToStringUni(credential.CredentialBlob, (int)credential.CredentialBlobSize / 2);
}
return new Credential(credential.Type, applicationName, userName, secret);
}
public static void WriteCredential(string applicationName, string userName, string secret)
{
byte[] byteArray = secret == null ? null : Encoding.Unicode.GetBytes(secret);
// XP and Vista: 512;
// 7 and above: 5*512
if (Environment.OSVersion.Version < new Version(6, 1) /* Windows 7 */)
{
if (byteArray != null && byteArray.Length > 512)
throw new ArgumentOutOfRangeException("secret", "The secret message has exceeded 512 bytes.");
}
else
{
if (byteArray != null && byteArray.Length > 512 * 5)
throw new ArgumentOutOfRangeException("secret", "The secret message has exceeded 2560 bytes.");
}
CREDENTIAL credential = new CREDENTIAL();
credential.AttributeCount = 0;
credential.Attributes = IntPtr.Zero;
credential.Comment = IntPtr.Zero;
credential.TargetAlias = IntPtr.Zero;
credential.Type = CredentialType.Generic;
credential.Persist = (uint)CredentialPersistence.LocalMachine;
credential.CredentialBlobSize = (uint)(byteArray == null ? 0 : byteArray.Length);
credential.TargetName = Marshal.StringToCoTaskMemUni(applicationName);
credential.CredentialBlob = Marshal.StringToCoTaskMemUni(secret);
credential.UserName = Marshal.StringToCoTaskMemUni(userName ?? Environment.UserName);
bool written = CredWrite(ref credential, 0);
Marshal.FreeCoTaskMem(credential.TargetName);
Marshal.FreeCoTaskMem(credential.CredentialBlob);
Marshal.FreeCoTaskMem(credential.UserName);
if (!written)
{
int lastError = Marshal.GetLastWin32Error();
throw new Exception(string.Format("CredWrite failed with the error code {0}.", lastError));
}
}
public static IReadOnlyList<Credential> EnumerateCrendentials()
{
List<Credential> result = new List<Credential>();
int count;
IntPtr pCredentials;
bool ret = CredEnumerate(null, 0, out count, out pCredentials);
if (ret)
{
for (int n = 0; n < count; n++)
{
IntPtr credential = Marshal.ReadIntPtr(pCredentials, n * Marshal.SizeOf(typeof(IntPtr)));
result.Add(ReadCredential((CREDENTIAL)Marshal.PtrToStructure(credential, typeof(CREDENTIAL))));
}
}
else
{
int lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(lastError);
}
return result;
}
[DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredRead(string target, CredentialType type, int reservedFlag, out IntPtr credentialPtr);
[DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredWrite([In] ref CREDENTIAL userCredential, [In] UInt32 flags);
[DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CredEnumerate(string filter, int flag, out int count, out IntPtr pCredentials);
[DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)]
static extern bool CredFree([In] IntPtr cred);
private enum CredentialPersistence : uint
{
Session = 1,
LocalMachine,
Enterprise
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct CREDENTIAL
{
public uint Flags;
public CredentialType Type;
public IntPtr TargetName;
public IntPtr Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public uint CredentialBlobSize;
public IntPtr CredentialBlob;
public uint Persist;
public uint AttributeCount;
public IntPtr Attributes;
public IntPtr TargetAlias;
public IntPtr UserName;
}
sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid
{
public CriticalCredentialHandle(IntPtr preexistingHandle)
{
SetHandle(preexistingHandle);
}
public CREDENTIAL GetCredential()
{
if (!IsInvalid)
{
CREDENTIAL credential = (CREDENTIAL)Marshal.PtrToStructure(handle, typeof(CREDENTIAL));
return credential;
}
throw new InvalidOperationException("Invalid CriticalHandle!");
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
CredFree(handle);
SetHandleAsInvalid();
return true;
}
return false;
}
}
}
public enum CredentialType
{
Generic = 1,
DomainPassword,
DomainCertificate,
DomainVisiblePassword,
GenericCertificate,
DomainExtended,
Maximum,
MaximumEx = Maximum + 1000,
}
public class Credential
{
private readonly string _applicationName;
private readonly string _userName;
private readonly string _password;
private readonly CredentialType _credentialType;
public CredentialType CredentialType
{
get { return _credentialType; }
}
public string ApplicationName
{
get { return _applicationName; }
}
public string UserName
{
get { return _userName; }
}
public string Password
{
get { return _password; }
}
public Credential(CredentialType credentialType, string applicationName, string userName, string password)
{
_applicationName = applicationName;
_userName = userName;
_password = password;
_credentialType = credentialType;
}
public override string ToString()
{
return string.Format("CredentialType: {0}, ApplicationName: {1}, UserName: {2}, Password: {3}", CredentialType, ApplicationName, UserName, Password);
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(CredentialManager.ReadCredential("Demo"));
CredentialManager.WriteCredential("Demo", "Meziantou", "Passw0rd");
CredentialManager.WriteCredential("http://www.softfluent.com", "Meziantou", "Passw0rd");
Console.WriteLine(CredentialManager.ReadCredential("Demo"));
foreach (var credential in CredentialManager.EnumerateCrendentials())
{
Console.WriteLine(credential);
}
}
}
@drjasonharrison

This comment has been minimized.

Copy link

commented Mar 14, 2016

@gérald what is the license for this code?

@MarkRobertJohnson

This comment has been minimized.

Copy link

commented Aug 17, 2016

Great, very helpful to enumerate the full list of a all vault credentials, thanks!

@mfekry

This comment has been minimized.

Copy link

commented Aug 30, 2016

hi do you have any idea how to pass the current logged on domain user credential to Outlook without prompting the user to write password for 1st time when he open the outlook

@prem16

This comment has been minimized.

Copy link

commented Aug 19, 2017

hi, Sir I am Prem Murmu,this is really very good. and Useful for me,
But i want to show list of DomainNetwork credential too,how i can do that.. with these code..

@pvpxan

This comment has been minimized.

Copy link

commented Feb 27, 2018

Is there a reason you are using Marshal.StringToCoTaskMemUni on the target, username, and password. I created a similar function that does not use that and just passes the strings in from managed memory. Instead pointers I use strings for the username/pw/target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.