Microsoft CNG |如何将PEM编码的ECDSA私钥导入MS密钥存储提供程序 [英] Microsoft CNG | How to import PEM encoded ECDSA private key into MS Key Storage Provider

查看:86
本文介绍了Microsoft CNG |如何将PEM编码的ECDSA私钥导入MS密钥存储提供程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道MS CNG私有版具有这种格式- BCRYPT_ECCKEY_BLOB BYTE X[cbKey] // Big-endian. BYTE Y[cbKey] // Big-endian. BYTE d[cbKey] // Big-endian.

I know the MS CNG private have this format - BCRYPT_ECCKEY_BLOB BYTE X[cbKey] // Big-endian. BYTE Y[cbKey] // Big-endian. BYTE d[cbKey] // Big-endian.

因此尝试在关键字节以下导入-

Thus tried to import below key bytes -

byte[] ec256PrivKB =
{
//Magic + CBLength
0x45, 0x43, 0x53, 0x31, 0x20, 0x00, 0x00, 0x00,
//X
0xA7, 0xFB, 0xCD, 0x4D, 0x7E, 0x43, 0x6F, 0x22, 0xBD, 0x74, 0xFA, 0x1F, 0xD7, 0x10, 0xDB, 0x8C, 0xF8, 0x29, 0xC1, 0xEC, 0x5E, 0x15, 0x1E, 0xE2, 0x84, 0x56, 0x3E, 0x54, 0x6E, 0x1D, 0x5C, 0xF6, 
//Y
0x6B, 0x42, 0x21, 0xD1, 0x92, 0xEB, 0x69, 0x66, 0x56, 0xD6, 0xEC, 0x4D, 0x21, 0xB7, 0xDB, 0x3C, 0x94, 0x56, 0x8D, 0x87, 0xEB, 0x1C, 0x11, 0x0F, 0x03, 0x80, 0xF6, 0x10, 0x70, 0x73, 0x7D, 0x1D, 
//D
0x5E, 0xF0, 0x2A, 0x1B, 0x34, 0xE9, 0x2B, 0x96, 0xA4, 0xAE, 0x05, 0x1D, 0x33, 0x53, 0x36, 0x39, 0x7B, 0x1F, 0xF5, 0x24, 0xA4, 0xD6, 0xBD, 0x12, 0x07, 0x3F, 0x43, 0x30, 0x70, 0x32, 0x4E, 0x5D
};

现在可以致电

ECDsaCng eCDsa = new ECDsaCng( CngKey.Import(ec256PrivKB, CngKeyBlobFormat.EccPrivateBlob,
                    CngProvider.MicrosoftSoftwareKeyStorageProvider));

它给出System.Security.Cryptography.CryptographicException: 'The requested operation is not supported. 我不明白为什么会给这个例外?

It gives System.Security.Cryptography.CryptographicException: 'The requested operation is not supported. I don't understand why it is giving this exception ?

同样如何将base64编码的ecdsa私钥导入到MS密钥存储提供程序中,即假设我具有以下ec私钥-

Also how to import base64 encoded ecdsa private key into MS key storage provider i.e suppose i have below ec private key -

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICWeuFHssg5i2vJlyMHPUb+DJnylxfbkR8KJPXfYw5ikoAoGCCqGSM49
AwEHoUQDQgAE7A4wVMLQ+orOZYcFv6mLNBbAWfffPwTTw4iroyQDcytYWT+frzl3
RiFXqC1niHgduYtGBZIbwq/48ooyL9HbkA==
-----END EC PRIVATE KEY-----

现在如何将其导入CNG提供程序?

Now how do i import this into CNG provider ?

编辑-也有任何方法可以使该过程相互转化,即 我知道如何从OpenSSL(PEM FORMAT)转换为MS Format(RAW format) 但是如何做相反的意思 如何在PEM中将MS格式ECDSA密钥转换为OpenSSL EC密钥.

Edit - Also is there any way to reciprocate this process i.e I know how to convert from OpenSSL(PEM FORMAT) to MS Format(RAW format) but how to do the reverse meaning how to convert MS Format ECDSA Key to OpenSSL EC Key in PEM.

推荐答案

您的密钥Blob以BCRYPT_ECDSA_ PUBLIC _P256_MAGIC开头,但是您想要BCRYPT_ECDSA_ PRIVATE _P256_MAGIC(更改0x31到0x32).

Your key blob starts with BCRYPT_ECDSA_PUBLIC_P256_MAGIC, but you want BCRYPT_ECDSA_PRIVATE_P256_MAGIC (change the 0x31 to 0x32).

由此,我们可以假定您知道如何进行转换,但是由于标题要求更一般地进行转换,因此我将继续. 从文本文件中的公共密钥中获取C#CngKey对象对公共密钥有一个简单明了的答案(如果很棘手).私钥有所不同,但大多都很简单.

From that we could assume that you know how to do the conversion, but since the title asks how to do it more generally I'll continue. C# Get CngKey object from public key in text file has a straightforward (if hacky) answer to public keys. Private keys are different, but mostly straightforward.

如果我们从问题中取出PEM密钥,则可以删除"PEM装甲"以获得base-64 blob.将基数为64的blob转换为十六进制,我们得到

If we take the PEM key from the question we can remove the "PEM armor" to get a base-64 blob. Turning that base-64 blob into hexadecimal we get

30 77 02 01 01 04 20 25 9E B8 51 EC B2 0E 62 DA 
F2 65 C8 C1 CF 51 BF 83 26 7C A5 C5 F6 E4 47 C2 
89 3D 77 D8 C3 98 A4 A0 0A 06 08 2A 86 48 CE 3D 
03 01 07 A1 44 03 42 00 04 EC 0E 30 54 C2 D0 FA 
8A CE 65 87 05 BF A9 8B 34 16 C0 59 F7 DF 3F 04 
D3 C3 88 AB A3 24 03 73 2B 58 59 3F 9F AF 39 77 
46 21 57 A8 2D 67 88 78 1D B9 8B 46 05 92 1B C2 
AF F8 F2 8A 32 2F D1 DB 90

如果我们随后打开 https://www.secg.org/sec1-v2.pdf 我们在C.4节中看到了

If we then open https://www.secg.org/sec1-v2.pdf section C.4 we see

ECPrivateKey ::= SEQUENCE {
  version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  privateKey OCTET STRING,
  parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
  publicKey [1] BIT STRING OPTIONAL
}

通过ASN.1( ITU-T X.690 )规范十六进制转储和结构:

Via the ASN.1 (ITU-T X.680) and BER/DER (ITU-T X.690) specifications we can blend that hex dump and that structure:

// (constructed) SEQUENCE, 119 content bytes
30 77
   // INTEGER, 1 content byte, value 0x01.
   02 01 01
   // OCTET STRING (byte[]), 32 bytes, value 25 9E ... 98 A4
   04 20
      25 9E B8 51 EC B2 0E 62 DA F2 65 C8 C1 CF 51 BF 
      83 26 7C A5 C5 F6 E4 47 C2 89 3D 77 D8 C3 98 A4
   // (constructed) CONTEXT-SPECIFIC 0, 10 content bytes
   A0 0A
      // OBJECT IDENTIFIER, 8 content bytes, 1.2.840.10045.3.1.7
      06 08 2A 86 48 CE 3D 03 01 07
   // (constructed) CONTEXT-SPECIFIC 1, 68 content bytes
   A1 44
      // BIT STRING, 66 content bytes, 0 unused bits, value 04 EC .. DB 90
      03 42
         00
         04 EC 0E 30 54 C2 D0 FA 8A CE 65 87 05 BF A9 8B 
         34 16 C0 59 F7 DF 3F 04 D3 C3 88 AB A3 24 03 73 
         2B 58 59 3F 9F AF 39 77 46 21 57 A8 2D 67 88 78 
         1D B9 8B 46 05 92 1B C2 AF F8 F2 8A 32 2F D1 DB 
         90

进行搜索1.2.840.10045.3.1.7 表示它(毫无疑问)是secp256r1/NIST P-256椭圆曲线.

Doing a search for 1.2.840.10045.3.1.7 indicates that it is (unsurprisingly) the secp256r1 / NIST P-256 elliptic curve.

BIT STRING的内容以04开头,表示它是未压缩的EC点,剩下的前半部分是X坐标,后半部分是Y坐标.很好,这与私钥的OCTET STRING的宽度一致,这意味着该结构是有效的.

The contents of the BIT STRING start with 04, which indicates that it is an uncompressed EC point, the first half of what remains is the X coordinate, and the second half is the Y coordinate. Nicely, this lines up with the width of the OCTET STRING for the private key, meaning the structure is valid.

您会注意到,ASN.1结构表示,曲线标识符和公钥在技术上都是可选的.在实践中,将它们写下来是很好的,因为我们要依靠它.

You'll note that the ASN.1 structure said that the curve identifier and the public key were technically both optional. In practice they are written down, which is good, since we're going to count on it.

// structure opening up to the private key (D) value.
private static readonly byte[] s_secp256R1Prefix =
    { 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20 };

// After D through the 0x04 identifying the public key is uncompressed
private static readonly byte[] s_secp256R1Infix =
{
    0xA0, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE,
    0x3D, 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42,
    0x00, 0x04
};

private static readonly byte[] s_secp256R1PrivateCngPrefix =
    { 0x45, 0x43, 0x53, 0x32, 0x20, 0x00, 0x00, 0x00 };

private static CngKey DecodeP256ECPrivateKeyBase64(string base64)
{
    byte[] derBlob = Convert.FromBase64String(base64);

    if (derBlob.Length == 121 &&
        derBlob.Take(s_secp256R1Prefix.Length).SequenceEqual(s_secp256R1Prefix) &&
        derBlob.Skip(0x20 + s_secp256R1Prefix.Length).Take(s_secp256R1Infix.Length).
            SequenceEqual(s_secp256R1Infix))
    {
        byte[] cngBlob = new byte[2 * sizeof(uint) + 3 * 0x20];
        int offset = 0;

        // Header (BCRYPT_ECDSA_PRIVATE_P256_MAGIC and 0x00000020)
        Buffer.BlockCopy(
            s_secp256R1PrivateCngPrefix,
            0,
            cngBlob,
            offset,
            s_secp256R1PrivateCngPrefix.Length);

        offset += s_secp256R1PrivateCngPrefix.Length;

        // X and Y
        Buffer.BlockCopy(
            derBlob,
            s_secp256R1Prefix.Length + 0x20 + s_secp256R1Infix.Length,
            cngBlob,
            offset,
            2 * 0x20);

        offset += 2 * 0x20;

        Buffer.BlockCopy(
            derBlob,
            s_secp256R1Prefix.Length,
            cngBlob,
            offset,
            0x20);

        offset += 0x20;
        Debug.Assert(offset == cngBlob.Length);

        return CngKey.Import(cngBlob, CngKeyBlobFormat.EccPrivateBlob);
    }

    throw new InvalidOperationException();
}

这篇关于Microsoft CNG |如何将PEM编码的ECDSA私钥导入MS密钥存储提供程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆