1

假设我使用 openssl 创建了一个 x25519 密钥对,它将输出一个 64 字节的私钥和相应的 44 字节 Base64 编码的公钥,看起来像

-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----


-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=
-----END PUBLIC KEY-----

Swift CryptoKit 只接受 32 字节的私钥和公钥初始化。

如果我理解正确的话,64 字节的私钥是种子,前 32 字节是实际的私钥。

尽管如此,对公钥使用相同的原则还是行不通(这并不奇怪)

现在的问题是:如何将公钥转换为 Swift CryptoKit 所需的 32 字节?

这是使用 base64 解码公钥的前 32 个字节的非功能示例

let base64PublicKey = Data(base64Encoded: "MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=")!.dropLast(12)

let publicKey = try! Curve25519.KeyAgreement.PublicKey(rawRepresentation: rawPublicKey) 
4

1 回答 1

4
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----

per rfc7468是一个 PKCS8 未加密的PrivateKeyInfo ,它在ASN.1 DER中编码,包含有关算法的数据(通常是参数,但不是这里的参数)以及实际密钥。运行它openssl asn1parse -i(它会自动 de-base64)给出

    0:d=0  hl=2 l=  46 cons: SEQUENCE
    2:d=1  hl=2 l=   1 prim:  INTEGER           :00
    5:d=1  hl=2 l=   5 cons:  SEQUENCE
    7:d=2  hl=2 l=   3 prim:   OBJECT            :X25519
   12:d=1  hl=2 l=  34 prim:  OCTET STRING      [HEX DUMP]:0420C045F12EF351CA386D1ACC888BB24DC49853FAC056536D13C48C616A6151AB70

特定于算法的私钥是 OCTETSTRING,其值为偏移量 12+2 和长度 34,但实际上包含嵌套的 OCTETSTRING 编码,其前两个八位字节是 04=tag 和 20=length,因此真正的私钥在偏移量 16 处,长度为32 - 或者更简单地说是最后 32 个字节。

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=
-----END PUBLIC KEY-----

同样是由 X.509 和 PKIX 定义的SubjectPublicKeyInfo结构,它同样是 DER,除了密钥之外还包含数据。解析它(用-dump)给出:

    0:d=0  hl=2 l=  42 cons: SEQUENCE
    2:d=1  hl=2 l=   5 cons:  SEQUENCE
    4:d=2  hl=2 l=   3 prim:   OBJECT            :X25519
    9:d=1  hl=2 l=  33 prim:  BIT STRING
      0000 - 00 13 47 a2 88 fd 0f 2a-3c bd 01 53 3f d3 3d 99   ..G....*<..S?.=.
      0010 - 21 99 f8 e7 75 92 24 d7-a6 ad 0e 7c 1c 05 c3 69   !...u.$....|...i
      0020 - 7d

BITSTRING 值的第一个八位字节用于未使用/填充位的数量,此处为 00,因此真正的公钥值是偏移量 9+2+1=12 处的 33-1=32 个八位字节,或最后 32 个字节.


Ed25519 对私钥进行哈希处理,以生成一个 32 字节的标量(有时称为种子)和一个 32 字节的值,该值决定了公钥。该种子可以与私钥一起存储以提高签名效率,但 OpenSSL 不会对 Ed25519 执行此操作,并且它根本不适用于 X25519。

于 2020-02-20T09:59:08.887 回答