将 public 密钥导出到 Ruby 中的 base64

Export public key to base64 in Ruby

我有一个 PEM 格式的 public 密钥,它是通过以下方式生成的:

ecdsa_public_key = OpenSSL::PKey::EC.new ecdsa_private_key
ecdsa_public_key.private_key = nil
ecdsa_public_key.to_pem

我必须读取 PEM 字符串并获得 base64 url 编码的字符串。 我怎样才能在 Ruby 中做到这一点?

ecdsa_public_key = OpenSSL::PKey.read pem_string
ecdsa_public_key.to_base64 # pseudo code...

顺便说一句,我必须为 WebPush 协议执行此操作,该协议规定:

you must add your VAPID public key to the Crypto-Key header as a base64 url encoded string with p256ecdsa= prepended to it.

你可以试试

  require 'base64'
  Base64.encode64(ecdsa_public_key)

转换为 base64

PEM 字符串实际上是 base 64 编码的(至少部分),但我不认为这是你想要的,它包含其他细节,我认为你想要“原始”public 键数据.

这里有一种方法可以让您的密钥变成我认为您想要的格式。有点啰嗦,但我不认为 Ruby 的 OpenSSL 绑定提供了更直接的方法(你需要先 require "base64"):

# Assuming the key is in ecdsa_public_key
Base64.urlsafe_encode64(ecdsa_public_key.public_key.to_bn.to_s(2), padding: false)

这会调用 public_key 以获取基础 OpenSSL::PKey::EC::Point,然后将其转换为正确格式的 OpenSSL::BN,并将其转换为二进制字符串。最后这个字符串是base64编码的。

抱歉,有点晚了。

我对Ruby不是很熟悉,所以我无法提供具体的代码示例,但我可以尝试描述一下VAPID的过程。 (此外,如果我进入不必要的细节,我深表歉意,因为我认为其他人可能会偶然发现这一点。)

简而言之,VAPID 是一个 Javascript 网络令牌 (JWT)。您可以使用您最喜欢的 VAPID 专用 ECDSA 生成方法创建 ECDSA 密钥对。

例如

openssl ecparam -name prime256v1 -genkey -noout -out vapid_private.pem
openssl ec -in vapid_private.pem -pubout -out vapid_public.pem

“PEM”是一种格式化文件,包括标准 header 行、页脚行和一组长字符串。 (不确定这是否是他们的技术术语,但是是的,我将继续使用它。)那些长长的废话字符串是以特定格式保存的关键数据的 Base64 表示。

老实说,我强烈建议尽可能使用图书馆。 jwt.io 有许多 Ruby 库可供您使用,还有其他语言的库。至于“Crypto-Key:”header,有一些好消息news/other。

  1. 您可以从 vapid-public.pem 文件中取出长字符串,将它们附加在一起并将它们指定为 'p256ecdsa=' 键。
  2. VAPID 协议即将更改https://datatracker.ietf.org/doc/html/draft-ietf-webpush-vapid-02

此更改有效地摆脱了 Crypto-Key p256ecdsa 组件。相反,授权密钥变为:

授权: vapid t=JWT containing VAPID info,k=VAPID Public key

例如

vapid t=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYWlsdG86d2VicHVzaF9vcHNAY2F0ZmFjdHMuZXhhbXBsZS5jb20iLCJleHAiOjE0ODc0NDM3MTR9.mlLOWYMt-6aM3NB6b6_Msf8LqRKCuHd1Vfdp_fuJ3eqsQoID8lit305hIfNubTbvfACucuCygF3qB4scDbuHvg,k=EJwJZq_GN8jJbo1GGpyU70hmP2hbWAUpQFKDByKB81yldJ9GTklBM5xqEwuPM7VuQcyiLDhvovthPIXx-gsQRQ

我对此看法不一。它确实减少了对单独 header 的需求,但也减少了您在 运行 离开 header 房间之前可以放入索赔中的信息量。