• FindPrivateKey X509


    
    namespace Microsoft.ChannelSDK.Tools.FindPrivateKey
    {
        using System;
        using System.IO;
        using System.Security.Cryptography.X509Certificates;
        using System.Runtime.InteropServices;
        class FindPrivateKey
        {
            static void PrintHelp()
            {
                Console.WriteLine("FindPrivateKey helps user to find the location of the Private Key file of a X.509 Certificate.");
                Console.WriteLine("Usage: FindPrivateKey <storeName> <storeLocation> [{ {-n <subjectName>} | {-t <thumbprint>} } [-f | -d | -a]]");
                Console.WriteLine("       <subjectName> subject name of the certificate");
                Console.WriteLine("       <thumbprint>  thumbprint of the certificate (use certmgr.exe to get it)");
                Console.WriteLine("       -f            output file name only");
                Console.WriteLine("       -d            output directory only");
                Console.WriteLine("       -a            output absolute file name");
                Console.WriteLine("e.g. FindPrivateKey My CurrentUser -n \"CN=John Doe\"");
                Console.WriteLine("e.g. FindPrivateKey My LocalMachine -t \"03 33 98 63 d0 47 e7 48 71 33 62 64 76 5c 4c 9d 42 1d 6b 52\" -a");
            }
            static void Main(string[] args)
            {            
                if (args.Length < 2 || args.Length == 3 || args.Length > 5 
                    || (args.Length > 2 && args[2] != "-n" && args[2] != "-t")
                    || (args.Length == 5 && args[4] != "-f" && args[4] != "-d" && args[4] != "-a"))
                {
                    PrintHelp();
                    return;
                }
                try
                {
                    StoreName storeName = (StoreName)Enum.Parse(typeof(StoreName), args[0], true);
                    StoreLocation storeLocation = (StoreLocation)Enum.Parse(typeof(StoreLocation), args[1], true);
                    X509Certificate2 cert;
                    if (args.Length > 2)
                    {
                        // insert a comma followed by a space for store.Certificates.Find(findType, key, false) 
                        // to successful find the certificate
                        string key = args[3];
                        string[] keys = key.Split(',');
                        key = string.Empty;
                        for (int i = 0; i < keys.Length; i++)
                        {
                            key += keys[i];
                            if ( i != keys.Length -1 )
                             key += ", ";
                        }
                        if (args[2] == "-n")
                            cert = LoadCertificate(storeName, storeLocation, key, X509FindType.FindBySubjectDistinguishedName);
                        else
                            cert = LoadCertificate(storeName, storeLocation, key, X509FindType.FindByThumbprint);
                    }
                    else
                    {
                        cert = SelectCertificate(storeName, storeLocation);
                        if (cert == null)
                            return;
                    }
                    string privateKeyFile = GetKeyFileName(cert);
                    string privateKeyDirectory = GetKeyFileDirectory(privateKeyFile);
                    if (args.Length == 5)
                    {
                        if (args[4] == "-f")
                            Console.WriteLine(privateKeyFile);
                        else if (args[4] == "-d")
                            Console.WriteLine(privateKeyDirectory);
                        else
                            Console.WriteLine("a:{0}\\{1}", privateKeyDirectory, privateKeyFile);
                    }
                    else
                    {
                        Console.WriteLine("Private key directory:");
                        Console.WriteLine(privateKeyDirectory);
                        Console.WriteLine("Private key file name:");
                        Console.WriteLine(privateKeyFile);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("FindPrivateKey failed for the following reason:");
                    Console.WriteLine(ex.Message);
                    Console.WriteLine("\nUse /? option for help");
                }
            }
            static X509Certificate2 SelectCertificate(StoreName storeName, StoreLocation storeLocation)
            {
                X509Certificate2 result;
                X509Store store = new X509Store(storeName, storeLocation);
                store.Open(OpenFlags.ReadOnly);
                try
                {
                    X509Certificate2Collection matches;
                    matches = X509Certificate2UI.SelectFromCollection(store.Certificates, "Select certificate", "Select the certificate to find the location of the associated private key file:", X509SelectionFlag.SingleSelection);
                    if (matches.Count != 1)
                        result = null;
                    else
                        result = matches[0];
                }
                finally
                {
                    store.Close();
                }
                return result;
            }
            static X509Certificate2 LoadCertificate(StoreName storeName, StoreLocation storeLocation, string key, X509FindType findType)
            {
                X509Certificate2 result;
                X509Store store = new X509Store(storeName, storeLocation);
                store.Open(OpenFlags.ReadOnly);
                try
                {
                    X509Certificate2Collection matches;
                    matches = store.Certificates.Find(findType, key, false);
                    if (matches.Count > 1)
                        throw new InvalidOperationException(String.Format("More than one certificate with key '{0}' found in the store.", key));
                    if (matches.Count == 0)
                        throw new InvalidOperationException(String.Format("No certificates with key '{0}' found in the store.", key));
                    result = matches[0];
                }
                finally
                {
                    store.Close();
                }
                return result;
            }
            static string GetKeyFileName(X509Certificate2 cert)
            {
                IntPtr            hProvider     = IntPtr.Zero; // CSP handle
                bool              freeProvider  = false;       // Do we need to free the CSP ?
                uint               acquireFlags  = 0;
                int                  _keyNumber = 0;
                string              keyFileName = null;
                byte[]              keyFileBytes = null;
                //
                // Determine whether there is private key information available for this certificate in the key store
                //
                if ( CryptAcquireCertificatePrivateKey(cert.Handle,
                    acquireFlags,
                    IntPtr.Zero,
                    ref hProvider,
                    ref _keyNumber,
                    ref freeProvider) )
                {
                    IntPtr pBytes  = IntPtr.Zero; // Native Memory for the CRYPT_KEY_PROV_INFO structure
                    int    cbBytes = 0;           // Native Memory size
                    try
                    {
                        if ( CryptGetProvParam(hProvider, CryptGetProvParamType.PP_UNIQUE_CONTAINER, IntPtr.Zero, ref cbBytes, 0) )
                        {
                            pBytes = Marshal.AllocHGlobal(cbBytes);
                            if ( CryptGetProvParam(hProvider, CryptGetProvParamType.PP_UNIQUE_CONTAINER, pBytes, ref cbBytes, 0) )
                            {
                                keyFileBytes = new byte[cbBytes];
                                Marshal.Copy(pBytes,keyFileBytes,0,cbBytes);
                                // Copy eveything except tailing null byte
                                keyFileName = System.Text.Encoding.ASCII.GetString(keyFileBytes, 0, keyFileBytes.Length-1);
                            }
                        }        
                    }
                    finally
                    {
                        if ( freeProvider )
                            CryptReleaseContext(hProvider,0);
                        //
                        // Free our native memory
                        //
                        if ( pBytes != IntPtr.Zero )
                            Marshal.FreeHGlobal(pBytes);
                    }
                }
                if (keyFileName == null)
                    throw new InvalidOperationException("Unable to obtain private key file name");
                return keyFileName;
            }
            static string GetKeyFileDirectory(string keyFileName)
            {
                // Look up All User profile from environment variable
                string allUserProfile = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
                // set up searching directory
                string machineKeyDir = allUserProfile + "\\Microsoft\\Crypto\\RSA\\MachineKeys";
                // Seach the key file
                string[] fs = System.IO.Directory.GetFiles(machineKeyDir, keyFileName);
                // If found
                if (fs.Length > 0)
                    return machineKeyDir;
                // Next try current user profile
                string currentUserProfile = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                // seach all sub directory
                string userKeyDir = currentUserProfile + "\\Microsoft\\Crypto\\RSA\\";
                fs = System.IO.Directory.GetDirectories(userKeyDir);
                if (fs.Length > 0)
                {
                    // for each sub directory
                    foreach (string keyDir in fs)
                    {
                        fs = System.IO.Directory.GetFiles(keyDir, keyFileName);
                        if (fs.Length == 0)
                            continue;
                        else
                            // found
                            return keyDir;
                    }
                }
                throw new InvalidOperationException("Unable to locate private key file directory");
            }
            [DllImport("crypt32", CharSet = CharSet.Unicode, SetLastError = true)]
            internal extern static bool CryptAcquireCertificatePrivateKey(IntPtr pCert, uint dwFlags, IntPtr pvReserved, ref IntPtr phCryptProv, ref int pdwKeySpec, ref bool pfCallerFreeProv);
            [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true)]
            internal extern static bool CryptGetProvParam(IntPtr hCryptProv, CryptGetProvParamType dwParam, IntPtr pvData, ref int pcbData, uint dwFlags);
            [DllImport("advapi32", SetLastError = true)]
            internal extern static bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
        }
        enum CryptGetProvParamType
        {
            PP_ENUMALGS = 1,
            PP_ENUMCONTAINERS = 2,
            PP_IMPTYPE = 3,
            PP_NAME = 4,
            PP_VERSION = 5,
            PP_CONTAINER = 6,
            PP_CHANGE_PASSWORD = 7,
            PP_KEYSET_SEC_DESCR = 8,       // get/set security descriptor of keyset
            PP_CERTCHAIN = 9,      // for retrieving certificates from tokens
            PP_KEY_TYPE_SUBTYPE = 10,
            PP_PROVTYPE = 16,
            PP_KEYSTORAGE = 17,
            PP_APPLI_CERT = 18,
            PP_SYM_KEYSIZE = 19,
            PP_SESSION_KEYSIZE = 20,
            PP_UI_PROMPT = 21,
            PP_ENUMALGS_EX = 22,
            PP_ENUMMANDROOTS = 25,
            PP_ENUMELECTROOTS = 26,
            PP_KEYSET_TYPE = 27,
            PP_ADMIN_PIN = 31,
            PP_KEYEXCHANGE_PIN = 32,
            PP_SIGNATURE_PIN = 33,
            PP_SIG_KEYSIZE_INC = 34,
            PP_KEYX_KEYSIZE_INC = 35,
            PP_UNIQUE_CONTAINER = 36,
            PP_SGC_INFO = 37,
            PP_USE_HARDWARE_RNG = 38,
            PP_KEYSPEC = 39,
            PP_ENUMEX_SIGNING_PROT = 40,
            PP_CRYPT_COUNT_KEY_USE = 41,
        }
    }
    
    
  • 相关阅读:
    课程作业06-汇总整理
    课程作业04-汇总整理
    课程作业04-字串加密解密
    课程作业03-你已经创建了多少个对象?
    课程作业03-汇总整理
    课程作业02-汇总整理
    02-实验性问题总结归纳
    猜数字游戏
    RandomStr实验报告(验证码实验)
    个人总结
  • 原文地址:https://www.cnblogs.com/Microshaoft/p/1460665.html
Copyright © 2020-2023  润新知