当前位置 博文首页 > python有证书的加密解密实现方法

    python有证书的加密解密实现方法

    作者:admin 时间:2021-07-17 18:40

    本文实例讲述了python有证书的加密解密实现方法。分享给大家供大家参考。具体实现方法如下:

    最近在做python的加解密工作,同时加完密的串能在php上能解出来,网上也找了一些靠谱的资料,刚好也有时间我就总结了一下python在加密与解密这块的代码,今后可能还能用的上。相对于php而言python这块加解密组件较多的,分别是:

    python-crypto - 这个组件是基本组件,使用的函式相对比较复杂。
    ezPyCrypto - 相对简单,但他作出来的公私钥无法与其他程序相兼容     SSLCrypto - 与 ezPyCrypto 是相同一个作者开发,效率上要比ezPyCrypto 好。但一样不能与其它程序相兼容。
    pyopenssl - 似乎是用在https 通讯上的,而我找不到加解密的用法。
    M2Crypto - 终于让我找到了,但它有一大缺点,它底层是用 SWIG 与 OpenSSL 交接的。
    在Windows安装SWIG 程序是非常难的。

    我选择使用的是M2Crypto,公钥与私钥证书生成有两个方式,一种采用RSA生成,另一种是X509生成。我就把这两种加解密代码分享出来,供大家参考,但转载或使用时请写明出处。

    一、 RSA标准方式生成的证书

    1.加密解密、加密签名、验证加密签名

    复制代码 代码如下:
    #encoding: utf8
    import os
    import M2Crypto
    #随机数生成器(1024位随机)
    M2Crypto.Rand.rand_seed(os.urandom(1024))
    #生成一个1024位公钥与私密钥证书
    Geekso = M2Crypto.RSA.gen_key(1024, 65537)
    Geekso.save_key('jb51.net-private.pem', None)
    Geekso.save_pub_key('jb51.net-public.pem')
    #使用公钥证书加密开始
    WriteRSA = M2Crypto.RSA.load_pub_key('jb51.net-public.pem')
    CipherText = WriteRSA.public_encrypt("这是一个秘密消息,只能用私钥进行解密",M2Crypto.RSA.pkcs1_oaep_padding)
    print "加密的串是:"
    print CipherText.encode('base64')
    #对加密串进行签名
    MsgDigest = M2Crypto.EVP.MessageDigest('sha1')
    MsgDigest.update(CipherText)
    #提示,这里也可以使用私钥签名
    #WriteRSA = M2Crypto.RSA.load_key ('jb51.net-private.pem')
    #Signature = WriteRSA.sign_rsassa_pss(MsgDigest.digest())
    Signature = Geekso.sign_rsassa_pss(MsgDigest.digest())
    print "签名的串是:"
    print Signature.encode('base64')
    #使用私钥证书解密开始
    ReadRSA = M2Crypto.RSA.load_key ('jb51.net-private.pem')
    try:
        PlainText = ReadRSA.private_decrypt (CipherText, M2Crypto.RSA.pkcs1_oaep_padding)
    except:
        print "解密错误"
        PlainText = ""
    if PlainText :
       print "解密出来的串是:"
       print PlainText
       # 验证加密串的签名
       MsgDigest = M2Crypto.EVP.MessageDigest('sha1')
       MsgDigest.update(CipherText)
       #提示,如果是用私钥签名的那就用公钥验证
       #VerifyRSA = M2Crypto.RSA.load_pub_key('Alice-public.pem')
       #VerifyRSA.verify_rsassa_pss(MsgDigest.digest(), Signature)
       if Geekso.verify_rsassa_pss(MsgDigest.digest(), Signature) == 1:
           print "签名正确"
       else:
           print "签名不正确"

    2.字符串生成签名、验证签名

    复制代码 代码如下:
    #用私钥签名
    SignEVP = M2Crypto.EVP.load_key('jb51.net-private.pem')
    SignEVP.sign_init()
    SignEVP.sign_update('来自这一客(http://blog.iis7.com)的签名串')
    StringSignature = SignEVP.sign_final()
    print "签名串是:"
    print StringSignature.encode('base64')
    #用公钥验证签名
    PubKey = M2Crypto.RSA.load_pub_key('jb51.net-public.pem')
    VerifyEVP = M2Crypto.EVP.PKey()
    VerifyEVP.assign_rsa(PubKey)
    VerifyEVP.verify_init()
    VerifyEVP.verify_update('来自这一客(http://blog.iis7.com)的签名串')
    if VerifyEVP.verify_final(StringSignature) == 1:
        print "字符串被成功验证。"
    else:
        print "字符串验证失败!"

    3.给证书加上密码

    给证书加密码的好处是即使证书被人拿了,没有密码也用不了。

    复制代码 代码如下:
    def passphrase(v):
        return '4567890'

    生成证书时用
    复制代码 代码如下:
    Geekso.save_key('jb51.net-private.pem',callback=passphrase)

    使用证书时用
    复制代码 代码如下:
    ReadRSA = RSA.load_key ('jb51.net-private.pem', passphrase)

    二、 X509标准方式生成的证书

    1.生成证书、公钥文件、私钥文件

    复制代码 代码如下:
    import time
    from M2Crypto import X509, EVP, RSA, ASN1
    def issuer_name():
        """
        证书发行人名称(专有名称)。
        Parameters:
            none
        Return:
            X509标准的发行人obj.
        """
        issuer = X509.X509_Name()
        issuer.C = "CN"                # 国家名称
        issuer.CN = "*.jb51.net"       # 普通名字
        issuer.ST = "Hunan Changsha"
        issuer.L = "Hunan Changsha"
        issuer.O = "Geekso Company Ltd"
        issuer.OU = "Geekso Company Ltd"
        issuer.Email = "123456@qq.com"
        return issuer
    def make_request(bits, cn):
        """
        创建一个X509标准的请求。
        Parameters:
            bits = 证书位数
            cn = 证书名称
        Return:
            返回 X509 request 与 private key (EVP).
        """
        rsa = RSA.gen_key(bits, 65537, None)
        pk = EVP.PKey()
        pk.assign_rsa(rsa)
        req = X509.Request()
        req.set_pubkey(pk)
        name = req.get_subject()
        name.C = "US"
        name.CN = cn
        req.sign(pk,'sha256')
        return req, pk
    def make_certificate_valid_time(cert, days):
        """
        从当前时间算起证书有效期几天。
        Parameters:
            cert = 证书obj
            days = 证书过期的天数
        Return:
            none
        """
        t = long(time.time()) # 获取当前时间
        time_now = ASN1.ASN1_UTCTIME()
        time_now.set_time(t)
        time_exp = ASN1.ASN1_UTCTIME()
        time_exp.set_time(t + days * 24 * 60 * 60)
        cert.set_not_before(time_now)
        cert.set_not_after(time_exp)
    def make_certificate(bits):
        """
        创建证书
        Parameters:
            bits = 证快的位数
        Return:
            证书, 私钥 key (EVP) 与 公钥 key (EVP).
        """
        req, pk = make_request(bits, "localhost")
        puk = req.get_pubkey()
        cert = X509.X509()
        cert.set_serial_number(1) # 证书的序例号
        cert.set_version(1) # 证书的版本
        cert.set_issuer(issuer_name()) # 发行人信息
        cert.set_subject(issuer_name()) # 主题信息
        cert.set_pubkey(puk)
        make_certificate_valid_time(cert, 365) # 证书的过期时间
        cert.sign(pk, 'sha256')
        return cert, pk, puk
    # 开始创建
    cert, pk, puk= make_certificate(1024)
    cert.save_pem('jb51.net-cret.pem')
    pk.save_key('jb51.net-private.pem',cipher = None, callback = lambda: None)
    puk.get_rsa().save_pub_key('jb51.net-public.pem')

    2.用证书加密、私钥文件解密

    复制代码 代码如下:
    def geekso_encrypt_with_certificate(message, cert_loc):
        """
        cert证书加密,可以用私钥文件解密.
        Parameters:
            message = 要加密的串
            cert_loc = cert证书路径
        Return:
            加密串 or 异常串
        """
        cert = X509.load_cert(cert_loc)
        puk = cert.get_pubkey().get_rsa() # get RSA for encryption
        message = base64.b64encode(message)
        try:
            encrypted = puk.public_encrypt(message, RSA.pkcs1_padding)
        except RSA.RSAError as e:
            return "ERROR encrypting " + e.message
        return encrypted
    encrypted = geekso_encrypt_with_certificate('www.jb51.net','jb51.net-cret.pem')
    print '加密串',encrypted
    def geekso_decrypt_with_private_key(message, pk_loc):
        """
        私钥解密证书生成的加密串
        Parameters:
            message = 加密的串
            pk_loc = 私钥路径
        Return:
            解密串 or 异常串
        """
        pk = RSA.load_key(pk_loc) # load RSA for decryption
        try:
            decrypted = pk.private_decrypt(message, RSA.pkcs1_padding)
            decrypted = base64.b64decode(decrypted)
        except RSA.RSAError as e:
            return "ERROR decrypting " + e.message
        return decrypted
    print '解密串',geekso_decrypt_with_private_key(encrypted, 'jb51.net-private.pem')

    3.用私钥加密、证书解密

    复制代码 代码如下:
    def geekso_encrypt_with_private_key(message,pk_loc):
        """
        私钥加密
        Parameters:
            message = 加密的串
            pk_loc = 私钥路径
        Return:
            加密串 or 异常串
        """
        ReadRSA = RSA.load_key(pk_loc);
        message = base64.b64encode(message)
        try:
            encrypted = ReadRSA.private_encrypt(message,RSA.pkcs1_padding)
        except RSA.RSAError as e:
            return "ERROR encrypting " + e.message
        return encrypted
    encrypted = geekso_encrypt_with_private_key('www.jb51.net', 'jb51.net-private.pem')
    print encrypted
    def geekso_decrypt_with_certificate(message, cert_loc):
        """
        cert证书解密.
        Parameters:
            message = 要解密的串
            cert_loc = cert证书路径
        Return:
            解密后的串 or 异常串
        """
        cert = X509.load_cert(cert_loc)
        puk = cert.get_pubkey().get_rsa()
        try:
            decrypting = puk.public_decrypt(message, RSA.pkcs1_padding)
            decrypting = base64.b64decode(decrypting)
        except RSA.RSAError as e:
            return "ERROR decrypting " + e.message
        return decrypting
    decrypting = geekso_decrypt_with_certificate(encrypted, 'jb51.net-cret.pem')
    print decrypting

    4.用私钥签名、证书验证签名

    复制代码 代码如下:
    def geekso_sign_with_private_key(message, pk_loc, base64 = True):
        """
        私钥签名
        Parameters:
            message = 待签名的串
            pk_loc = 私钥路径
            base64 = True(bease64处理) False(16进制处理)
        Return:
            签名后的串 or 异常串
        """
        pk = EVP.load_key(pk_loc)
        pk.sign_init()
        try:
            pk.sign_update(message)
            signature = pk.sign_final()
        except EVP.EVPError as e:
            return "ERROR signature " + e.message
        return signature.encode('base64') if base64 is True else signature.encode('hex')
    signature = geekso_sign_with_private_key('www.jb51.net','jb51.net-private.pem')
    print signature
    def geekso_verifysign_with_certificate(message, signature, cert_loc, base64 = True):
        """
        证书验证签名
        Parameters:
            message = 原来签名的串
            signature = 签名后的串
            cert_loc = 证书路径文件
            base64 = True(bease64处理) False(16进制处理)
        Return:
            成功or失败串 or 异常串
        """
        signature = signature.decode('base64') if base64 is True else signature.decode('hex')
        cert = X509.load_cert(cert_loc)
        puk = cert.get_pubkey().get_rsa()
        try:
            verifyEVP = EVP.PKey()
            verifyEVP.assign_rsa(puk)
            verifyEVP.verify_init()
            verifyEVP.verify_update(message)
            verifysign = verifyEVP.verify_final(signature)
            if verifysign == 1 :
                return '成功'
            else :
                return '失败'
        except EVP.EVPError as e:
            return "ERROR Verify Sign " + e.message
       
    print geekso_verifysign_with_certificate('www.jb51.net', signature, 'jb51.net-cret.pem')

    希望本文所述对大家的Python程序设计有所帮助。

    jsjbwy