Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将旧python代码从m2crypto迁移到加密(摘要的RSA签名)_Python_Cryptography_M2crypto - Fatal编程技术网

如何将旧python代码从m2crypto迁移到加密(摘要的RSA签名)

如何将旧python代码从m2crypto迁移到加密(摘要的RSA签名),python,cryptography,m2crypto,Python,Cryptography,M2crypto,嗨,我有一个旧的遗留代码(python2),它为摘要创建了一个签名文件。(在我的例子中,这个摘要总是一个40个字符的字符串,只有0-9a-f个字符) 它使用m2crypto 我还有一个函数,用于验证摘要和签名文件是否匹配 现在我必须使用加密技术而不是m2crypto重新实现签名代码(并切换到python3 lateron) 但是,生成的签名必须使用旧的m2crypto代码进行验证。(执行验证的代码在机器上运行。 我现在无法更新,但签名必须迁移到加密(和python3) 附件我有一个完整的自我解释

嗨,我有一个旧的遗留代码(python2),它为摘要创建了一个签名文件。(在我的例子中,这个摘要总是一个40个字符的字符串,只有0-9a-f个字符)

它使用m2crypto

我还有一个函数,用于验证摘要和签名文件是否匹配

现在我必须使用加密技术而不是m2crypto重新实现签名代码(并切换到python3 lateron) 但是,生成的签名必须使用旧的m2crypto代码进行验证。(执行验证的代码在机器上运行。 我现在无法更新,但签名必须迁移到加密(和python3)

附件我有一个完整的自我解释的例子。 我想问题在于填充,这与m2crypto和cryptography解决方案不同。但我不知道如何继续

旧的签名代码是:

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
第二次尝试

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())


在Paul的反馈之后,我也尝试了

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:提供的数据长度必须与哈希算法的摘要大小相同。

如果声明了上述所有函数,则以下代码可能会重现错误:

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行),它是完全独立的

附录2019-06-13 23:15:00 UTC 似乎是这样的。M2Crypto.RSA.sign()

最后调用下面的C代码。(来自文件
SWIG/\u m2crypto\u wrap.C
中的m2crypto git存储库)

我对libssl不是很在行,但也许其他人理解这一点 并且可以告诉我如何在不使用M2Crypto的情况下“重现计算”(可能使用openssl命令行或ctypes)

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)的解决方法(在我的上下文中)是可以接受的。

M2Crypto在调用
符号时可能使用PKCS1填充,因此PKCS1v15示例与您想要的非常接近。假设它默认为PKCS1(而不是没有填充,这是非常不安全的,
加密技术不支持)那么摘要可能就是问题所在


digest
是否已经是您想要签名的散列,还是要散列的数据?默认情况下,加密会为您散列提供的数据。如果数据已经散列,则需要使用以避免该步骤。

Paul,我已经尝试过类似的方法,但也遇到了问题。我的示例中的摘要是一个类似于:dig的字符串=b“f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0”如果我使用:
return key.sign(digest,padding.PKCS1v15(),utils.Prehashed(hashes.SHA1()),)
我得到以下错误:ValueError:提供的数据必须与哈希算法的摘要大小相同。示例中的摘要以十六进制编码,需要解码为二进制以用于预灰化。
binascii.unhexlify()
将为您提供。是的,我可以这样做,并会尝试,但我怀疑签名是否与现有的m2crypto代码兼容
旧签名()
,目前在不同的机器上使用,并尝试验证签名。整个目标是使代码与当前现有解决方案互操作,其签名与旧的\u check\u签名()验证我认为要具体回答这种可能性,您需要确定M2Crypto的rsa.sign在默认情况下的功能。如果它是未添加的rsa,则加密不支持该功能,但您应该立即修复它,因为这是一个重大的安全问题。同意主要问题是M2Crypto正在做什么(我没有找到有关它的详细信息)看看加密技术是否也能做到这一点。对于未来的版本(只要我能更新所有主机,验证签名和主机签名),我肯定会使用更智能/更安全的填充…,等等。谢谢。不管我怎么做:我不会用任何其他代码获得相同的签名(到目前为止,我尝试了加密和命令行openssl rsautl-sign)我认为原始代码有点缺陷,但这就是目前在某些机器上使用的代码。我将尝试更多的东西,但最终我可能会放弃使用不带m2crypto的中间代码,它可以创建这些旧签名,然后切换到新签名和新签名验证算法。这只会使部署变得更容易升级和更新稍微复杂一点。SHA-1 vs SHA-256?OpenSSL在几年前更改了默认设置。但是Mcrypt太旧了,很可能使用SHA-1。m2crypto使用SHA-1,而我没有找到任何命令行版本,这会产生相同的结果。您可以查看我发布到pastebin的代码,看看您是否发现了错误ny命令行版本给出了相同的结果,如果您查看其调用的源代码,它将调用
RSA\u private\u encrypt
。它不消化消息,也不格式化消息。您可以使用
openssl digest
使用SHA-256进行签名,并将其传输到
rsautil
。我不知道如何使用类似PKCS的填充来格式化消息#但是,我相信您使用了另一个实用程序(我再也跟不上OpenSSL实用程序了)。
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;
}