Skip to content

Instantly share code, notes, and snippets.

@Rene-Sackers
Last active June 8, 2023 16:43
Show Gist options
  • Save Rene-Sackers/dc99ec903024a05ea2146f19c664e65a to your computer and use it in GitHub Desktop.
Save Rene-Sackers/dc99ec903024a05ea2146f19c664e65a to your computer and use it in GitHub Desktop.
.NET 5+ WindowsCredentialVault access
using System.Security;
public static class ConsolePasswordInput
{
public static SecureString? ReadPassword()
{
var securePassword = new SecureString();
while (true)
{
var inputKey = Console.ReadKey();
switch (inputKey.Key)
{
case ConsoleKey.Enter:
securePassword.MakeReadOnly();
return securePassword;
case ConsoleKey.Escape:
securePassword.Clear();
return null;
case ConsoleKey.Backspace:
if (securePassword.Length <= 0)
{
Console.CursorLeft++;
continue;
}
securePassword.RemoveAt(securePassword.Length - 1);
Console.Write(" ");
Console.CursorLeft--;
continue;
}
securePassword.AppendChar(inputKey.KeyChar);
Console.CursorLeft--;
Console.Write("•");
}
}
}
// 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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment