2010-03-08 14 views
3

J'essaie d'utiliser CredWrite, mais obtenir une erreur ERROR_INVALID_PARAMETER 87 (0x57). L'intention est d'avoir un endroit sûr pour enregistrer le mot de passe de l'utilisateur pour mon application .net WPF.Quelqu'un a-t-il utilisé la fonction CredWrite de l'API Win32 dans .NET?

Et mon code:

public class CredMan 
{ 
    private const string TARGET_PREFIX = "myappname:"; 

    public static void SavePassword(string username, string password) 
    { 
     Win32CredMan.Credential cred = new Win32CredMan.Credential(); 
     cred.Flags = 0; 
     cred.Type = Win32CredMan.CRED_TYPE.GENERIC; 
     cred.TargetName = TARGET_PREFIX + username; 

     var encoding = new System.Text.UTF8Encoding(); 
     cred.CredentialBlob = encoding.GetBytes(password); 
     cred.Persist = Win32CredMan.CRED_PERSIST.LOCAL_MACHINE; 
     cred.UserName = username; 

     bool isGood = Win32CredMan.CredWrite(cred, 0); 
     int lastError = Marshal.GetLastWin32Error(); 

    } 
} 

Ceci est l'emballage win32: (la plupart du temps attrapé par pinvoke.net)

internal class Win32CredMan 
{ 
    [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); 

    [DllImport("Advapi32.dll", EntryPoint = "CredFreeW", CharSet = CharSet.Unicode, SetLastError = true)] 
    public static extern void CredFree(IntPtr buffer); 

    [DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredWriteW", CharSet = CharSet.Unicode)] 
    public static extern bool CredWrite([In] Credential userCredential, [In] UInt32 flags); 

    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; 
    } 
} 
+0

Jetez un oeil ici .... http://stackoverflow.com/questions/2337672/credwrite-returns-win32-error-code-2-error-invalid-function-incorrect-function/2337753#2337753 – t0mm13b

+1

Juste relisez le code, et il semble que la classe Credential n'est pas en train d'être rassemblée (selon le commentaire) .... hmm! :) – mlsteeves

+4

http://blogs.msdn.com/peerchan/pages/487834.aspx --A une solution complète, et cela fonctionne. – mlsteeves

Répondre

3

Je suis tombé sur ce même problème maintenant. J'ai trouvé que ce problème s'est produit en utilisant l'option DOMAIN_PASSWORD comme type d'informations d'identification. Il s'avère que le TargetName contenait une valeur incorrecte.

Vous ne devez spécifier que l'adresse DNS ou IP (caractère générique facultatif), mais ne contenant PAS une URL ou un protocole complet. par exemple. "* .microsoft.com" est correct, mais "http://www.microsoft.com/" est INVALIDE

Je vais juste poster ceci ici au cas où d'autres personnes rencontreraient ce problème. m'a pris un moment pour le trouver.

+0

FYI: Les limitations sur la spécification du domaine sont similaires à celles de la fonction OSX SecKeychainItemCreateFromContent utilisée avec les services Keychain –