如何在 Delphi 中将 JSON Web Key 转换为 PEM 格式?

Posted

技术标签:

【中文标题】如何在 Delphi 中将 JSON Web Key 转换为 PEM 格式?【英文标题】:How to convert JSON Web Key to PEM format in Delphi? 【发布时间】:2021-06-05 18:57:17 【问题描述】:

Earlier I found out 在使用JWT Library 中的签名之前,我需要将 JSON Web Key (JWK) 转换为 PEM 格式。

JWK 格式的原始私钥:


  "kty": "EC",
  "d": "Rwyv99W3GnfjYbI0X-b5Umhvh88oRCKQkPxiwCPVGgg",
  "crv": "P-256",
  "x": "sDbcYT8HzBk1tUl849ZHrhpIn8ZV7HfD1DwYdsP1ip0",
  "y": "EWodfKWQ6oE0ppyi7tRO_61BgAQsZyDjDGj9kLZiUts"

需要获取PEM格式,比如这里:

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIEcMr/fVtxp342GyNF/m+VJob4fPKEQikJD8YsAj1RoIoAoGCCqGSM49
AwEHoUQDQgAEsDbcYT8HzBk1tUl849ZHrhpIn8ZV7HfD1DwYdsP1ip0Rah18pZDq
gTSmnKLu1E7/rUGABCxnIOMMaP2QtmJS2w==
-----END EC PRIVATE KEY-----

有一个online converter 可以满足我的需要。是否可以在 Delphi 中进行相同的转换?

【问题讨论】:

【参考方案1】:

找到了解决方案。阅读详情here。

简化示例:

uses
  JSON,
  EncdDecd;

function Base64urlToBase64(Base64urlStr: String): String;
begin
  Result := StringReplace(Base64urlStr,'_','/', [rfReplaceAll]);
  Result := StringReplace(Result,'-','+', [rfReplaceAll]);
end;

function JwkToPem(JWK: TJSONObject): String;
var
  BinKey: TBytes;
begin
  BinKey :=

  [$30] + // ASN.1
  [$77] + // Length of all following bytes (119 bytes)

  [$02] + // Type (integer)
  [$01] + // Length of integer (1 byte)
  [$01] + // Value of integer (1)

  [$04] + // Type (octet string)
  [$20] + // Length of string (32 bytes)
  DecodeBase64(Base64urlToBase64(JWK.Get('d').JsonValue.Value)) +  // Private Key

  [$A0] + // Tag 0
  [$0A] + // Length of tag (10 bytes)
  [$06] + // Type (Object ID)
  [$08] + // Length of the Object ID (8 bytes)
  [$2A, $86, $48, $CE, $3D, $03, $01, $07] + // - The object ID of the curve prime256v1

  [$A1] + // Tag 1
  [$44] + // Length of tag (68 bytes)
  [$03] + // Type – Bit string
  [$42] + // Length of the bit string (66 bytes)
  [$00] + // ???
  [$04] + // Uncompressed Public Key
  DecodeBase64(Base64urlToBase64(JWK.Get('x').JsonValue.Value))+ // Public Key X coord
  DecodeBase64(Base64urlToBase64(JWK.Get('y').JsonValue.Value)); // Public Key Y coord

  Result :=
  '-----BEGIN EC PRIVATE KEY-----'+#13#10+
  EncodeBase64(Pointer(BinKey), Length(BinKey))+#13#10+
  '-----END EC PRIVATE KEY-----';
end;

【讨论】:

【参考方案2】:

您将在低级 OpenSSL 中拥有所需的一切。

它的 API 有点神秘,但您可以使用 EC_POINT*() 函数来完成它。

检查我们做了什么 mormot.crypt.openssl 使用低级 ECC 私钥并将它们与 OpenSSL 集成:

ecdsa_sign_osl 接受原始私钥并将其转换为 OpenSSL PEC_KEY; OpenSslSaveKeys 将此密钥保存为 PEM。

您只需导出"d": "Rwyv99W3GnfjYbI0X-b5Umhvh88oRCKQkPxiwCPVGgg" 参数。它似乎与TEccPrivateKey 中用作ecdsa_sign_osl() 中的输入参数的布局相同。

您还可以在mormot.crypt.ecc256r1.pas 中找到一些纯帕斯卡代码计算 ECC prime256v1。

【讨论】:

@Bouchez TEccPrivateKey 类型的大小为 32 字节。如何将" d ":" Rwyv99W3GnfjYbI0X-b5Umhvh88oRCKQkPxiwCPVGgg" 放入此参数中? 好像是base-64-uri编码成"d" 好的,我从base64解码这个参数,实际上得到了32个字节。那么函数 ecdsa_sign_osl 的第二个参数 - Hash 呢?它也是 32 字节。这是什么? 这是它正在签名的 256 位哈希。正如它的名字所说。我怀疑,如果您无法弄清楚这一点,您可能会在旅途中迷路。也许值得阅读一些有关 ECDSA 工作原理的文档。

以上是关于如何在 Delphi 中将 JSON Web Key 转换为 PEM 格式?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 中将 JSON 参数作为 Web 服务请求发送? [复制]

如何在 C# EF 核心 web api 中将列表转换为 Json

如何在 Delphi 2010 中将参数传递给 flash 电影?

如何在 Node.JS 中将 Json Web Token 拆分为 Header-Payload-Signature

delphi json 是不是有效

delphi7有System.json么