X509Certificate2构造函数参数字符串fileName类型

时间:2018-02-04 03:10:44

标签: c# cryptography

第一个参数中文件的格式(.pfx,.cer或其他什么)应该是什么?

public X509Certificate2(
    string fileName,
    SecureString password,
    X509KeyStorageFlags keyStorageFlags
)

更多背景信息:

我在尝试使用以下函数获取证书时遇到以下错误 -

功能:

public static X509Certificate2 AuthenticationCertificate(string AuthenticationCertificateAsBase64String, string AuthenticationCertificatePassword)
        {
            if (!string.IsNullOrEmpty(AuthenticationCertificateAsBase64String) &&
                AuthenticationCertificatePassword != null)
            {
                Console.WriteLine("AuthenticationCertificateAsBase64String: " + AuthenticationCertificateAsBase64String);
                Console.WriteLine("AuthenticationCertificatePassword: " + AuthenticationCertificatePassword);
                return new X509Certificate2(Convert.FromBase64String(AuthenticationCertificateAsBase64String),
                    AuthenticationCertificatePassword);
            }
            return null;
        }

错误:

{System.Security.Cryptography.CryptographicException: The specified network password is not correct.

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
   at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password)
   at CryptoPlay.Program.AuthenticationCertificate(String AuthenticationCertificateAsBase64String, String AuthenticationCertificatePassword) in d:\personal\CryptoPlay\CryptoPlay\Program.cs:line 154
   at CryptoPlay.Program.Main(String[] args) in d:\personal\CryptoPlay\CryptoPlay\Program.cs:line 59
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()}

错误表示密码不正确但不是这样。如果有人感兴趣,这里是完整的参考代码(将文件名和密码替换为通用名称作为示例)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Pkcs;

namespace CryptoPlay
{
    class Program
    {
        static void Main(string[] args)
        {
            X509Certificate2 spCert = GetCertificateForUse();
            X509Certificate2 encryptCert = GetCertificateUsedForEncryption();

            string AuthenticationCertificatePasswordBase64String = EncryptAsBase64String(encryptCert, "Password1!");
            Console.WriteLine("AuthenticationCertificatePasswordBase64String:");
            Console.WriteLine(AuthenticationCertificatePasswordBase64String);

            string AuthenticationCertificatePassword = DecryptFromBase64String(AuthenticationCertificatePasswordBase64String);
            Console.WriteLine("AuthenticationCertificatePassword:");
            Console.WriteLine(AuthenticationCertificatePassword);

            string CertificateAsBase64String = EncryptAsBase64String(encryptCert, spCert);
            Console.WriteLine("CertificateAsBase64String");
            Console.WriteLine(CertificateAsBase64String);

            byte[] rawdata = DecryptBytesFromBase64String(CertificateAsBase64String);
            Console.WriteLine("Raw data: " + PrintBytes(rawdata));

            string AuthenticationCertificateAsBase64String = Convert.ToBase64String(DecryptBytesFromBase64String(CertificateAsBase64String));
            Console.WriteLine("AuthenticationCertificateAsBase64String:");
            Console.WriteLine(AuthenticationCertificateAsBase64String);

            byte[] rawdata2 = Convert.FromBase64String(AuthenticationCertificateAsBase64String);
            Console.WriteLine("Raw data: " + PrintBytes(rawdata2));
            if (ByteArrayCompare(rawdata, rawdata2))
                Console.WriteLine("Raw data are same");

            X509Certificate2 certFromConfig = AuthenticationCertificate(AuthenticationCertificateAsBase64String, AuthenticationCertificatePassword);

            Console.WriteLine("Press enter to close...");
            Console.ReadLine();

        }

        public static byte[] DecryptBytesFromBase64String(string payloadBase64String, X509Certificate2 decryptingCert = null)
        {
            try
            {
                var env = new EnvelopedCms();
                env.Decode(Convert.FromBase64String(payloadBase64String));
                if (decryptingCert != null)
                {
                    env.Decrypt(new X509Certificate2Collection(decryptingCert));
                }
                else
                {
                    env.Decrypt();
                }
                return env.ContentInfo.Content;
            }
            catch (Exception e)
            {
                throw new CryptographicException("Failed to decrypt: " + payloadBase64String, e);
            }
        }

        public static string DecryptFromBase64String(string payloadBase64String, X509Certificate2 decryptingCert = null)
        {
            return Encoding.UTF8.GetString(DecryptBytesFromBase64String(payloadBase64String, decryptingCert));
        }

        public static string EncryptAsBase64String(X509Certificate2 cert, string payload)
        {
            return EncryptAsBase64String(cert, Encoding.UTF8.GetBytes(payload));
        }

        public static string EncryptAsBase64String(X509Certificate2 cert, byte[] payload)
        {
            var ci = new ContentInfo(payload);
            var env = new EnvelopedCms(ci);
            env.Encrypt(new CmsRecipient(cert));
            return Convert.ToBase64String(env.Encode());
        }

        public static string EncryptAsBase64String(X509Certificate2 encryptingCert, X509Certificate2 payload)
        {
            byte[] bytes = payload.Export(X509ContentType.Pfx);
            return EncryptAsBase64String(encryptingCert, bytes);
        }

        private static X509Certificate2 GetCertificateUsedForEncryption()
        {
            string certPath = "D:\\encryptcert.pfx";
            string certPassword = "P@ssword123";
            var cert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.Exportable);
            return cert;
        }

        private static X509Certificate2 GetCertificateForUse()
        {
            string certPath = "D:\\securecert.pfx";
            string certPassword = "Password1!";
            var cert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.Exportable);
            return cert;
        }

        public static X509Certificate2 AuthenticationCertificate(string AuthenticationCertificateAsBase64String, string AuthenticationCertificatePassword)
        {
            if (!string.IsNullOrEmpty(AuthenticationCertificateAsBase64String) &&
                AuthenticationCertificatePassword != null)
            {
                Console.WriteLine("AuthenticationCertificateAsBase64String: " + AuthenticationCertificateAsBase64String);
                Console.WriteLine("AuthenticationCertificatePassword: " + AuthenticationCertificatePassword);
                return new X509Certificate2(Convert.FromBase64String(AuthenticationCertificateAsBase64String),
                    AuthenticationCertificatePassword);
            }
            return null;
        }

        public static string PrintBytes(byte[] byteArray)
        {
            var sb = new StringBuilder("new byte[] { ");
            for (var i = 0; i < byteArray.Length; i++)
            {
                var b = byteArray[i];
                sb.Append(b);
                if (i < byteArray.Length - 1)
                {
                    sb.Append(", ");
                }
            }
            sb.Append(" }");
            return sb.ToString();
        }

        static bool ByteArrayCompare(byte[] a1, byte[] a2)
        {
            if (a1.Length != a2.Length)
                return false;

            for (int i = 0; i < a1.Length; i++)
                if (a1[i] != a2[i])
                    return false;

            return true;
        }

    }
}

1 个答案:

答案 0 :(得分:1)

您最初的问题是关于以string作为第一个参数的重载,但您的代码使用的是使用byte[]的重载。

简单的答案是,字符串1只是一个文件名,作为字节数组加载,然后调用另一个(它比那更细致,例如文件一个不像符号链路)。

以下类型(由我)知道:

  • PFX / PKCS#12,DER编码
  • X.509证书,DER编码
  • X.509证书,PEM + DER编码(-----BEGIN CERTIFICATE-----\n[etc]\n-----END CERTIFICATE-----
  • PKCS#7 ContentInfo(SignedData),BER编码(使用第一个签名者识别的嵌入式证书)
  • PKCS#7 ContentInfo(SignedData),PEM + BER编码(-----BEGIN PKCS7-----\n...)(使用第一个签名者识别的嵌入式证书)
  • Authenticode签名文件(.exe,.dll,.msi,.msp,...)(它使用第一个签名者的证书)

您是否传入密码与blob被识别为的文件格式无关。除非您的个人资料或临时目录位于SMB / CIFS共享上,否则Windows报告ERROR_BAD_PASSWORD表示它认为您的字节代表PFX,但无法使用输入密码作为密钥验证PFX MAC。我建议您检查密码变量是否包含嵌入式换行符或换行符(或空值);或领先或尾随空格。