微软压缩天然气 |如何将 PEM 编码的 ECDSA 私钥导入 MS Key Storage Provider [英] Microsoft CNG | How to import PEM encoded ECDSA private key into MS Key Storage Provider

查看:13
本文介绍了微软压缩天然气 |如何将 PEM 编码的 ECDSA 私钥导入 MS Key Storage Provider的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道 MS CNG 私人有这种格式 -<代码>BCRYPT_ECCKEY_BLOBBYTE X[cbKey]//大端.BYTE Y[cbKey]//大端.BYTE d[cbKey]//大端.

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: '请求的操作不受支持.我不明白为什么它会给出这个例外?

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 Format ECDSA Key转为OpenSSL EC Key.

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# Get CngKey object from public key in text file 对公钥有一个简单的(如果 hacky)答案.私钥是不同的,但大多很简单.

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.将 base-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.680) 和 BER/DER (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();
}

这篇关于微软压缩天然气 |如何将 PEM 编码的 ECDSA 私钥导入 MS Key Storage Provider的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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