我希望能够将OpenSSL中的Elliptic Curve Diffie-Hellman的公钥格式化为Ruby,就像这个在线示例(link)一样,因为我一直在使用那个JS库。
我的代码生成一个OpenSSL :: PKey :: EC公钥和私钥
#Ruby
ec = OpenSSL::PKey::EC.new('secp128r1')
ec.generate_key
ec.private_key
#--> 205607153615223513963863936713567041725
ec.public_key.to_bn
#--> 499599043529551953518354858381998373780459818901085313561109939106744612770290
尝试复制205607153615223513963863936713567041725
上方的私钥并将其粘贴在在线(link)上作为Alices的私有值。但是,请先点击secp1284r1
按钮以获得相同的曲线参数,然后点击Compute Public
按钮。
这将从输入的私钥生成公钥。但是,Ruby OpenSSL文档并没有真正的帮助,我仍然坚持要弄清楚如何转换上面生成的公钥:
499599043529551953518354858381998373780459818901085313561109939106744612770290
进入这样的事情(从在线网站上看到):
x: 107060165679262225845922473865530329196
y: 109296969851421346147544217212275741170
我认为通过正确转换一个,它可以以某种方式变得与另一个相等,因为它们具有相同的曲线参数。还是我错了? (还有,因为point_conversion_form
的默认格式是:uncompressed
,我刚刚测试了一下)请帮忙。
P.S。您可能想知道为什么我需要将公钥转换为另一个。不,我真的不需要。我只是想学习如何转换它,因为我将使用该方法来转换类似的东西。这是您测试方便的简化问题。
答案 0 :(得分:2)
Jay-Ar,
您不应该发现您的解决方案很奇怪,因为我认为对 ec.public_key.to_bn 的调用可能会遵守rfc5480 section 2.2重新:主题公钥哪个州:
2.2。主题公钥
- OCTET STRING的第一个八位字节表示密钥是否为 压缩或未压缩。指示未压缩的形式 按0x04,压缩形式由0x02或表示 0x03(参见[SEC1]中的2.3.3)。如果,公钥必须被拒绝 第一个八位字节中包含任何其他值。
假设情况属实,并且由于您声明格式为:未压缩,您自己的答案对我来说完全合情合理。谢谢发帖! :)
答案 1 :(得分:0)
ec.public_key.to_bn
#--> 499599043529551953518354858381998373780459818901085313561109939106744612770290
以十六进制打印可能会更好。
公钥是曲线上的一个点。也就是说,它是一个(x,y)
坐标。因此可能需要拆分该值(因此以十六进制打印的原因)。猜猜:
x = 499599043529551953518354858381998373780
y = 459818901085313561109939106744612770290
公钥是一个点,因为它来自基点G
,它也是一个点。 G
有时会扩展为(g_x, g_y)
。私有指数是a
(或b
),它是标量或整数。所以公钥是A=G^a
或A=(g_x, g_y)^a
,这是一个点。
还因为point_conversion_form的默认格式是:uncompressed,因为我刚刚测试了
点转换/压缩只是表示层优化技巧。它省略了坐标的y
部分,因为您可以在给定x
的情况下解决它。由于它是一条曲线,有时您需要发送+1
或-1
来指定y
坐标所在的象限。但同样,它只是一个优化,只对互操作有用。将这一点读入库后,x
和y
都可用。
您可能想知道为什么我需要将公钥转换为其他公钥...
不::)
但您可能想要注意的一件事是OpenSSL的“命名曲线”标志。如果要将EC
密钥加载到基于OpenSSL的服务器,则需要确保私钥和生成的证书具有OPENSSL_EC_NAMED_CURVE
标记。否则,在尝试连接服务器时,您将收到诸如“无共享密码”之类的奇怪错误。有关详细信息,请参阅OpenSSL wiki上的ECDH and Named Curves。
答案 2 :(得分:0)
最后!我以某种方式设法正确转换它,但它有点奇怪。
#From above code
c.public_key.to_bn
#--> 499599043529551953518354858381998373780459818901085313561109939106744612770290
#irb:
require 'openssl'
key_int = '499599043529551953518354858381998373780459818901085313561109939106744612770290'
key_bn = OpenSSL::BN.new(key_int, 10) #Convert to OpenSSL::BN (Big Number, with 10=Decimal as base)
key_hex = key_bn.to_s(16) #Convert to Hex String (16=Hexadecimal)
#--> "04508B09B35FA8C21820BE19C16B38486C5239D4A932D081DD56B90F91120551F2"
#I don't really know why, but removing '04' above will finally convert it properly
key_hex = key_hex[2..-1] #Remove first 2 chars: '04'
#--> "508B09B35FA8C21820BE19C16B38486C5239D4A932D081DD56B90F91120551F2"
#Split key_hex into halves
key_hexarr = key_hex.chars.each_slice( (key_hex.length/2.0).round ).map(&:join)
#--> ["508B09B35FA8C21820BE19C16B38486C", "5239D4A932D081DD56B90F91120551F2"]
#Convert first value into BN (input: 16=hexadecimal), then convert to string(output: 10=decimal)
key_x_int = OpenSSL::BN.new(key_hexarr[0], 16).to_s(10)
#--> "107060165679262225845922473865530329196"
#Convert second value into BN (input: 16=hexadecimal), then convert to string(output: 10=decimal)
key_y_int = OpenSSL::BN.new(key_hexarr[1], 16).to_s(10)
#--> "109296969851421346147544217212275741170"
最后,key_x_int
和key_y_int
现在与在线链接