Ruby SHA1 RSA签名与命令行OpenSSL不同?

时间:2018-05-25 15:57:57

标签: ruby openssl rsa sha1

我正在尝试实施RSA SHA1签名验证。 令我惊讶的是,命令行OpenSSL工具不会生成与Ruby OpenSSL相同的密钥。

如果我运行这些命令:

MacBook-Pro-de-Geoffrey:ssl_tests Escaflowne$ cat data.txt 
000
MacBook-Pro-de-Geoffrey:ssl_tests Escaflowne$ openssl dgst -sha1 -binary -sign prvkey.pem -out sig.bin data.txt
MacBook-Pro-de-Geoffrey:ssl_tests Escaflowne$ openssl base64 -in sig.bin -out sig64.txt
MacBook-Pro-de-Geoffrey:ssl_tests Escaflowne$ cat sig64.txt
AJEh2kA7O3j624Kdl7UCGN1HiEk/v2LQudB+cjxw1CfmRTjcSPBjUE/EAwy8NEut
K4zYgfRwwTs7NY3AwYiUEtAe5yohUM0Qv17qSDW+G4IWjwe9PKE7Sl00umiMdszA
q/1hqeQlHKgjme7YO7H6i1UcAXmriOOjn+ySRaovsHw=

所以命令行中的最终base64结果是: AJEh2kA7O3j624Kdl7UCGN1HiEk/v2LQudB+cjxw1CfmRTjcSPBjUE/EAwy8NEut K4zYgfRwwTs7NY3AwYiUEtAe5yohUM0Qv17qSDW+G4IWjwe9PKE7Sl00umiMdszA q/1hqeQlHKgjme7YO7H6i1UcAXmriOOjn+ySRaovsHw=

现在,如果我尝试通过我的ruby脚本签名:

def sign_message(message)
    privkey = OpenSSL::PKey::RSA.new(File.read(Rails.root.join('lib', 'payment', 'prvkey.pem')))

    digest = OpenSSL::Digest.new('sha1')

    expected_sign = privkey.sign(digest, message)
    base_64_expected_sign = [expected_sign].pack('m')

    puts "Expected Signature"
    puts expected_sign
    puts "Base 64 Expected Signature"
    puts base_64_expected_sign

    return base_64_expected_sign
  end

调用这个函数:

  def test_sign
    message = "000"
    message_signature = sign_message(message)
    puts "Message Signature : #{message_signature}"

    puts "Valid : #{verify_signature(message_signature, message)}"
  end

我得到了输出:

Expected Signature
??|??n?^~?T_1Y@??BR??u???k      x?*????S?L?:.7
                          t??tc?)崪? ?}DMp?p2??4?D-f??jT;!e
                                                              ?k??5??
Base 64 Expected Signature
QjhL1zQoUdGFLVCMg06/CKeE/HdhRTOhJ/p09wkWeK0qD/afsxfcU7tMtDou
Nw3rwXw/5W68XhZ+BK1UXwIxWUDbFYlCUpu6HnWTmI5rC3QP+f50Y8kp5bSq
gQkekH1ETXDmcDKvExeSNKVELWYe3uwTalQ7IWUMyWvnF541rvo=
Message Signature : QjhL1zQoUdGFLVCMg06/CKeE/HdhRTOhJ/p09wkWeK0qD/afsxfcU7tMtDou
Nw3rwXw/5W68XhZ+BK1UXwIxWUDbFYlCUpu6HnWTmI5rC3QP+f50Y8kp5bSq
gQkekH1ETXDmcDKvExeSNKVELWYe3uwTalQ7IWUMyWvnF541rvo=

所以最终的ruby OpenSSL签名是: QjhL1zQoUdGFLVCMg06/CKeE/HdhRTOhJ/p09wkWeK0qD/afsxfcU7tMtDou Nw3rwXw/5W68XhZ+BK1UXwIxWUDbFYlCUpu6HnWTmI5rC3QP+f50Y8kp5bSq gQkekH1ETXDmcDKvExeSNKVELWYe3uwTalQ7IWUMyWvnF541rvo=

Versus命令行: AJEh2kA7O3j624Kdl7UCGN1HiEk/v2LQudB+cjxw1CfmRTjcSPBjUE/EAwy8NEut K4zYgfRwwTs7NY3AwYiUEtAe5yohUM0Qv17qSDW+G4IWjwe9PKE7Sl00umiMdszA q/1hqeQlHKgjme7YO7H6i1UcAXmriOOjn+ySRaovsHw=

我一直在努力解决这个问题已有一段时间了,我不明白可能会有什么影响!

更新:

好吧,如果我用File.read(Rails.root.join('lib', 'payment', 'data.txt'))替换我的消息变量,显然结果匹配 所以基本上,使用与文本文件中的值相同的字符串不会给出相同的结果。 这意味着它的编码相关吗?

更新2:

因此,如果我运行us-ascii,该文件会将其编码在file -I data.txt中 但是,如果我message.encoding.name,则表示其加载为UTF-8 此外,message.encode('ascii')不会更改生成的签名的结果,它仍然与命令行openssl相对应。 只要我切换到字符串"000".encode('utf-8')"000".encode('ascii'),签名就不再匹配了。 所以编码似乎根本没有发挥作用。

完全相同的内容之间有什么不同,无论是来自阅读文件还是写成字符串?

1 个答案:

答案 0 :(得分:1)

文件data.txt有一个您在代码中没有考虑的尾随换行符。使用

message = "000\n"

应该有用。

您也可以

message = File.binread("data.txt")

确保您获得命令行的确切数据。