验证用python签名的文件的问题

时间:2017-10-20 21:33:37

标签: python google-app-engine openssl cryptography google-cloud-storage

我尝试使用OpenSSL和Python创建一个签名文件,但我没有收到任何错误消息,但是过程无法正常工作,我无法找到原因。< / p>

以下是我一步一步签署文件并检查签名:

  1. 首先我在命令行中创建crt

    openssl req -nodes -x509 -sha256 -newkey rsa:4096 -keyout "cert.key" -out "cert.crt" -subj "/C=BR/ST=SP/L=SP/O=Company/OU=IT Dept/CN=cert"

  2. 此时,我有两个文件:cert.keycert.crt

    1. 使用如下所示的Python脚本对文件进行签名:

      import os.path
      from Crypto.PublicKey import RSA
      from Crypto.Signature import PKCS1_v1_5
      from Crypto.Hash import SHA256
      from base64 import b64encode, b64decode
      
      def __init__(self):
          folder = os.path.dirname(os.path.realpath(__file__))
          file_path = os.path.join(folder, '../static/cert.key')
          self.key = open(file_path, "r").read()
      
      def sign_data(self, my_file):
          rsakey = RSA.importKey(self.key) # I opened the cert.key in __init__
          signer = PKCS1_v1_5.new(rsakey)
          digest = SHA256.new()
      
          digest.update(my_file)
          sign = signer.sign(digest)
      
          return sign, b64encode(sign)
      
    2. 一切正常,保存文件后,我还有其他三个文件:my_file.csv(原始文件),my_file.txt.sha256my_file.txt.sha256.base64。此时,我可以解码base64文件并与签名文件进行比较,两者都很好。

      问题是当我尝试使用以下命令verify the signature时:

      `openssl dgst -sha256 -verify  <(openssl x509 -in "cert.crt"  -pubkey -noout) -signature my_file.txt.sha256 my_file.csv`
      

      此时我总是收到&#34;验证失败&#34;并且不明白为什么。

      也许问题是我缺乏Python的知识,因为当我使用以下命令签署文件时(在步骤1之后和使用2中描述的Python脚本之前),相同的验证工作正常。

      openssl dgst -sha256 -sign "cert.key" -out my_file.txt.sha256 my_file.csv
      

      我做错了吗?

      更新

      基于这些评论,我在python 2.7的本地virtualnv中尝试了这个脚本并且它工作正常,所以问题必须在读/写操作中。

      我使用完整的脚本更新此队列,包括读/写操作,因为我可以在本地运行它,但我仍然没有在GAE环境中出现任何错误,并且可以& #39;了解原因。

      第一步是使用以下脚本在Google存储(存储桶)中创建和存储CSV

      import logging
      import string
      import cloudstorage as gcs
      from google.appengine.api import app_identity
      
      def create_csv_file(self, filename, cursor=None):    
          filename = '/' + self.bucket_name + filename
          try:
              write_retry_params = gcs.RetryParams(backoff_factor=1.1)
              # the cursor stores a MySQL result set
              if cursor is not None:
                  gcs_file = gcs.open(filename,
                                      'w',
                                      content_type='text/csv',
                                      retry_params=write_retry_params)
                  for row in cursor:
                      gcs_file.write(','.join(map(str, row)) + '\n')
                  gcs_file.close()
          except Exception as ex:
              logging.critical("Problem to write in th GC Storage with the exception:{}".format(ex))
              raise ex
      

      工作正常,并将CSV存储在Google存储空间内的正确路径中。在该部分之后,下一个读/写操作是文件的签名。

      def cert_file(self, original_filename):
          filename = '/' + self.bucket_name + original_filename
          cert = Cert() # This class just has one method, that is that described in my original question and is used to sign the file.
      
          with gcs.open(filename) as cloudstorage_file:
              cloudstorage_file.seek(-1024, os.SEEK_END)
              signed_file, encoded_signed_file = cert.sign_data(cloudstorage_file.read()) #the method to sign the file
          signature_content = encoded_signed_file
      
          signed_file_name = string.replace(original_filename, '.csv', '.txt.sha256')
          encoded_signed_file_name = string.replace(signed_file_name, '.txt.sha256', '.txt.sha256.base64')
      
          self.inner_upload_file(signed_file, signed_file_name)
          self.inner_upload_file(encoded_signed_file, encoded_signed_file_name)
      
          return signed_file_name, encoded_signed_file_name, signature_content
      

      inner_upload_file,只需将新文件保存在同一个存储桶中:

      def inner_upload_file(self, file_data, filename):
          filename = '/' + self.bucket_name + filename
          try:
              write_retry_params = gcs.RetryParams(backoff_factor=1.1)
              gcs_file = gcs.open(filename,
                                  'w',
                                  content_type='application/octet-stream',
                                  retry_params=write_retry_params)
              gcs_file.write(file_data)
              gcs_file.close()
          except Exception as ex:
              logging.critical("Problem to write in th GC Storage with the exception:{}".format(ex))
              raise ex
      

      Here is the app.yaml以供参考。命令行生成的cert.key和cert.crt存储在app文件夹内的静态文件夹中(与我的app.yaml相同的目录)。

      更新2

      在评论之后,我尝试在本地运行签名过程,然后比较文件。以下是逐步和结果。

      首先,我将签名过程调整为python sign.py file_name

      #!/usr/bin/python
      
      import sys
      import os
      from Crypto.PublicKey import RSA
      from Crypto.Signature import PKCS1_v1_5
      from Crypto.Hash import SHA256
      from base64 import b64encode, b64decode
      
      file_path = 'static/cert.key'
      key = open(file_path, "rb").read()
      
      rsakey = RSA.importKey(key)
      signer = PKCS1_v1_5.new(rsakey)
      digest = SHA256.new()
      file_object  = open(sys.argv[1], "r")
      digest.update(file_object.read())
      sign = signer.sign(digest)
      signed_path = "signed"
      f = open(signed_path + '.txt.sha256', 'w')
      f.write(sign)
      f.close()
      f2 = open(signed_path + '.txt.sha256.base64', 'w')
      f2.write(b64encode(sign))
      f2.close()
      

      我运行了自动进程,将签名文件保存在GCS的存储桶中(以及原始CSV文件)。之后,我通过谷歌网页面板为GCS下载了这两个文件。

      我使用我刚刚下载的CSV文件在带有python 2.7.10的virtualenv中运行了命令python sign.py gcs_file_original.csv

      之后,我将两个签名文件与cmp -b gcs_signed.txt.sha256 locally_signed.txt.sha256进行了比较,结果为:

        

      gcs_signed.txt.sha256 local_signed.txt.sha256不同:字节1,第1行是24 ^ T 164 t

      使用VisualBinaryDiff,结果看起来像两个完全不同的文件。

      diif between signatures

      现在,我知道这个问题,但不知道如何解决它。这个问题非常棘手。

1 个答案:

答案 0 :(得分:2)

我终于找到了问题。我非常专注于在openssl签名过程中发现问题并且没有注意旧的Ctrl + C / Ctrl + V问题。

出于测试目的,我复制了'Read from GCS' example from this tutorial

当我将测试移到真实世界的应用程序时,我没有再次阅读该页面,也没有注意到gcs_file.seek(-1024, os.SEEK_END)

正如我在原始问题中所说,我不是Python专家,但这行只是阅读GCS文件的一部分,因此签名确实与原始签名不同。

只需缩短我的阅读方法,现在一切正常。