python有認證的加密解密實現方法_python

來源:互聯網
上載者:User

本文執行個體講述了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://www.jb51.net)的簽名串')
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://www.jb51.net)的簽名串')
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程式設計有所協助。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.