[英]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.