使用Ruby OpenSSL从私钥获取椭圆曲线公钥

问题描述 投票:0回答:4

我正在使用 Ruby 2.5.x OpenSSL 库尝试椭圆曲线。我可以使用

轻松生成私钥和公钥对
curve = OpenSSL::PKey::EC.new('secp256k1')
curve.generate_key

但是给定私钥我想重新生成公钥。

我知道 OpenSSL 可以做到这一点,因为命令行允许你做到这一点,Ruby 比特币项目也可以做到这一点。但 Ruby Bitcoin 项目有自己的使用 FFI 的 OpenSSL 接口,而不是 Ruby 提供的接口。

Ruby 2.5.x openssl 库是否没有公开足够的 OpenSSL 接口来从私钥生成椭圆曲线公钥,或者它可以但没有记录?

ruby openssl elliptic-curve
4个回答
8
投票

如果有人也有兴趣获取 pem 格式的公钥:)

example_key = OpenSSL::PKey::EC.new('secp256k1').generate_key
puts example_key.to_pem
pkey = OpenSSL::PKey::EC.new(example_key.public_key.group)
pkey.public_key = example_key.public_key
puts pkey.to_pem

4
投票

https://stackoverflow.com/a/64023608/2603673中的答案不适用于openssl 3.x,因为密钥现在是不可变的,我们需要更改为:

key = OpenSSL::PKey::EC.new('secp256k1').generate_key
group = key.public_key.group
point = key.public_key
asn1 = OpenSSL::ASN1::Sequence(
  [
    OpenSSL::ASN1::Sequence([
      OpenSSL::ASN1::ObjectId('id-ecPublicKey'),
      OpenSSL::ASN1::ObjectId(group.curve_name)
    ]),
    OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
  ]
)
pkey = OpenSSL::PKey::EC.new(asn1.to_der)
puts pkey.to_pem

3
投票

据我所知,Ruby OpenSSL 绑定不允许您直接从

PKey::EC
对象获取公钥,但它们确实暴露了足够的信息来让您自己进行计算,这很简单。

将私钥作为

OpenSSL:BN
对象给出,对于示例,我们可以这样生成:

example_key = OpenSSL::PKey::EC.new('secp256k1').generate_key
private_key = example_key.private_key

我们可以通过将组基点(即生成器)乘以私钥来计算公钥:

group = OpenSSL::PKey::EC::Group.new('secp256k1')
public_key = group.generator.mul(private_key)

公钥是

OpenSSL::PKey::EC::Point
。你可以和原版比较一下,发现是一样的:

puts example_key.public_key == public_key # => true

0
投票

在 OpenSSL 3.0 中,密钥是不可变的,这意味着您无法在创建现有 OpenSSL::PKey::EC 对象后对其进行修改。您应该使用 ASN.1 编码构建公钥,而不是尝试在现有对象上设置公钥。

以下是如何重构代码以使用 OpenSSL 3.0:

  private_key = OpenSSL::PKey::EC.generate("secp256k1")
  asn1 = OpenSSL::ASN1::Sequence(
    [
      OpenSSL::ASN1::Sequence(
        [
          OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
          OpenSSL::ASN1::ObjectId(private_key.public_key.group.curve_name)
        ]
      ),
      OpenSSL::ASN1::BitString(private_key.public_key.to_octet_string(:uncompressed))
    ]
  )
  public_key = OpenSSL::PKey::EC.new(asn1.to_der)
  puts public_key.to_pem
© www.soinside.com 2019 - 2024. All rights reserved.