Ruby RSA从指数和模数字符串

fivyi3re  于 2023-10-17  发布在  Ruby
关注(0)|答案(4)|浏览(104)

我有一个RSA公钥模数和指数字符串。
我想用这两个字符串创建一个OpenSSL::PKey::RSA
基本上,它们是:

*n= 'long string'
*e= '4-字符串'

在Ruby中如何做到这一点?最终目标是把它放到JWT gem中。

更新

我目前使用的是Ruby 2.3.1,所以这样做是可行的:

key = OpenSSL::PKey::RSA.new
key.e = OpenSSL::BN.new(Base64.decode64(e), 2)
key.n = OpenSSL::BN.new(Base64.decode64(n), 2)

但是,它在升级过程中不起作用。

up9lanfz

up9lanfz1#

我让它以这种方式工作,基于这个python实现:
https://github.com/jpf/okta-jwks-to-pem/blob/master/jwks_to_pem.py

key = OpenSSL::PKey::RSA.new
    exponent = kid_header['e']
    modulus = kid_header['n']

    # Voila !
    key.set_key(base64_to_long(modulus), base64_to_long(exponent), nil)

    def base64_to_long(data)
      decoded_with_padding = Base64.urlsafe_decode64(data) + Base64.decode64('==')
      decoded_with_padding.to_s.unpack('C*').map do |byte|
        to_hex(byte)
      end.join.to_i(16)
    end

    def to_hex(int)
      int < 16 ? '0' + int.to_s(16) : int.to_s(16)
    end
v440hwme

v440hwme2#

您可以使用JSON::JWT gem(https://rubygems.org/gems/json-jwthttps://github.com/nov/json-jwt

# can be found somewhere in `.well-known` space on the server
key_hash = {
  "kty": "RSA",
  "use": "sig",
  "kid": ...,
  "e": ...,
  "n": ...,
  "alg": "RS256"
}
jwk = JSON::JWK.new(key_hash)
JSON::JWT.decode token, jwk.to_key
# voila!

Ruby JWT(https://rubygems.org/gems/jwthttps://github.com/jwt/ruby-jwt/blob/master/lib/jwt/jwk/rsa.rb)也可以实现同样的效果。

public_key = JWT::JWK::RSA.import(key_hash).public_key
JWT.decode token, public_key, true, { algorithm: key_hash[:alg] }
xpszyzbs

xpszyzbs3#

对于Ruby 2.4+,您应该使用:用途:

key = OpenSSL::PKey::RSA.new
key.set_key(n, e, d)

如果你没有d,你可以设置为nil

50pmv0ei

50pmv0ei4#

接受的答案在OpenSSL v3中对我不起作用。查看此线程以获得适用于OpenSSL v3的解决方案。
使用“模数”和“指数”在OpenSSL v3中创建RSA密钥在Ruby on Rails中不起作用

解决方案:

我发现第一个Gist在 * OpenSSL v3之前 * 工作,但是它在OpenSSL v3中不工作。值得庆幸的是,这位伟大的家伙在评论中分享了如何在OpenSSL v3中实现这一点。查看第二个链接以获得Gist或下面的代码以获得解决方案。

在第二个链接中分享这里提供的Gist代码(以防万一):

# Given n and e in typical encoding, like that found on a jwks well-known.
# For example for google, from https://www.googleapis.com/oauth2/v3/certs
n = "t0VFy4n4MGtbMWJKk5qfCY2WGBja2WSWQ2zsLziSx9p1QE0QgXtr1x85PnQYaYrAvOBiXm2mrxWnZ42MxaUUu9xyykTDxsNWHK--ufchdaqJwfqd5Ecu-tHvFkMIs2g39pmG8QfXJHKMqczKrvcHHJrpTqZuos1uhYM9gxOLVP8wTAUPNqa1caiLbsszUC7yaMO3LY1WLQST79Z8u5xttKXShXFv1CCNs8-7vQ1IB5DWQSR2um1KV4t42d31Un4-8cNiURx9HmJNJzOXbTG-vDeD6sapFf5OGDsCLO4YvzzkzTsYBIQy_p88qNX0a6AeU13enxhbasSc-ApPqlxBdQ"
e = "AQAB"

rsa = create_rsa_key(n, e)

def create_rsa_key(n, e)
  data_sequence = OpenSSL::ASN1::Sequence([
                                            OpenSSL::ASN1::Integer(base64_to_long(n)),
                                            OpenSSL::ASN1::Integer(base64_to_long(e))
                                          ])
  asn1 = OpenSSL::ASN1::Sequence(data_sequence)
  OpenSSL::PKey::RSA.new(asn1.to_der)
end

def base64_to_long(data)
  decoded_with_padding = Base64.urlsafe_decode64(data) + Base64.decode64("==")
  decoded_with_padding.to_s.unpack("C*").map do |byte|
    byte_to_hex(byte)
  end.join.to_i(16)
end

def byte_to_hex(int)
  int < 16 ? "0" + int.to_s(16) : int.to_s(16)
end

希望这对你有帮助!

相关问题