在 Dart 中将 ECPrivateKey/ECPublicKey 转换为 PEM 字符串

Posted

技术标签:

【中文标题】在 Dart 中将 ECPrivateKey/ECPublicKey 转换为 PEM 字符串【英文标题】:Convert ECPrivateKey/ECPublicKey to PEM string in Dart 【发布时间】:2019-09-27 11:01:50 【问题描述】:

我有一个 ECPrivateKey/ECPublicKey,想将其转换为如下 PEM 字符串

公钥:

-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnd21ku0m+VZvM3tJAP3IIM3XXGla PM2zhRura+/qioJoUwDK7qLbuFzcmbHHx6ELnXFXgAjDbZgFyMdfcm1ugw== -----END PUBLIC KEY-----

私钥:

-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2sfmpsl894GDcNOl vzKW0gzf/b8XvQigr/rZGSjKydqhRANCAASd3bWS7Sb5Vm8ze0kA/cggzddcaVo8 zbOFG6tr7+qKgmhTAMruotu4XNyZscfHoQudcVeACMNtmAXIx19ybW6D -----END PRIVATE KEY-----

【问题讨论】:

您可以展示您尝试过的内容或您正在使用的加密库。预计您会进行一些初步研究,但目前没有显示。 【参考方案1】:

如果你喂

MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnd21ku0m+VZvM3tJAP3IIM3XXGla PM2zhRura+/qioJoUwDK7qLbuFzcmbHHx6ELnXFXgAjDbZgFyMdfcm1ugw==

进入像this 这样的ASN.1 解析器,您会发现它只是一些oid(包括曲线)和密钥的R/S 值的Base64/ASN.1 编码。该编码在 PKCS#8 规范中有所描述。

SEQUENCE (2 elem)   SEQUENCE (2 elem)
    OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
    OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve)
    BIT STRING (520 bit) 0000010010011101110111011011010110010010111011010010011011111001010101…

使用Dart ASN encoder/decoder package 首先解码上面的示例,以探索 ASN 组件的顺序和嵌套。然后反转该过程并使用库的编码器部分对其进行重新编码,并断言您将获得与开始时相同的 BER 编码。现在您可以对任何您喜欢的密钥进行编码。

【讨论】:

ECDSA signature 有 R & S 组件(最多 n 个); EC publickey 包含 if 未压缩的点(如这里)具有前缀 04 然后仿射 X 和 Y 坐标(对于素数曲线最多 p);请参阅 rfc5480 sec 2.2 和 X9.62 或(更便宜的)SEC1。对于 PKCS8 格式的私钥,请参阅 rfc5280 sec 4 和 rfc5915 或 SEC1。【参考方案2】:

查看 Dart Basic Utils 包。我通过使用 Pointycastle 和 ASN1 包完成了这项工作。

更新 pubspec.yaml 并将以下行添加到您的依赖项中。

dependencies:
  basic_utils: ^2.5.6

存储库:https://github.com/Ephenodrom/Dart-Basic-Utils

Pub.dev:https://pub.dev/packages/basic_utils

String encodeEcPublicKeyToPem(ECPublicKey publicKey);
String encodeEcPrivateKeyToPem(ECPrivateKey ecPrivateKey);

如果你不想使用包,这里是完整的代码:

static String encodeEcPublicKeyToPem(ECPublicKey publicKey) 
    ASN1ObjectIdentifier.registerFrequentNames();
    var outer = ASN1Sequence();
    var algorithm = ASN1Sequence();
    algorithm.add(ASN1ObjectIdentifier.fromName('ecPublicKey'));
    algorithm.add(ASN1ObjectIdentifier.fromName('prime256v1'));
    var subjectPublicKey = ASN1BitString(publicKey.Q.getEncoded(false));

    outer.add(algorithm);
    outer.add(subjectPublicKey);
    var dataBase64 = base64.encode(outer.encodedBytes);
    var chunks = StringUtils.chunk(dataBase64, 64);

    return '$BEGIN_EC_PUBLIC_KEY\n$chunks.join('\n')\n$END_EC_PUBLIC_KEY';
  

static String encodeEcPrivateKeyToPem(ECPrivateKey ecPrivateKey) 
    ASN1ObjectIdentifier.registerFrequentNames();
    var outer = ASN1Sequence();

    var version = ASN1Integer(BigInt.from(1));
    var privateKeyAsBytes = _bigIntToBytes(ecPrivateKey.d);
    var privateKey = ASN1OctetString(privateKeyAsBytes);
    var choice = ASN1Sequence(tag: 0xA0);

    choice
        .add(ASN1ObjectIdentifier.fromName(ecPrivateKey.parameters.domainName));

    var publicKey = ASN1Sequence(tag: 0xA1);

    var subjectPublicKey =
        ASN1BitString(ecPrivateKey.parameters.G.getEncoded(false));
    publicKey.add(subjectPublicKey);

    outer.add(version);
    outer.add(privateKey);
    outer.add(choice);
    outer.add(publicKey);
    var dataBase64 = base64.encode(outer.encodedBytes);
    var chunks = StringUtils.chunk(dataBase64, 64);

    return '$BEGIN_EC_PRIVATE_KEY\n$chunks.join('\n')\n$END_EC_PRIVATE_KEY';
  

【讨论】:

这在 base64.encode(outer.encodedBytes);在 publicKey 中,它说它是 null

以上是关于在 Dart 中将 ECPrivateKey/ECPublicKey 转换为 PEM 字符串的主要内容,如果未能解决你的问题,请参考以下文章

在 Dart 中将文件作为字符串流读取:将发出多少个事件?

在 Dart 中将异常从异步方法向上传递到同步方法

为啥文本元素居中以及如何在 Dart 中将其与右侧对齐

如何在Dart中将列表转换为地图

如何在 Dart/flutter 中将视频文件分割成小块?

在 Flutter(Dart)中将字符串解析为 DateTime [重复]