使用 pyOpenSSL 签署大文件
Signing huge file with pyOpenSSL
我需要创建 SSL signatures for large *.tar.gz
files (gigabytes of data) using Python 3 and pyopenssl
模块。
下面是我的代码(有效)的简化摘录。有问题的行是以下一行:
bytes_to_sign = sign_file.read() # PROBLEM if file is LARGE
一次读取整个文件is probably not best idea但我不知道如何用其他方式读取。
代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import OpenSSL
import argparse
import getpass
import logging
DIGEST_METHOD = 'sha256'
SSL_CERT_FORMAT_TYPE = OpenSSL.crypto.FILETYPE_PEM
LOG_FORMAT = '[%(asctime)s][ %(levelname)s ] %(message)s'
def create_args_parser():
p = argparse.ArgumentParser(description='Simple SSL signature generator.')
p.add_argument('file', type=argparse.FileType('rb'),
metavar='signed_file_path',
help='path to the file that will be signed')
p.add_argument('--ssl-key', type=argparse.FileType(),
metavar='CERT_PATH', required=True,
help='path to SSL certificate private key in PEM format')
p.add_argument('-o', '--out', type=argparse.FileType('wb'),
metavar='SIGNATURE_PATH', required=True,
help='path where generated signature will be saved')
return p
def get_priv_key_obj(ssl_key_file):
"""Get password protecting SSL private key and create private key object."""
priv_key_str = ssl_key_file.read()
ssl_key_file.close() #
priv_key = None
while not priv_key:
ssl_passwd = getpass.getpass()
try:
priv_key = OpenSSL.crypto.load_privatekey(SSL_CERT_FORMAT_TYPE,
priv_key_str,
ssl_passwd.encode('ascii'))
except OpenSSL.crypto.Error:
logging.warning('Probably wrong password - try again')
return priv_key
def sign_file(priv_key, sign_file, out_file):
"""Sign given file with SSL private key and save signature in given file."""
bytes_to_sign = sign_file.read() # PROBLEM if file is LARGE
sign = OpenSSL.crypto.sign(priv_key, bytes_to_sign, DIGEST_METHOD)
sign_file.close()
out_file.write(sign)
out_file.close()
def main():
parser = create_args_parser()
args = parser.parse_args()
priv_key = get_priv_key_obj(args.ssl_key)
sign_file(priv_key, args.file, args.out)
if __name__ == '__main__':
try:
logging.basicConfig(format=LOG_FORMAT)
main()
except Exception as e:
logging.exception('Generating SSL certificate has failed. Check if '
'SSL cert password is correct. Details: {}'.format(e))
脚本--help
:
usage: sign.py [-h] --ssl-key CERT_PATH -o SIGNATURE_PATH signed_file_path
Simple SSL signature generator.
positional arguments:
signed_file_path path to the file that will be signed
optional arguments:
-h, --help show this help message and exit
--ssl-key CERT_PATH path to SSL certificate private key saved in PEM
format
-o SIGNATURE_PATH, --out SIGNATURE_PATH
path where generated signature will be saved
有什么方法可以不一次性 read()
整个文件吗?
到verify the created signature run (or alternatively implement verification using pyOpenSSL
):
openssl dgst -sha256 -verify cert_public_key_file.pub -signature cert_file.crt signed_file_path
如果您需要创建 SSL 证书来测试它,请参阅 this tutorial。
- 我知道有 similar questions on SO 但他们没有回答我的问题。
您必须实现自己的 chunked sign
功能。
但是收件人呢,它能验证吗?
Read about: EVP_DigestSignInit
EVP_DigestSignUpdate() hashes cnt bytes of data at d into the signature context ctx.
This function can be called several times on the same ctx to include additional data.
Adapt from def sign(pkey, data, digest):
我需要创建 SSL signatures for large *.tar.gz
files (gigabytes of data) using Python 3 and pyopenssl
模块。
下面是我的代码(有效)的简化摘录。有问题的行是以下一行:
bytes_to_sign = sign_file.read() # PROBLEM if file is LARGE
一次读取整个文件is probably not best idea但我不知道如何用其他方式读取。
代码如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import OpenSSL
import argparse
import getpass
import logging
DIGEST_METHOD = 'sha256'
SSL_CERT_FORMAT_TYPE = OpenSSL.crypto.FILETYPE_PEM
LOG_FORMAT = '[%(asctime)s][ %(levelname)s ] %(message)s'
def create_args_parser():
p = argparse.ArgumentParser(description='Simple SSL signature generator.')
p.add_argument('file', type=argparse.FileType('rb'),
metavar='signed_file_path',
help='path to the file that will be signed')
p.add_argument('--ssl-key', type=argparse.FileType(),
metavar='CERT_PATH', required=True,
help='path to SSL certificate private key in PEM format')
p.add_argument('-o', '--out', type=argparse.FileType('wb'),
metavar='SIGNATURE_PATH', required=True,
help='path where generated signature will be saved')
return p
def get_priv_key_obj(ssl_key_file):
"""Get password protecting SSL private key and create private key object."""
priv_key_str = ssl_key_file.read()
ssl_key_file.close() #
priv_key = None
while not priv_key:
ssl_passwd = getpass.getpass()
try:
priv_key = OpenSSL.crypto.load_privatekey(SSL_CERT_FORMAT_TYPE,
priv_key_str,
ssl_passwd.encode('ascii'))
except OpenSSL.crypto.Error:
logging.warning('Probably wrong password - try again')
return priv_key
def sign_file(priv_key, sign_file, out_file):
"""Sign given file with SSL private key and save signature in given file."""
bytes_to_sign = sign_file.read() # PROBLEM if file is LARGE
sign = OpenSSL.crypto.sign(priv_key, bytes_to_sign, DIGEST_METHOD)
sign_file.close()
out_file.write(sign)
out_file.close()
def main():
parser = create_args_parser()
args = parser.parse_args()
priv_key = get_priv_key_obj(args.ssl_key)
sign_file(priv_key, args.file, args.out)
if __name__ == '__main__':
try:
logging.basicConfig(format=LOG_FORMAT)
main()
except Exception as e:
logging.exception('Generating SSL certificate has failed. Check if '
'SSL cert password is correct. Details: {}'.format(e))
脚本--help
:
usage: sign.py [-h] --ssl-key CERT_PATH -o SIGNATURE_PATH signed_file_path
Simple SSL signature generator.
positional arguments:
signed_file_path path to the file that will be signed
optional arguments:
-h, --help show this help message and exit
--ssl-key CERT_PATH path to SSL certificate private key saved in PEM
format
-o SIGNATURE_PATH, --out SIGNATURE_PATH
path where generated signature will be saved
有什么方法可以不一次性 read()
整个文件吗?
到verify the created signature run (or alternatively implement verification using
pyOpenSSL
):openssl dgst -sha256 -verify cert_public_key_file.pub -signature cert_file.crt signed_file_path
如果您需要创建 SSL 证书来测试它,请参阅 this tutorial。
- 我知道有 similar questions on SO 但他们没有回答我的问题。
您必须实现自己的 chunked sign
功能。
但是收件人呢,它能验证吗?
Read about: EVP_DigestSignInit
EVP_DigestSignUpdate() hashes cnt bytes of data at d into the signature context ctx.
This function can be called several times on the same ctx to include additional data.
Adapt from def sign(pkey, data, digest):