public NetworkCredential Read(string target) { Trace.Entering(); ArgUtil.NotNullOrEmpty(target, nameof(target)); IntPtr credPtr = IntPtr.Zero; try { if (CredRead(target, CredentialType.Generic, 0, out credPtr)) { Credential credStruct = (Credential)Marshal.PtrToStructure(credPtr, typeof(Credential)); int passwordLength = (int)credStruct.CredentialBlobSize; string password = passwordLength > 0 ? Marshal.PtrToStringUni(credStruct.CredentialBlob, passwordLength / sizeof(char)) : String.Empty; string username = Marshal.PtrToStringUni(credStruct.UserName); Trace.Info($"Credentials for '{target}' read from windows credential store."); // delete from .credential_store file since we are able to read it from windows credential store if (_credStore.Remove(target)) { Trace.Info($"Delete credentials for '{target}' from credential store file."); SyncCredentialStoreFile(); } return(new NetworkCredential(username, password)); } else { // Can't read from Windows Credential Store, fail back to .credential_store file if (_credStore.ContainsKey(target) && !string.IsNullOrEmpty(_credStore[target])) { Trace.Info($"Credentials for '{target}' read from credential store file."); // Base64Decode -> DP-API machine level decrypt -> Base64Username:Base64Password -> Base64Decode string decryptedUsernamePassword = Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(_credStore[target]), null, DataProtectionScope.LocalMachine)); string[] credential = decryptedUsernamePassword.Split(':'); if (credential.Length == 2 && !string.IsNullOrEmpty(credential[0]) && !string.IsNullOrEmpty(credential[1])) { string username = Encoding.UTF8.GetString(Convert.FromBase64String(credential[0])); string password = Encoding.UTF8.GetString(Convert.FromBase64String(credential[1])); // store back to windows credential store for current user NetworkCredential creds = WriteInternal(target, username, password); // delete from .credential_store file since we are able to write the credential to windows credential store for current user. if (_credStore.Remove(target)) { Trace.Info($"Delete credentials for '{target}' from credential store file."); SyncCredentialStoreFile(); } return(creds); } else { throw new ArgumentOutOfRangeException(nameof(decryptedUsernamePassword)); } } throw new Win32Exception(Marshal.GetLastWin32Error(), $"CredRead throw an error for '{target}'"); } } finally { if (credPtr != IntPtr.Zero) { CredFree(credPtr); } } }
internal static extern bool CredWrite([In] ref Credential userCredential, [In] UInt32 flags);