Привет, у меня старый устаревший код (python2), который создает файл подписи для дайджеста. (в моем случае этот дайджест всегда представляет собой строку из 40 символов, содержащую только 0-9a-f символов).
Использует m2crypto
У меня также есть функция, которая проверяет, совпадают ли дайджест и файл подписи.
Теперь я должен переопределить код подписи, используя криптографию вместо m2crypto (и позже переключиться на python3)
Однако полученная подпись должна быть проверена старым кодом m2crypto. (Код, выполняющий проверку, запускается на машинах.
что я не могу обновить сейчас, однако подпись должна быть перенесена в криптографию (и python3)
Прикрепленный У меня есть полный самоочевидный пример.
Я предполагаю, что проблема лежит где-то в заполнении, которое не идентично решению m2crypto и криптографии. но я не знаю, как поступить.
Старый код подписи:
def old_sign(digest):
import M2Crypto
rsa = M2Crypto.RSA.load_key("k.key")
return rsa.sign(digest, "sha1")
Код для проверки подписи:
def old_check_signature(digest, signature):
import M2Crypto
rsa = M2Crypto.RSA.load_pub_key("k.pub")
try:
rsa.verify(digest, signature, algo="sha1")
return True
except M2Crypto.RSA.RSAError as exc:
args = exc.args
if len(args) < 1:
raise
return False
Я не знаю, какой тип заполнения использовал m2crypto, и я не знаю всех возможных вариантов заполнения.
Я пробовал два разных дополнения с криптографией
Первая попытка:
def new_sign1(digest):
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
key_data = open("k.key").read()
key = serialization.load_pem_private_key(
key_data, password=None, backend=default_backend())
return key.sign(
digest,
padding.PSS(
mgf=padding.MGF1(hashes.SHA1()),
salt_length=padding.PSS.MAX_LENGTH,
),
hashes.SHA1())
вторая попытка
def new_sign2(digest):
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
key_data = open("k.key").read()
key = serialization.load_pem_private_key(
key_data, password=None, backend=default_backend())
return key.sign(digest, padding.PKCS1v15(), hashes.SHA1())
После отзыва Павла я тоже попробовал
def new_sign3(digest):
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.asymmetric import utils
key_data = open("k.key", "rb").read()
key = serialization.load_pem_private_key(
key_data, password=None, backend=default_backend())
return key.sign(
digest,
padding.PKCS1v15(),
utils.Prehashed(hashes.SHA1()),
)
, который не работает с
ValueError: The provided data must be the same length as the hash algorithm's digest size.
Следующий код может воспроизвести ошибку, если объявлены все вышеуказанные функции:
dig = "f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0"
sigs = [old_sign(dig), new_sign1(dig), new_sign2(dig)]
print([old_check_signature(dig, sig) for sig in sigs])
Выходные данные [True, False, False], что означает, что только подпись, созданная с помощью m2crypto, является правильной, и подписи, созданные с помощью криптографии, не могут быть проверены с помощью m2crypto.
Если вы хотите проверить код и у вас нет файла ключа и файла открытого ключа, вы можете использовать следующий фрагмент для его создания:
KEY = """
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAusZYCLS8RPUJ3fhod3cr2foK++t3R30Eiqstq+B5vIIrcJN1
2HnKfU1o3m9cwEJOezHxuI7Ks8/YVt/bGy6HyY4i3bk5AS9BK4gEptmUlldsvV+l
hOLel884dwhUk2ZrEpCq7YvSpMBb7ORKcUwcTu9tyuSHTlVpabYADTStebDWwp0+
heeRWN/zG5CN0zO4BScRNTpnw/TAqBTytuWgo/YFhBX6a4U3fKKASqynn5ZJYAg3
CDqdAe4BM2OZUv73UHWQsltC3xyKqsN6+gH7O7WoetxdMZsvYtEp4hvhUjgCrDSU
gSvtZD8BMxcPPO59w670DdVa3EPLWZzhGel18wIDAQABAoIBAB+DrAL8C/BOsDWF
3oqZzwpeiE/tcRjc3VFQhMpFfAT0qcO6/d1i32m5EALII4xFI9zhlnmfjlA8t7Ig
32V8umil1Pg4cofio0pnDvHgMJQVeEGTy+faJ9jRnCNpgmvEkjh1tIGUYBxwYJJe
CrmHMBeZipr7aGEtRDYUAXo48zRe+mO41ICkPeVRRSK0b5F9P7SOm+QnkN8rHmtm
MsCJ0jPJ1fG5Xi5BVVdjhQ6+S42tbm/A68Yx/uWSC3pt+ScIklgYF2owawVWDbWJ
Eekl0sNUTm1j1OlnyAEbb8R/VkYsLYfEwpgULTzkokBRq4NZxjCKY7VJRZ05neev
4JbdcOECgYEA46e+L/uvHUUzyhWgrNgHAdT7Eff4Imu7WdG+KQ7d7kNazMJFyMrk
1Ln66i/oPyiMwMXcACmEoA5Jl/wBk3sjKjLno9dvMM3amfwkBZav4FirQS+9Xk/l
EQAoc/WxsxlVywM00c20CgGqNu0hRBlM5C8zCoIFlt6G2Mwv58yd8hkCgYEA0geU
7FXh/xVnq4wU9bnTF0laPd4HlVYYNpRMjTdRwwIycrCynAlfEF+keUyOXhgYw5vm
loyICCqsNi5pw8tRPFyzBiESkLUL+ZTcfxswfgmhlTs71Zk72b8LCM3sRPeuUg2a
6GrNvycWRLfc+toq5NvSKnfVQS2tgMKJ0CtPIesCgYB+Za0H8SKaCsklY3qxXMQP
NVQs9tOTMON1jCmbnECGQGlSlG6wfE4u+g+hJPY60uXLRk/O2z5iq2wa8XVikBTH
IjpQUpXOsAy2QDMz0yVVV4XGDJ6ElbFmDgNn1rtR6DglHmOeNSrH/4KlOmWk7LMv
YjFhnS1DRcvy5POYLJhpSQKBgEILIEkwuF/92xuWcQDT7gzkg/vwVXIgIH0JJQlC
2/L2PebSqVdnmv0LFi0OZbYw3Zik7V1p01y+Dmj7L0biKClS/PhwbeYTCDDzHmLZ
qeX4IVdLyQThqnBOIqoiFqmZOLeUj6GF9Cynndj99/7pm5NbjDrOc8CLHIPgqHVN
KRUBAoGBAKEr1mg+Hjf+M/5ru1tQT6xTvlKW1rS4ioGB35XQf+n/OAO98SPQkwPQ
XfX5nKHif/TmDZygGeHYm96qCceOmzCL7LqaYOb1qTZLEk6L18eEtHwG+hXyMKuA
t2XLK89blAoPT+9x10KKp27IWe/W+QCD6LnrdjoN9BQ7fCnV5v3Q
-----END RSA PRIVATE KEY-----
"""
open("k.key", "w").write(KEY)
PUB_KEY = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAusZYCLS8RPUJ3fhod3cr
2foK++t3R30Eiqstq+B5vIIrcJN12HnKfU1o3m9cwEJOezHxuI7Ks8/YVt/bGy6H
yY4i3bk5AS9BK4gEptmUlldsvV+lhOLel884dwhUk2ZrEpCq7YvSpMBb7ORKcUwc
Tu9tyuSHTlVpabYADTStebDWwp0+heeRWN/zG5CN0zO4BScRNTpnw/TAqBTytuWg
o/YFhBX6a4U3fKKASqynn5ZJYAg3CDqdAe4BM2OZUv73UHWQsltC3xyKqsN6+gH7
O7WoetxdMZsvYtEp4hvhUjgCrDSUgSvtZD8BMxcPPO59w670DdVa3EPLWZzhGel1
8wIDAQAB
-----END PUBLIC KEY-----
"""
open("k.pub", "w").write(PUB_KEY)
Заранее спасибо за любые предложения.
Я не так часто использую,
У меня также есть полноценный файл Python (102 строки), который полностью автономен. Как поделиться такими файлами на SO в вопросе
Приложение 2019-06-13 23:15:00 UTC
Кажется. что M2Crypto.RSA.sign ()
вызывает, наконец, следующий C-код. (из репозитория m2crypto git в файле SWIG/_m2crypto_wrap.c
.
Я не очень хорошо разбираюсь в libssl, но, возможно, кто-то другой понимает это
и может рассказать мне, как «воспроизвести расчет» (возможно, с помощью командной строки openssl или ctypes) без использования M2Crypto.
PyObject *rsa_sign(RSA *rsa, PyObject *py_digest_string, int method_type) {
int digest_len = 0;
int buf_len = 0;
int ret = 0;
unsigned int real_buf_len = 0;
char *digest_string = NULL;
unsigned char * sign_buf = NULL;
PyObject *signature;
ret = m2_PyString_AsStringAndSizeInt(py_digest_string, &digest_string,
&digest_len);
if (ret == -1) {
/* PyString_AsStringAndSize raises the correct exceptions. */
return NULL;
}
buf_len = RSA_size(rsa);
sign_buf = (unsigned char *)PyMem_Malloc(buf_len);
ret = RSA_sign(method_type, (const unsigned char *)digest_string, digest_len,
sign_buf, &real_buf_len, rsa);
if (!ret) {
m2_PyErr_Msg(_rsa_err);
PyMem_Free(sign_buf);
return NULL;
}
signature = PyBytes_FromStringAndSize((const char*) sign_buf, buf_len);
PyMem_Free(sign_buf);
return signature;
}
Обходной путь с использованием subprocess.Popen или ctypes (непосредственно атакующий libssl) является (в моем контексте) приемлемым.