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

Jam*_*mes 8 python google-app-engine openssl cryptography google-cloud-storage

我正在尝试使用OpenSSL和Python创建一个签名文件,我没有收到任何错误消息,但是进程无法正常工作,我找不到原因.

下面是我逐步签署文件并检查签名:

  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"

此时,我有两个文件: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)
    
    Run Code Online (Sandbox Code Playgroud)

一切正常,保存文件后,我还有其他三个文件:( my_file.csv原始文件),my_file.txt.sha256my_file.txt.sha256.base64.此时,我可以解码base64文件并与签名的文件进行比较,两者都很好.

问题是当我尝试使用以下命令验证签名时:

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

在这一点上,我总是收到"验证失败",不明白为什么.

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

openssl dgst -sha256 -sign "cert.key" -out my_file.txt.sha256 my_file.csv
Run Code Online (Sandbox Code Playgroud)

我做错了吗?

UPDATE

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

我正在用完整的脚本更新这个队列,包括读/写操作,因为我可以在本地运行它,但我仍然没有在GAE环境中得到任何错误,并且无法理解原因.

第一步是使用下面的脚本在Google Storage(Bucket)中创建和存储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
Run Code Online (Sandbox Code Playgroud)

它工作正常,并将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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这是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()
Run Code Online (Sandbox Code Playgroud)

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

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

在它之后,我比较了两个签名文件,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

现在,我知道这个问题,但不知道如何修复它.这个问题非常棘手.

Jam*_*mes 2

我终于找到了问题所在。我非常专注于寻找 openssl 签名过程中的问题,而没有注意到旧的 Ctrl+C/Ctrl+V 问题。

出于测试目的,我复制了本教程中的“从 GCS 读取”示例

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

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

只要剪掉我的阅读方法的那一行,现在一切都正常了。