将公钥从其他地方导入CngKey?

Jos*_*del 16 javascript c# cryptography bouncycastle cng

我正在寻找一种跨平台的方式来共享ECDSA签名的公钥.从CngKey和标准.NET加密库的性能角度来看,我有一个很棒的事情,但后来我无法弄清楚33(或65)字节的公钥(使用secp256r1/P256)是如何变成104字节的由MS .. Ergo,我无法支持跨平台签名和验证..

我现在正在使用BouncyCastle,但神圣的handgranade它很慢!

因此,寻找以下要求的建议:

  1. 跨平台/语言(服务器是.NET,但这是通过JSON/Web.API接口提供的)
    • JavaScript,Ruby,Python,C++等.
  2. 在服务器上并不疯狂
  3. 不那么痛苦的慢人们不能在客户端上使用它.

客户端必须能够对消息进行签名,服务器必须能够使用在注册到服务时交换的公钥来验证签名.

无论如何,想法会很棒...谢谢

Jos*_*del 29

所以我想出了在ECCPublicKeyBlob和ECCPrivateKeyBlob中导出的CngKey的格式.这应该允许其他人在其他密钥格式和CngKey之间进行互操作以进行Elliptcal Curve签名等.

ECCPrivateKeyBlob格式化(对于P256)如下

  • [密钥类型(4字节)] [密钥长度(4字节)] [公共密钥(64字节)] [私钥(32字节)]
  • HEX中的KEY TYPE为45-43-53-32
  • HEX的关键长度是20-00-00-00
  • PUBLIC KEY是未压缩格式减去前导字节(在其他库中始终为04表示未压缩密钥)

ECCPublicKeyBlob格式化(对于P256)如下

  • [密钥类型(4字节)] [密钥长度(4字节)] [公共密钥(64字节)]
  • HEX中的KEY TYPE为45-43-53-31
  • HEX的关键长度是20-00-00-00
  • PUBLIC KEY是未压缩格式减去前导字节(在其他库中始终为04表示未压缩密钥)

因此,如果使用其他语言的Hex中未压缩的公钥,则可以修剪第一个字节,将这8个字节添加到前面并使用

CngKey.Import(key,CngKeyBlobFormat.EccPrivateBlob);
Run Code Online (Sandbox Code Playgroud)

注意:密钥blob格式由Microsoft记录.

KEY TYPE和KEY LENGTH在BCRYPT_ECCKEY_BLOB结构中定义为:

{ ulong Magic; ulong cbKey; }
Run Code Online (Sandbox Code Playgroud)

ECC公钥存储格式:

BCRYPT_ECCKEY_BLOB
BYTE X[cbKey] // Big-endian.
BYTE Y[cbKey] // Big-endian.
Run Code Online (Sandbox Code Playgroud)

ECC私钥内存格式:

BCRYPT_ECCKEY_BLOB
BYTE X[cbKey] // Big-endian.
BYTE Y[cbKey] // Big-endian.
BYTE d[cbKey] // Big-endian.
Run Code Online (Sandbox Code Playgroud)

.NET中提供的MAGIC值在Microsoft的官方GitHub dotnet/corefx BCrypt/Interop.Blobs中.

internal enum KeyBlobMagicNumber : int
{
    BCRYPT_ECDH_PUBLIC_P256_MAGIC = 0x314B4345,
    BCRYPT_ECDH_PRIVATE_P256_MAGIC = 0x324B4345,
    BCRYPT_ECDH_PUBLIC_P384_MAGIC = 0x334B4345,
    BCRYPT_ECDH_PRIVATE_P384_MAGIC = 0x344B4345,
    BCRYPT_ECDH_PUBLIC_P521_MAGIC = 0x354B4345,
    BCRYPT_ECDH_PRIVATE_P521_MAGIC = 0x364B4345,
    BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345,
    BCRYPT_ECDSA_PRIVATE_P256_MAGIC = 0x32534345,
    BCRYPT_ECDSA_PUBLIC_P384_MAGIC = 0x33534345,
    BCRYPT_ECDSA_PRIVATE_P384_MAGIC = 0x34534345
    BCRYPT_ECDSA_PUBLIC_P521_MAGIC = 0x35534345,
    BCRYPT_ECDSA_PRIVATE_P521_MAGIC = 0x36534345,
    ...
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • https://msdn.microsoft.com/en-us/library/windows/desktop/aa375520(v=vs.85).aspx.实际的魔术值来自bcrypt.h,例如#define BCRYPT_ECDSA_PRIVATE_P256_MAGIC 0x32534345L (2认同)
  • 所以.许多.挖掘.找到这个答案.谢谢!我希望它可以为其他人提供与我一样多的价值. (2认同)

and*_*eas 5

感谢您,我能够使用以下代码从证书导入 ECDSA_P256 公钥:

    private static CngKey ImportCngKeyFromCertificate(X509Certificate2 cert)
    {
        var keyType = new byte[] {0x45, 0x43, 0x53, 0x31};
        var keyLength = new byte[] {0x20, 0x00, 0x00, 0x00};

        var key = cert.PublicKey.EncodedKeyValue.RawData.Skip(1);

        var keyImport = keyType.Concat(keyLength).Concat(key).ToArray();

        var cngKey = CngKey.Import(keyImport, CngKeyBlobFormat.EccPublicBlob);
        return cngKey;
    }
Run Code Online (Sandbox Code Playgroud)

65 字节的密钥(仅公钥)以0x04需要删除的开头。然后添加您描述的标题。

然后我能够验证这样的签名:

var crypto = ECDsaCng(cngKey);
var verify = crypto.VerifyHash(hash, sig);
Run Code Online (Sandbox Code Playgroud)