Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加簽驗(yàn)簽
Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加簽驗(yàn)簽,具體代碼如下所示:
#!/usr/bin/env python # -*- coding: utf8 -*- import os import rsa import json import hashlib import base64 from Crypto.Cipher import AES from ..settings_manager import settings class RSAEncrypter(object): """RSA加密解密 參考 https://stuvel.eu/python-rsa-doc/index.html 對(duì)應(yīng)JavaScript版本參考 https://github.com/travist/jsencrypt [description] """ @classmethod def encrypt(cls, plaintext, keydata): #明文編碼格式 content = plaintext.encode('utf8') if os.path.isfile(keydata): with open(keydata) as publicfile: keydata = publicfile.read() pubkey = rsa.PublicKey.load_pkcs1_openssl_pem(keydata) #公鑰加密 crypto = rsa.encrypt(content, pubkey) return base64.b64encode(crypto).decode('utf8') @classmethod def decrypt(cls, ciphertext, keydata): if os.path.isfile(keydata): with open(keydata) as privatefile: keydata = privatefile.read() try: ciphertext = base64.b64decode(ciphertext) privkey = rsa.PrivateKey.load_pkcs1(keydata, format='PEM') con = rsa.decrypt(ciphertext, privkey) return con.decode('utf8') except Exception as e: pass return False @classmethod def signing(cls, message, privkey): """ 簽名 https://legrandin.github.io/pycryptodome/Doc/3.2/Crypto.Signature.pkcs1_15-module.html """ from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA if os.path.isfile(privkey): with open(privkey) as privatefile: privkey = privatefile.read() try: key = RSA.import_key(privkey) h = SHA256.new(message.encode('utf8')) sign = pkcs1_15.new(key).sign(h) sign = base64.b64encode(sign).decode('utf8') return sign except Exception as e: raise e @classmethod def verify(cls, message, sign, pubkey): """ 驗(yàn)證簽名 https://legrandin.github.io/pycryptodome/Doc/3.2/Crypto.Signature.pkcs1_15-module.html """ from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA res = False sign = base64.b64decode(sign) # print('sign', type(sign), sign) try: key = RSA.importKey(pubkey) h = SHA256.new(message.encode('utf8')) pkcs1_15.new(key).verify(h, sign) res = True except (ValueError, TypeError) as e: raise e pass except Exception as e: raise e pass return res class AESEncrypter(object): def __init__(self, key, iv=None): self.key = key.encode('utf8') self.iv = iv if iv else bytes(key[0:16], 'utf8') def _pad(self, text): text_length = len(text) padding_len = AES.block_size - int(text_length % AES.block_size) if padding_len == 0: padding_len = AES.block_size t2 = chr(padding_len) * padding_len t2 = t2.encode('utf8') # print('text ', type(text), text) # print('t2 ', type(t2), t2) t3 = text + t2 return t3 def _unpad(self, text): pad = ord(text[-1]) return text[:-pad] def encrypt(self, raw): raw = raw.encode('utf8') raw = self._pad(raw) cipher = AES.new(self.key, AES.MODE_CBC, self.iv) encrypted = cipher.encrypt(raw) return base64.b64encode(encrypted).decode('utf8') def decrypt(self, enc): enc = enc.encode('utf8') enc = base64.b64decode(enc) cipher = AES.new(self.key, AES.MODE_CBC, self.iv) decrypted = cipher.decrypt(enc) return self._unpad(decrypted.decode('utf8')) class AESSkyPay: """ Tested under Python 3.7 and pycryptodome """ BLOCK_SIZE = 16 def __init__(self, key): #菲律賓支付通道 SkyPay Payment Specification.lending.v1.16.pdf # SkyPay 對(duì)密碼做了如下處理 s1 = hashlib.sha1(bytes(key, encoding='utf-8')).digest() s2 = hashlib.sha1(s1).digest() self.key = s2[0:16] self.mode = AES.MODE_ECB def pkcs5_pad(self,s): """ padding to blocksize according to PKCS #5 calculates the number of missing chars to BLOCK_SIZE and pads with ord(number of missing chars) @see: http://www.di-mgt.com.au/cryptopad.html @param s: string to pad @type s: string @rtype: string """ BS = self.BLOCK_SIZE return s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode('utf8') def pkcs5_unpad(self,s): """ unpadding according to PKCS #5 @param s: string to unpad @type s: string @rtype: string """ return s[:-ord(s[len(s) - 1:])] # 加密函數(shù),如果text不足16位就用空格補(bǔ)足為16位, # 如果大于16當(dāng)時(shí)不是16的倍數(shù),那就補(bǔ)足為16的倍數(shù)。 # 補(bǔ)足方法:PKCS5 def encrypt(self, text): cryptor = AES.new(self.key, self.mode) # 這里密鑰key 長(zhǎng)度必須為16(AES-128), # 24(AES-192),或者32 (AES-256)Bytes 長(zhǎng)度 # 目前AES-128 足夠目前使用 ciphertext = cryptor.encrypt(self.pkcs5_pad(text.encode('utf8'))) # 因?yàn)锳ES加密時(shí)候得到的字符串不一定是ascii字符集的,輸出到終端或者保存時(shí)候可能存在問題 # 所以這里將加密的字符串進(jìn)行base64編碼 return base64.b64encode(ciphertext).decode() def decrypt(self, text): cryptor = AES.new(self.key, self.mode) plain_text = cryptor.decrypt(base64.b64decode(text)) return bytes.decode(self.pkcs5_unpad(plain_text)) def aes_decrypt(ciphertext, secret=None, prefix='aes:::'): secret = secret if secret else settings.default_aes_secret cipher = AESEncrypter(secret) prefix_len = len(prefix) if ciphertext[0:prefix_len]==prefix: return cipher.decrypt(ciphertext[prefix_len:]) else: return ciphertext def aes_encrypt(plaintext, secret=None, prefix='aes:::'): secret = secret if secret else settings.default_aes_secret cipher = AESEncrypter(secret) encrypted = cipher.encrypt(plaintext) return '%s%s' % (prefix, encrypted) if __name__ == "__main__": try: # for RSA test ciphertext = 'Qa2EU2EF4Eq4w75TnA1IUw+ir9l/nSdW3pMV+a6FkzV9bld259DxM1M4RxYkpPaVXhQFol04yFjuxzkRg12e76i6pkDM1itQSOy5hwmrud5PQvfnBf7OmHpOpS6oh6OQo72CA0LEzas+OANmRXKfn5CMN14GsmfWAn/F6j4Azhs=' public_key = '/Users/leeyi/workspace/joywin_staff/joywin_staff_api/datas/public.pem' private_key = '/Users/leeyi/workspace/joywin_staff/joywin_staff_api/datas/private.pem' ciphertext = RSAEncrypter.encrypt('admin888中國(guó)', public_key) print("ciphertext: ", ciphertext) plaintext = RSAEncrypter.decrypt(ciphertext, private_key) print("plaintext: ", type(plaintext)) print("plaintext: ", plaintext) # for AES test key = 'abc20304050607081q2w3e4r*1K|j!ta' cipher = AESEncrypter(key) plaintext = '542#1504' encrypted = cipher.encrypt(plaintext) print('Encrypted: %s' % encrypted) ciphertext = 'EPLtushldq9E1U8vG/sL3g==' assert encrypted == ciphertext plaintext = '542#1504你好' encrypted = '+YGDvnakKi77SBD6GXmThw==' decrypted = cipher.decrypt(encrypted) print('Decrypted: %s' % decrypted) assert decrypted == plaintext except KeyboardInterrupt: sys.exit(0)
ps:Python3 RSA加密解密加簽驗(yàn)簽示例代碼
本代碼引入Pycryptodome基于Python3.50版本編譯庫(kù)
#!/usr/bin/env python3 # coding=utf-8 # Author: Luosu201803 """ create_rsa_key() - 創(chuàng)建RSA密鑰 my_encrypt_and_decrypt() - 測(cè)試加密解密功能 rsa_sign() & rsa_signverify() - 測(cè)試簽名與驗(yàn)簽功能 """ from binascii import unhexlify from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP, PKCS1_v1_5 import base64 from Crypto.Hash import SHA1 from Crypto.Signature import pkcs1_15 def create_rsa_key(password="123456"): """ 創(chuàng)建RSA密鑰,步驟說明: 1、從 Crypto.PublicKey 包中導(dǎo)入 RSA,創(chuàng)建一個(gè)密碼(此密碼不是RSA秘鑰對(duì)) 2、生成 1024/2048 位的 RSA 密鑰對(duì)(存儲(chǔ)在私鑰文件和公鑰文件) 3、調(diào)用 RSA 密鑰實(shí)例的 exportKey 方法(傳入"密碼"、"使用的 PKCS 標(biāo)準(zhǔn)"、"加密方案"這三個(gè)參數(shù))得到私鑰。 4、將私鑰寫入磁盤的文件。 5、使用方法鏈調(diào)用 publickey 和 exportKey 方法生成公鑰,寫入磁盤上的文件。 """ key = RSA.generate(1024) encrypted_key = key.exportKey(passphrase=password, pkcs=8,protection="scryptAndAES128-CBC") # encrypted_key = key.exportKey(pkcs=1) print('encrypted_key:',encrypted_key) with open("my_private_rsa_key.pem", "wb") as f: f.write(encrypted_key) with open("my_rsa_public.pem", "wb") as f: f.write(key.publickey().exportKey()) def encrypt_and_decrypt_test(password="123456"): # 加載私鑰用于加密 recipient_key = RSA.import_key( open("my_rsa_public.pem").read() ) cipher_rsa = PKCS1_v1_5.new(recipient_key) #使用base64編碼保存數(shù)據(jù)方便查看,同樣解密需要base64解碼 en_data = base64.b64encode(cipher_rsa.encrypt(b"123456,abcdesd")) print("加密數(shù)據(jù)信息:",type(en_data),'\n',len(en_data),'\n',en_data) # 加載公鑰用于解密 encoded_key = open("my_private_rsa_key.pem").read() private_key = RSA.import_key(encoded_key,passphrase=password) cipher_rsa = PKCS1_v1_5.new(private_key) data = cipher_rsa.decrypt(base64.b64decode(en_data), None) print(data) def rsa_sign(message,password="123456"): #讀取私鑰信息用于加簽 private_key = RSA.importKey(open("my_private_rsa_key.pem").read(),passphrase=password) hash_obj = SHA1.new(message) # print(pkcs1_15.new(private_key).can_sign()) #check wheather object of pkcs1_15 can be signed #base64編碼打印可視化 signature = base64.b64encode(pkcs1_15.new(private_key).sign(hash_obj)) return signature def rsa_signverify(message,signature): #讀取公鑰信息用于驗(yàn)簽 public_key = RSA.importKey(open("my_rsa_public.pem").read()) #message做“哈希”處理,RSA簽名這么要求的 hash_obj = SHA1.new(message) try: #因?yàn)楹灻籦ase64編碼,所以這里先解碼,再驗(yàn)簽 pkcs1_15.new(public_key).verify(hash_obj,base64.b64decode(signature)) print('The signature is valid.') return True except (ValueError,TypeError): print('The signature is invalid.') if __name__ == '__main__': # create_rsa_key() encrypt_and_decrypt_test() # message = b'Luosu is a Middle-aged uncle.' # signature = rsa_sign(message) # print('signature:',signature) # print(rsa_signverify(message,signature))
總結(jié)
以上所述是小編給大家介紹的Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加簽驗(yàn)簽,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
如何利用python寫GUI及生成.exe可執(zhí)行文件
工作中需要開發(fā)一個(gè)小工具,簡(jiǎn)單的UI界面可以很好的提高工具的實(shí)用性,由此開啟了我的第一次GUI開發(fā)之旅,這篇文章主要給大家介紹了關(guān)于如何利用python寫GUI及生成.exe可執(zhí)行文件的相關(guān)資料,需要的朋友可以參考下2021-12-12windows中python實(shí)現(xiàn)自動(dòng)化部署
本文主要介紹了windows中python實(shí)現(xiàn)自動(dòng)化部署,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Python實(shí)現(xiàn)線程池工作模式的案例詳解
這篇文章給大家介紹Python實(shí)現(xiàn)線程池工作模式的相關(guān)知識(shí),本文基于Socket通信方法,自定義數(shù)據(jù)交換協(xié)議,圍繞蘋果樹病蟲害識(shí)別需求,迭代構(gòu)建了客戶機(jī)/服務(wù)器模式的智能桌面App,感興趣的朋友跟隨小編一起看看吧2022-06-06淺談Python2、Python3相對(duì)路徑、絕對(duì)路徑導(dǎo)入方法
今天小編就為大家分享一篇淺談Python2、Python3相對(duì)路徑、絕對(duì)路徑導(dǎo)入方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-06-06Python實(shí)現(xiàn)將元組中的元素作為參數(shù)傳入函數(shù)的操作
這篇文章主要介紹了Python實(shí)現(xiàn)將元組中的元素作為參數(shù)傳入函數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06