Как проверить подписанный файл в Python - PullRequest
0 голосов
/ 30 мая 2018

Фон

Я подписал файл, используя openssl SHA256 и закрытый ключ, следующим образом:

with subprocess.Popen(
        # Pipe the signature to openssl to convert it from raw binary encoding to base64 encoding.
        # This will prevent any potential corruption due to line ending conversions, and also allows 
        # a human to read and copy the signature (e.g. for manual verification).
        'openssl dgst -sha256 -sign private.key sign_me.zip | openssl base64 > signature.sha256',
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        shell=True,
) as proc:
    out, _ = proc.communicate()

Требования

  1. Мне нужноиспользуйте signature.sha256 и public_key.crt, чтобы убедиться, что sign_me.zip не был изменен.
  2. Совместимо с Python 3.2 - 3.4
  3. Требуется для работы как в Windows, так и в Redhat, инет никакой гарантии, что OpenSSL будет на пути или в известном месте.В идеале я хотел бы использовать основной модуль Python, но я рассмотрю сторонний модуль, если он уменьшит сложность.

Что я пробовал

Я сделалЯ много искал, пытаясь понять, как это сделать, но я не смог найти удовлетворительного ответа.Вот список вещей, которые я пробовал и / или исследовал:

  • Я могу вручную проверить подпись с помощью следующей команды оболочки.Это не будет работать как постоянное решение из-за требования 3.

    openssl dgst -sha256 -verify <(openssl x509 -in public_key.crt -pubkey -noout) -signature signature.sha256 sign_me.zip

  • Я нашел этот вопрос , что почти точноЧто я хочу сделать.Это не было ответа или даже прокомментировано в течение почти 2 лет.В ней упоминается библиотека ssl python , которая в основном работает с сертификатами и сокетами клиент / сервер.

  • Этот вопрос , по-видимому, использует библиотеку шифрования для проверкиПодпись "SHA256 с RSA и PKCS1".К сожалению, он нацелен на Python 2.7, и, кроме того, я не смог найти документацию по методу verify() в модуле Python 2.7 crypto , на который ссылается вопрос.
  • Я также обнаружил третье лицомодуль под названием криптография .Похоже, консенсус по переполнению стека заключается в том, что это последний / самый лучший модуль для шифрования и тому подобное, но я не смог найти документацию, соответствующую моим требованиям.

Возможно, я упускаю что-то очевидное?Я не очень много работал с безопасностью / шифрованием / хэшированием, поэтому отзывы приветствуются.

1 Ответ

0 голосов
/ 13 июля 2018

Спасибо Патрику Мевзеку за то, что он указал мне правильное направление.В конце концов я нашел следующее решение моей проблемы с помощью модуля Cryptography .Я закончил тем, что изменил, как я подписываю файл, чтобы соответствовать тому, как я буду позже проверять это.

Генерация ключа:

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

# Generate the public/private key pair.
private_key = rsa.generate_private_key(
    public_exponent = 65537,
    key_size = 4096,
    backend = default_backend(),
)

# Save the private key to a file.
with open('private.key', 'wb') as f:
    f.write(
        private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
        )
    )

# Save the public key to a file.
with open('public.pem', 'wb') as f:
    f.write(
        private_key.public_key().public_bytes(
            encoding = serialization.Encoding.PEM,
            format = serialization.PublicFormat.SubjectPublicKeyInfo,
        )
    )

Подпись:

import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding

# Load the private key. 
with open('private.key', 'rb') as key_file: 
    private_key = serialization.load_pem_private_key(
        key_file.read(),
        password = None,
        backend = default_backend(),
    )

# Load the contents of the file to be signed.
with open('payload.dat', 'rb') as f:
    payload = f.read()

# Sign the payload file.
signature = base64.b64encode(
    private_key.sign(
        payload,
        padding.PSS(
            mgf = padding.MGF1(hashes.SHA256()),
            salt_length = padding.PSS.MAX_LENGTH,
        ),
        hashes.SHA256(),
    )
)
with open('signature.sig', 'wb') as f:
    f.write(signature)

Проверка:

import base64
import cryptography.exceptions
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_pem_public_key

# Load the public key.
with open('public.pem', 'rb') as f:
    public_key = load_pem_public_key(f.read(), default_backend())

# Load the payload contents and the signature.
with open('payload.dat', 'rb') as f:
    payload_contents = f.read()
with open('signature.sig', 'rb') as f:
    signature = base64.b64decode(f.read())

# Perform the verification.
try:
    public_key.verify(
        signature,
        payload_contents,
        padding.PSS(
            mgf = padding.MGF1(hashes.SHA256()),
            salt_length = padding.PSS.MAX_LENGTH,
        ),
        hashes.SHA256(),
    )
except cryptography.exceptions.InvalidSignature as e:
    print('ERROR: Payload and/or signature files failed verification!')
...