简体   繁体   English

使用RSA AES提供程序生成自签名1024位X509Certificate2时出现问题

[英]Problems generating a self-signed 1024-bit X509Certificate2 using the RSA AES provider

I am trying to generate an X509Certificate2 object using the Microsoft AES Cryptographic Provider : 我正在尝试使用Microsoft AES加密提供程序生成X509Certificate2对象:

CALG_AES_256 (0x00006610) 256 bit AES. CALG_AES_256(0x00006610)256位AES。 This algorithm is supported by the Microsoft AES Cryptographic Provider. Microsoft AES加密提供程序支持此算法。

My problem is that my call to CryptGenKey(providerContext, 0x6610, 0x4000001, out cryptKey) fails with the following error: 我的问题是我对CryptGenKey(providerContext, 0x6610, 0x4000001, out cryptKey)失败,出现以下错误:

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll mscorlib.dll中发生未处理的“System.Runtime.InteropServices.COMException”类型异常

Additional information: Invalid flags specified. 附加信息:指定了无效标志。 (Exception from HRESULT: 0x80090009) (HRESULT异常:0x80090009)

The flags I am using are (1024 << 16) | 1) 我使用的标志是(1024 << 16) | 1) (1024 << 16) | 1) . (1024 << 16) | 1) Unless I am mistaken, should this not produce a 1024-bit exportable key according to the documentation on MSDN ? 除非我弄错了, 根据MSDN上的文档 ,这不应该产生1024位可导出密钥吗? What is the problem with my approach here? 我的方法有什么问题?

My code is as follows: 我的代码如下:

using System;
using System.Security;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;

namespace WebSockets
{
    public struct SystemTime
    {
        public short Year;
        public short Month;
        public short DayOfWeek;
        public short Day;
        public short Hour;
        public short Minute;
        public short Second;
        public short Milliseconds;
    }

    public static class MarshalHelper
    {
        public static void CheckReturnValue(bool nativeCallSucceeded)
        {
            if (!nativeCallSucceeded)
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }
    }

    public static class DateTimeExtensions
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FileTimeToSystemTime(ref long fileTime, out SystemTime systemTime);

        public static SystemTime ToSystemTime(this DateTime dateTime)
        {
            long fileTime = dateTime.ToFileTime();
            SystemTime systemTime;
            MarshalHelper.CheckReturnValue(FileTimeToSystemTime(ref fileTime, out systemTime));
            return systemTime;
        }
    }

    class X509Certificate2Helper
    {

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern bool CryptAcquireContextW(out IntPtr providerContext, string container, string provider, uint providerType, uint flags);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool CryptReleaseContext(IntPtr providerContext, int flags);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool CryptGenKey(IntPtr providerContext, int algorithmId, int flags, out IntPtr cryptKeyHandle);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool CryptDestroyKey(IntPtr cryptKeyHandle);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern bool CertStrToNameW(int certificateEncodingType, IntPtr x500, int strType, IntPtr reserved, byte[] encoded, ref int encodedLength, out IntPtr errorString);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern IntPtr CertCreateSelfSignCertificate(IntPtr providerHandle, ref CryptoApiBlob subjectIssuerBlob, int flags, ref CryptKeyProviderInformation keyProviderInformation, IntPtr signatureAlgorithm, ref SystemTime startTime, ref SystemTime endTime, IntPtr extensions);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern bool CertFreeCertificateContext(IntPtr certificateContext);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern bool CertSetCertificateContextProperty(IntPtr certificateContext, int propertyId, int flags, ref CryptKeyProviderInformation data);

        public static X509Certificate2 GenerateSelfSignedCertificate(String name = "", DateTime? startTime = null, DateTime? endTime = null)
        {
            if (startTime == null || (DateTime)startTime < DateTime.FromFileTimeUtc(0))
                startTime = DateTime.FromFileTimeUtc(0);
            var startSystemTime = ((DateTime)startTime).ToSystemTime();
            if (endTime == null)
                endTime = DateTime.MaxValue;
            var endSystemTime = ((DateTime)endTime).ToSystemTime();
            string containerName = Guid.NewGuid().ToString();
            GCHandle dataHandle = new GCHandle();
            IntPtr providerContext = IntPtr.Zero;
            IntPtr cryptKey = IntPtr.Zero;
            IntPtr certificateContext = IntPtr.Zero;
            IntPtr algorithmPointer = IntPtr.Zero;
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                MarshalHelper.CheckReturnValue(CryptAcquireContextW(out providerContext, containerName, null, 0x18, 0x8));
                MarshalHelper.CheckReturnValue(CryptGenKey(providerContext, 0x6610, 0x4000001, out cryptKey));
                IntPtr errorStringPtr;
                int nameDataLength = 0;
                byte[] nameData;
                dataHandle = GCHandle.Alloc(name, GCHandleType.Pinned);
                if (!CertStrToNameW(0x10001, dataHandle.AddrOfPinnedObject(), 3, IntPtr.Zero, null, ref nameDataLength, out errorStringPtr))
                {
                    string error = Marshal.PtrToStringUni(errorStringPtr);
                    throw new ArgumentException(error);
                }
                nameData = new byte[nameDataLength];
                if (!CertStrToNameW(0x10001, dataHandle.AddrOfPinnedObject(), 3, IntPtr.Zero, nameData, ref nameDataLength, out errorStringPtr))
                {
                    string error = Marshal.PtrToStringUni(errorStringPtr);
                    throw new ArgumentException(error);
                }
                dataHandle.Free();
                dataHandle = GCHandle.Alloc(nameData, GCHandleType.Pinned);
                CryptoApiBlob nameBlob = new CryptoApiBlob { cbData = (uint)nameData.Length, pbData = dataHandle.AddrOfPinnedObject() };
                dataHandle.Free();
                CryptKeyProviderInformation keyProvider = new CryptKeyProviderInformation { pwszContainerName = containerName, dwProvType = 1, dwKeySpec = 1 };
                CryptAlgorithmIdentifier algorithm = new CryptAlgorithmIdentifier { pszObjId = "1.2.840.113549.1.1.13", Parameters = new CryptoApiBlob() };
                algorithmPointer = Marshal.AllocHGlobal(Marshal.SizeOf(algorithm));
                Marshal.StructureToPtr(algorithm, algorithmPointer, false);
                certificateContext = CertCreateSelfSignCertificate(providerContext, ref nameBlob, 0, ref keyProvider, algorithmPointer, ref startSystemTime, ref endSystemTime, IntPtr.Zero);
                MarshalHelper.CheckReturnValue(certificateContext != IntPtr.Zero);
                return new X509Certificate2(certificateContext);
            }
            finally
            {
                if (dataHandle.IsAllocated)
                    dataHandle.Free();
                if (certificateContext != IntPtr.Zero)
                    CertFreeCertificateContext(certificateContext);
                if (cryptKey != IntPtr.Zero)
                    CryptDestroyKey(cryptKey);
                if (providerContext != IntPtr.Zero)
                    CryptReleaseContext(providerContext, 0);
                if (algorithmPointer != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(algorithmPointer, typeof(CryptAlgorithmIdentifier));
                    Marshal.FreeHGlobal(algorithmPointer);
                }
            }
        }

        struct CryptoApiBlob
        {
            public uint cbData;
            public IntPtr pbData;
        }

        struct CryptAlgorithmIdentifier {
            [MarshalAs(UnmanagedType.LPStr)]
            public String pszObjId;
            public CryptoApiBlob Parameters;
        }

        struct CryptKeyProviderInformation
        {
            [MarshalAs(UnmanagedType.LPWStr)]
            public String pwszContainerName;
            [MarshalAs(UnmanagedType.LPWStr)]
            public String pwszProvName;
            public uint dwProvType;
            public uint dwFlags;
            public uint cProvParam;
            public IntPtr rgProvParam;
            public uint dwKeySpec;
        }
    }
}

To call it, you may use: X509Certificate2Helper.GenerateSelfSignedCertificate("CN = Example"); 要调用它,您可以使用: X509Certificate2Helper.GenerateSelfSignedCertificate("CN = Example"); .

Update : 更新

If I use 0x1 for the flags: 如果我使用0x1作为标志:

CryptAcquireContextW(out providerContext, containerName, "Microsoft Enhanced RSA and AES Cryptographic Provider", 0x18, 0x8);
CryptGenKey(providerContext, 0x6610, 0x1, out cryptKey);

It gets past CryptGenKey , but then fails on CertCreateSelfSignCertificate with: 它越过CryptGenKey ,但随后在CertCreateSelfSignCertificate上失败:

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll mscorlib.dll中发生未处理的“System.Runtime.InteropServices.COMException”类型异常

Additional information: Key does not exist. 附加信息:密钥不存在。 (Exception from HRESULT: 0x8009000D) (HRESULT异常:0x8009000D)

Must this key-set be passed in differently? 这个键集必须以不同方式传递吗? What is wrong with the way I have created it above? 我在上面创建它的方式有什么问题?

The problem is with CryptGenKey function call. 问题出在CryptGenKey函数调用上。 In the Algid parameter, you should pass either 0x1 (for RSA key exchange) or 0x2 (RSA digital signature). Algid参数中,您应该传递0x1(用于RSA密钥交换)或0x2(RSA数字签名)。 You don't need other values. 您不需要其他值。 And key length value should be 0x4000001 (with exportable key). 密钥长度值应为0x4000001(带可导出密钥)。 Also, I noticed that you pass incorrect provider type when you instantiate CryptKeyProviderInformation object. 另外,我注意到在实例化CryptKeyProviderInformation对象时传递了错误的提供程序类型。 Replace this line: 替换此行:

CryptKeyProviderInformation keyProvider = new CryptKeyProviderInformation {
    pwszContainerName = containerName,
    dwProvType = 1,
    dwKeySpec = 1
};

with this line: 用这一行:

CryptKeyProviderInformation keyProvider = new CryptKeyProviderInformation {
    pwszContainerName = containerName,
    dwProvType = 0x18,
    dwKeySpec = 1
};

Use this formula 使用此公式

(keySize * 65536) | 1;

For a 2048bit key it is 0x08000001. 对于2048位密钥,它是0x08000001。 According to documentation of CryptGenKey method you can use RSA1024BIT_KEY to generate 1024bit key. 根据CryptGenKey方法的文档,您可以使用RSA1024BIT_KEY生成1024位密钥。 I've tried looking for the define and found this (although it was on Adobe site :) ) 我已经尝试寻找定义并找到了这个 (虽然它是在Adobe网站上:))

#define RSA1024BIT_KEY                   0x04000000 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 生成带有私钥的自签名X509Certificate2证书 - Generating a self-signed X509Certificate2 certificate with its private key 如何以编程方式创建有效的自签名X509Certificate2,而不是从.NET Core中的文件加载 - How to create a valid, self-signed X509Certificate2 programmatically, not loading from file in .NET Core 将openssl创建的自签名证书导入X509Certificate2(Mono):可以加密,无法解密 - Importing an openssl-created self-signed cert into a X509Certificate2 (Mono): Can encrypt, can't decrypt 使用X509certificate2进行RSA加密和解密 - RSA Encryption and Decryption with X509certificate2 使用C#生成X509Certificate2对象 - Generating X509Certificate2 object using C# 为什么自签名 PFX X509Certificate2 私钥会引发 NotSupportedException? - Why does self signed PFX X509Certificate2 private key raise a NotSupportedException? 从自签名证书生成X.509 SubjectPublicKeyInfo / OpenSSL PEM公钥 - Generate X.509 SubjectPublicKeyInfo/OpenSSL PEM public key from self-signed certificate 更改IdentityServer.v3中的嵌入式自签名X.509证书(idsrv3test.pfx) - Changing the embedded self-signed X.509 Certificate (idsrv3test.pfx) in IdentityServer.v3 X509Certificate2的RemoteCertificateValidationCallback - RemoteCertificateValidationCallback with X509Certificate2 X509Certificate2到EccKey - X509Certificate2 to EccKey
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM