// Install package System.Runtime.InteropServices
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
public static class WindowsCredentialVault
{
public static bool WriteCredential(string credentialName, string username, SecureString password)
{
// Encrypt the password
password.MakeReadOnly();
var credentialBlob = new byte[password.Length * 2];
Marshal.Copy(Marshal.SecureStringToGlobalAllocUnicode(password), credentialBlob, 0,
credentialBlob.Length);
// Create the Credential struct
var credential = new Credential
{
Flags = 0,
Type = CredentialType.Generic,
TargetName = Marshal.StringToCoTaskMemUni(credentialName),
Comment = nint.Zero,
LastWritten = new System.Runtime.InteropServices.ComTypes.FILETIME(),
CredentialBlobSize = (uint)credentialBlob.Length,
CredentialBlob = Marshal.AllocHGlobal(credentialBlob.Length),
Persist = (uint)CredentialPersist.LocalMachine,
AttributeCount = 0,
Attributes = nint.Zero,
TargetAlias = nint.Zero,
UserName = Marshal.StringToCoTaskMemUni(username),
};
Marshal.Copy(credentialBlob, 0, credential.CredentialBlob, credentialBlob.Length);
// Write the credential to the Windows Credential Manager
var success = CredWrite(ref credential, 0);
// Free the allocated memory
Marshal.ZeroFreeGlobalAllocUnicode(credential.TargetName);
Marshal.ZeroFreeGlobalAllocUnicode(credential.UserName);
Marshal.FreeHGlobal(credential.CredentialBlob);
return success;
}
public static NetworkCredential ReadCredential(string credentialName)
{
// Read the credential from the Windows Credential Manager
var success = CredRead(credentialName, CredentialType.Generic, 0, out var credentialPtr);
if (success)
{
var credential = (Credential)Marshal.PtrToStructure(credentialPtr, typeof(Credential));
var username = Marshal.PtrToStringUni(credential.UserName);
var password = Marshal.PtrToStringUni(credential.CredentialBlob, (int)credential.CredentialBlobSize / 2);
// Free the allocated memory
CredFree(credentialPtr);
return new NetworkCredential(username, password);
}
var errorCode = Marshal.GetLastWin32Error();
if (errorCode == 1168)
throw new InvalidOperationException("The credential was not found.");
throw new InvalidOperationException($"Failed to read credential: Error code {errorCode}");
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Credential
{
public uint Flags;
public CredentialType Type;
public nint TargetName;
public nint Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public uint CredentialBlobSize;
public nint CredentialBlob;
public uint Persist;
public uint AttributeCount;
public nint Attributes;
public nint TargetAlias;
public nint UserName;
}
public enum CredentialPersist : uint
{
Session = 1,
LocalMachine = 2,
Enterprise = 3,
}
public enum CredentialType : uint
{
Generic = 1,
DomainPassword = 2,
DomainCertificate = 3,
DomainVisiblePassword = 4,
GenericCertificate = 5,
DomainExtended = 6,
Maximum = 7,
MaximumEx = (Maximum + 1000),
}
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool CredRead(string target, CredentialType type, int reservedFlag, out nint credential);
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool CredWrite([In] ref Credential userCredential, [In] uint flags);
[DllImport("Advapi32.dll", SetLastError = true)]
private static extern void CredFree(nint credential);
}