CredRead (advapi32)
Last changed: -194.146.189.99

.
Summary
Read the credential (generic, domain, etc) from the windows key ring.

C# Signature:

        [DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern bool CredRead(string target, CRED_TYPE type, int reservedFlag,
                          [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(CredentialInMarshaler))]out Credential credential);

VB Signature:

<Runtime.InteropServices.DllImport("advapi32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Unicode)> _
Function CredReadW( _
ByVal strTargetName$, _
ByVal intType As UInteger, _
ByVal intFlags As UInteger, _
ByRef intCredential As IntPtr) As Boolean

VB.NET type:

<Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Sequential, CharSet:=Runtime.InteropServices.CharSet.Unicode)> _
Structure Credential
   Dim Flags As UInteger
   Dim Type As UInteger
   Dim TargetName$
   Dim Comment$
   Dim LastWritten As System.Runtime.InteropServices.ComTypes.FILETIME
   Dim CredentialBlobSize As UInteger
   Dim CredentialBlob As IntPtr
   Dim Persist As UInteger
   Dim AttributeCount As UInteger
   Dim Attributes As IntPtr
   Dim TargetAlias$
   Dim UserName$
End Structure

Sample Code:

VB.NET

Dim credRead As New Credential
Dim credPtr As IntPtr

Dim blnCredReadResult As Boolean
blnCredReadResult = WinAPI.CredReadW("API_key", &H1, 0, credPtr)

If blnCredReadResult Then
  credRead = CType(Runtime.InteropServices.Marshal.PtrToStructure(credPtr, GetType(Credential)), Credential)
  Dim arrB(credRead.CredentialBlobSize - 1) As Byte
  Runtime.InteropServices.Marshal.Copy(credRead.CredentialBlob, arrB, 0, credRead.CredentialBlobSize)
  Console.WriteLine(Text.Encoding.Unicode.GetString(arrB))
End If

User-Defined Types:

        public enum CRED_TYPE : uint
        {
        GENERIC = 1,
        DOMAIN_PASSWORD = 2,
        DOMAIN_CERTIFICATE = 3,
        DOMAIN_VISIBLE_PASSWORD = 4,
        GENERIC_CERTIFICATE = 5,
        DOMAIN_EXTENDED = 6,
        MAXIMUM = 7,      // Maximum supported cred type
        MAXIMUM_EX = (MAXIMUM + 1000),  // Allow new applications to run on old OSes
        }

        public enum CRED_PERSIST : uint
        {
        SESSION = 1,
        LOCAL_MACHINE = 2,
        ENTERPRISE = 3,
        }

       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct CREDENTIAL_ATTRIBUTE
        {
        string Keyword;
        uint Flags;
        uint ValueSize;
        IntPtr Value;
        }

        //This type is deliberately not designed to be marshalled.
        public class Credential
        {
        public UInt32 Flags;
        public CRED_TYPE Type;
        public string TargetName;
        public string Comment;
        public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
        public byte[] CredentialBlob;
        public CRED_PERSIST Persist;
        public CREDENTIAL_ATTRIBUTE[] Attributes;
        public string TargetAlias;
        public string UserName;
        }

        /// <summary>
        ///
        /// </summary>
        public class CredentialInMarshaler : ICustomMarshaler
        {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private class NATIVECREDENTIAL
        {
            public UInt32 Flags;
            public CRED_TYPE Type;
            public string TargetName;
            public string Comment;
            public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
            public UInt32 CredentialBlobSize;
            public IntPtr CredentialBlob;
            public CRED_PERSIST Persist;
            public UInt32 AttributeCount;
            public IntPtr Attributes;
            public string TargetAlias;
            public string UserName;
        }          

        public void CleanUpManagedData(object ManagedObj)
        {
            // Nothing to do since all data can be garbage collected.
        }

        public void CleanUpNativeData(IntPtr pNativeData)
        {
            if (pNativeData == IntPtr.Zero)
            {
            return;
            }
            CredFree(pNativeData);
        }

        public int GetNativeDataSize()
        {
            throw new NotImplementedException();
        }

        public IntPtr MarshalManagedToNative(object obj)
        {
            throw new NotImplementedException();
        }

        public object MarshalNativeToManaged(IntPtr pNativeData)
        {
            if (pNativeData == IntPtr.Zero)
            {
            return null;
            }

            NATIVECREDENTIAL lRawCredential = (NATIVECREDENTIAL)Marshal.PtrToStructure(pNativeData, typeof(NATIVECREDENTIAL));

            Credential lCredential = new Credential()
            {
            UserName = lRawCredential.UserName,
            TargetName = lRawCredential.TargetName,
            TargetAlias = lRawCredential.TargetAlias,
            Persist = lRawCredential.Persist,
            Comment = lRawCredential.Comment,
            Flags = lRawCredential.Flags,
            LastWritten = lRawCredential.LastWritten,
            Type = lRawCredential.Type,
            CredentialBlob = new byte[lRawCredential.CredentialBlobSize],
            Attributes = new CREDENTIAL_ATTRIBUTE[lRawCredential.AttributeCount]
            };

            Marshal.Copy(lRawCredential.CredentialBlob, lCredential.CredentialBlob, 0, (int)lRawCredential.CredentialBlobSize);

            return lCredential;
        }

        public static ICustomMarshaler GetInstance(string cookie)
        {
            return new CredentialInMarshaler();
        }
        }

Alternative Managed API:

Do you know one? Please contribute it!

Notes:

Attributes are not properly supported at this time.

An alternate approach to this can be found at http://blogs.msdn.com/peerchan/pages/487834.aspx. However as presented that technique requires more manual marshalling and more work for the calling code.

Custom Marshalling provide a self contained and caller transparent solution to this scenario, the returned Credentials object is fully managed without the need to worry about object lifetimes.

Tips & Tricks:

Use System.Text.Encoding.Unicode.GetString to convert the CredentialBlob into a password string.

Sample Code:

Documentation
CredRead on MSDN