如何格式化OpenSSL密钥以匹配在线示例(JSBN-ECC)

时间:2014-03-14 16:31:17

标签: javascript ruby openssl elliptic-curve diffie-hellman

我希望能够将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。您可能想知道为什么我需要将公钥转换为另一个。不,我真的不需要。我只是想学习如何转换它,因为我将使用该方法来转换类似的东西。这是您测试方便的简化问题。

3 个答案:

答案 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^aA=(g_x, g_y)^a,这是一个点。


  

还因为point_conversion_form的默认格式是:uncompressed,因为我刚刚测试了

点转换/压缩只是表示层优化技巧。它省略了坐标的y部分,因为您可以在给定x的情况下解决它。由于它是一条曲线,有时您需要发送+1-1来指定y坐标所在的象限。但同样,它只是一个优化,只对互操作有用。将这一点读入库后,xy都可用。


  

您可能想知道为什么我需要将公钥转换为其他公钥...

不::)

但您可能想要注意的一件事是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_intkey_y_int现在与在线链接

的结果相匹配