Problemas para verificar um arquivo assinado com python

8

Estou tentando criar um arquivo assinado usando o OpenSSL e o Python, e não estou recebendo nenhuma mensagem de erro, mas o processo não está funcionando corretamente e não consigo encontrar o motivo.

Abaixo está o meu passo-a-passo para assinar o arquivo e verificar a assinatura:

  1. Primeiro eu crio o crt na linha de comando

    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"

Neste ponto, tenho dois arquivos: cert.key e cert.crt

  1. Assine o arquivo usando um script Python como abaixo:

    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)
    

Tudo funciona bem e depois de salvar os arquivos, eu tenho outros três arquivos: my_file.csv (o original), my_file.txt.sha256 e my_file.txt.sha256.base64 . Neste ponto, eu posso decodificar o arquivo base64 e comparar com o assinado e ambos estão bem.

O problema é quando tento verificar a assinatura usando o seguinte comando:

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

Nesse ponto, sempre recebo a "Falha de verificação" e não entendo o motivo.

Talvez o problema seja minha falta de Conhecimento do Python, porque quando eu assino o arquivo usando o seguinte comando (após a etapa 1 e antes de usar o script Python descrito em 2), a mesma verificação funciona bem.

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

Estou fazendo algo errado?

UPDATE

Com base nos comentários, eu tentei o script em um virtualnv local com python 2.7 e funcionou, então o problema deve estar nas operações de leitura / gravação.

Estou atualizando essa opção com o script completo, incluindo as operações de leitura / gravação, pois posso executá-lo localmente, mas ainda não recebo nenhum erro no ambiente do GAE e não consigo entender o motivo.

O primeiro passo é a criação e armazenamento de CSV no Google Storage (Bucket) com o script abaixo

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

Funciona bem e armazena um CSV no caminho correto dentro do armazenamento do Google. Depois dessa parte, a próxima operação de leitura / gravação é a assinatura do arquivo.

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

O inner_upload_file , basta salvar os novos arquivos no mesmo intervalo:

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

Aqui está o app.yaml para referência. O cert.key e o cert.crt gerados pela linha de comando são armazenados em uma pasta estática dentro da pasta do aplicativo (o mesmo diretório onde está o meu app.yaml).

UPDATE 2

Após os comentários, tentei executar o processo de assinatura localmente e comparar os arquivos. Abaixo está o passo a passo e os resultados.

Primeiro, adaptei o processo de assinatura para ser executado como 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()

Eu executei o processo automático que salvou o arquivo assinado no bucket do GCS (junto com o arquivo CSV original). Depois, faço o download dos dois arquivos pelo painel da web do Google para o GCS.

Eu executei o comando python sign.py gcs_file_original.csv em um virtualenv com python 2.7.10 usando o arquivo CSV que acabei de baixar.

Depois, comparei os dois arquivos assinados com cmp -b gcs_signed.txt.sha256 locally_signed.txt.sha256 , resultando em:

  

gcs_signed.txt.sha256 locally_signed.txt.sha256 diferem: byte 1, linha 1 é 24 ^ T 164 t

Usando o VisualBinaryDiff , o resultado parece com dois arquivos totalmente diferentes.

Agora, conheço o problema, mas não tenho ideia de como corrigi-lo. Esse problema está sendo muito complicado.

    
por James 20.10.2017 в 23:33
fonte

1 resposta

2

Eu finalmente encontrei o problema. Eu estava tão focado em encontrar um problema no processo de assinatura do openssl e não prestei atenção ao antigo problema Ctrl + C / Ctrl + V.

Para fins de teste, copiei o 'Ler do GCS 'exemplo deste tutorial .

Quando mudei o teste para o aplicativo do mundo real, não li a página novamente e não anotei o gcs_file.seek(-1024, os.SEEK_END) .

Como eu disse na pergunta original, eu não sou especialista em Python, mas esta linha estava lendo apenas parte do arquivo GCS, então a assinatura era realmente diferente da original.

Basta cortar essa linha dos meus métodos de leitura e agora tudo funciona bem.

    
por James 26.10.2017 / 21:22
fonte