我正在尝试编写
Ruby代码来检查我发现的特定消息上的椭圆曲线数字签名算法(ECDSA)签名
here.
问题是我不知道如何将公钥的八位字符串转换为OpenSSL::PKey::EC::Point对象.如果我用C语言写这个,我只是将八位字节串传递给OpenSSL的o2i_ECPublicKey
,它做了一些接近我想要的东西,实际上是reference implementation使用的.但是,我搜索了source code of Ruby (MRI)并且它不包含对o2i_EcpublicKey的调用所以我不知道如何在没有编写C扩展的情况下从Ruby中使用该函数.
这是八位字节的八位字符串.它只是一个0x04字节,后跟两个32字节整数,表示椭圆曲线上点的x和y坐标:
04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284
那么有谁知道如何将该字符串转换为Ruby中的OpenSSL :: PKey :: EC :: Point?一旦我得到了点对象,我将在下面的代码中使用它,我相信它将验证签名:
key = OpenSSL::PKey::EC.new('secp256k1') key.public_key = point result = key.dsa_verify_asn1(digest,signature)
更新:
感谢Jay-Ar Polidario,我得到了它的工作.以下是我使用OpenSSL验证签名的完整代码.我还写了一个名为ecdsa的宝石,并且我提供了代码,展示了如何使用我的宝石做同样的事情.
# coding: ASCII-8BIT digest = "\xbf\x91\xfb\x0b\x4f\x63\x33\x77\x4a\x02\x2b\xd3\x07\x8e\xd6\xcc" \ "\xd1\x76\xee\x31\xed\x4f\xb3\xf9\xaf\xce\xb7\x2a\x37\xe7\x87\x86" signature_der_string = "\x30\x45" \ "\x02\x21\x00" \ "\x83\x89\xdf\x45\xf0\x70\x3f\x39\xec\x8c\x1c\xc4\x2c\x13\x81\x0f" \ "\xfc\xae\x14\x99\x5b\xb6\x48\x34\x02\x19\xe3\x53\xb6\x3b\x53\xeb" \ "\x02\x20" \ "\x09\xec\x65\xe1\xc1\xaa\xee\xc1\xfd\x33\x4c\x6b\x68\x4b\xde\x2b" \ "\x3f\x57\x30\x60\xd5\xb7\x0c\x3a\x46\x72\x33\x26\xe4\xe8\xa4\xf1" public_key_octet_string = "\x04" \ "\xfc\x97\x02\x84\x78\x40\xaa\xf1\x95\xde\x84\x42\xeb\xec\xed\xf5" \ "\xb0\x95\xcd\xbb\x9b\xc7\x16\xbd\xa9\x11\x09\x71\xb2\x8a\x49\xe0" \ "\xea\xd8\x56\x4f\xf0\xdb\x22\x20\x9e\x03\x74\x78\x2c\x09\x3b\xb8" \ "\x99\x69\x2d\x52\x4e\x9d\x6a\x69\x56\xe7\xc5\xec\xbc\xd6\x82\x84" # Verifying with openssl. require 'openssl' ec = OpenSSL::PKey::EC.new('secp256k1') key_bn = OpenSSL::BN.new(public_key_octet_string,2) # 2 means binary ec.public_key = OpenSSL::PKey::EC::Point.new(ec.group,key_bn) result = ec.dsa_verify_asn1(digest,signature_der_string) puts result # => true # Verifying with the new ECDSA gem I wrote,version 0.1.5 require 'ecdsa' group = ECDSA::Group::Secp256k1 point = ECDSA::Format::PointOctetString.decode(public_key_octet_string,group) signature = ECDSA::Format::SignatureDerString.decode(signature_der_string) result = ECDSA.valid_signature?(point,digest,signature) puts result # => true
我认为OpenSSL让你暂时将公钥表示为单个BN(大数字)是很奇怪的,因为它实际上是两个大数字.我的gem可以直接将八位字符串(如SEC2标准中所定义)转换为ECDSA :: Point对象.
解决方法
尝试以下(测试没有错误):
key = '04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284' key_bn = OpenSSL::BN.new(key,16) #Input: 16=Hexa,Output: BigNumber group = OpenSSL::PKey::EC::Group.new('secp256k1') point = OpenSSL::PKey::EC::Point.new(group,key_bn) #--> <OpenSSL::PKey::EC::Point:0x5288178>