使用“模数”和“指数”在OpenSSL v3中创建RSA密钥在Ruby on Rails中不起作用

thtygnil  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(123)

我有一个RSA公钥模数和指数字符串。我想在Ruby on Rails中使用它们创建一个OpenSSL::PKey::RSA。我试了三种不同的方法,我觉得我的记忆有些混乱,但是,我不能发现它。你知道吗?
版本号:

ruby 3.2.1 (2023-02-08 revision 31819e82c8) [arm64-darwin22]
Rails 7.0.8
OpenSSL 3.1.2 1 Aug 2023

首次尝试

我这样做:

modulus = k['n']
exponent= k['e']
rsa = OpenSSL::PKey::RSA.new
rsa.set_key_rsa(k['n'], k['e'], 2)

我得到错误:

undefined method `set_key_rsa' for #<OpenSSL::PKey::RSA:0x000000010a1468a0 oid=rsaEncryption>

第二次尝试

我这样做:

modulus = k['n']
exponent= k['e']
rsa = OpenSSL::PKey::RSA.new
rsa.set_key(k['n'], k['e'], 2) # <---- used set_key

我收到错误:

rsa#set_key= is incompatible with OpenSSL 3.0

rsa = OpenSSL::PKey::RSA.new
rsa.n = OpenSSL::BN.new(Base64.urlsafe_decode64(k['n']), 2)
rsa.e = OpenSSL::BN.new(Base64.urlsafe_decode64(k['e']), 2)

我收到错误:

undefined method `n=' for #<OpenSSL::PKey::RSA:0x000000010ab56e08 oid=rsaEncryption>

啊,怎么回事?

new9mtju

new9mtju1#

跳到解决方案的一部分,如果你不感兴趣,我正在尝试。

上下文:

我正在创建一个LTI工具,它有一个URL来获取密钥集,用于验证从LTI平台发送的JWT令牌。密钥集中的密钥具有模数(n)和指数(e)值,以创建将解码JWT的RSA密钥。
有两个问题

  • 在OpenSSL v3中,ne方法不再起作用。
  • 不清楚如何正确格式化模数(n)和指数(e)值,以便在某些方法中使用

解决方案:

我发现第一个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

希望这对你有帮助!

相关问题