如何将由 openssl 创建的 44 字节 x25519 public 密钥传递给需要 32 字节密钥长度的 CryptoKit
How do I pass a 44 Bytes x25519 public key created by openssl to CryptoKit which requires a key length of 32 Bytes
假设我使用 openssl 创建一个 x25519 密钥对,它将输出一个 64 字节的私钥和相应的 44 字节的 Base64 编码 public 密钥,看起来像
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=
-----END PUBLIC KEY-----
Swift CryptoKit 只接受每个 32 字节,私有和 public 密钥初始化。
如果我没理解错的话,64 字节的私钥是种子,其中前 32 字节是实际的私钥。
仍然,对 public 键使用相同的原理是行不通的(其实并不奇怪)
现在的问题是:如何将 public 密钥转换为 Swift CryptoKit 所需的 32 字节?
这是使用 base64 解码的前 32 个字节的非功能示例 public 密钥
let base64PublicKey = Data(base64Encoded: "MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=")!.dropLast(12)
let publicKey = try! Curve25519.KeyAgreement.PublicKey(rawRepresentation: rawPublicKey)
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----
per rfc7468 is a PKCS8-unencrypted PrivateKeyInfo which is encoded in ASN.1 DER 并包含有关算法的数据(一般情况下但不是此处的参数)以及实际密钥。 运行 这变成 openssl asn1parse -i
(自动取消 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-----
similarly is the SubjectPublicKeyInfo 由 X.509 和 PKIX 定义的结构,它同样是 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 值的第一个八位位组用于 unused/pad 位数,此处为 00,因此真正的公钥值是偏移量 9+2+1=12 处的 33-1=32 个八位位组,或者最后 32 个字节。
Ed25519 对私钥进行哈希处理,生成一个有时称为种子的 32 字节标量和一个确定公钥的 32 字节值。此种子可以与私钥一起存储,以提高签名效率,但 OpenSSL 不会为 Ed25519 执行此操作,并且它根本不适用于 X25519。
假设我使用 openssl 创建一个 x25519 密钥对,它将输出一个 64 字节的私钥和相应的 44 字节的 Base64 编码 public 密钥,看起来像
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=
-----END PUBLIC KEY-----
Swift CryptoKit 只接受每个 32 字节,私有和 public 密钥初始化。
如果我没理解错的话,64 字节的私钥是种子,其中前 32 字节是实际的私钥。
仍然,对 public 键使用相同的原理是行不通的(其实并不奇怪)
现在的问题是:如何将 public 密钥转换为 Swift CryptoKit 所需的 32 字节?
这是使用 base64 解码的前 32 个字节的非功能示例 public 密钥
let base64PublicKey = Data(base64Encoded: "MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=")!.dropLast(12)
let publicKey = try! Curve25519.KeyAgreement.PublicKey(rawRepresentation: rawPublicKey)
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----
per rfc7468 is a PKCS8-unencrypted PrivateKeyInfo which is encoded in ASN.1 DER 并包含有关算法的数据(一般情况下但不是此处的参数)以及实际密钥。 运行 这变成 openssl asn1parse -i
(自动取消 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-----
similarly is the SubjectPublicKeyInfo 由 X.509 和 PKIX 定义的结构,它同样是 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 值的第一个八位位组用于 unused/pad 位数,此处为 00,因此真正的公钥值是偏移量 9+2+1=12 处的 33-1=32 个八位位组,或者最后 32 个字节。
Ed25519 对私钥进行哈希处理,生成一个有时称为种子的 32 字节标量和一个确定公钥的 32 字节值。此种子可以与私钥一起存储,以提高签名效率,但 OpenSSL 不会为 Ed25519 执行此操作,并且它根本不适用于 X25519。