网络编程
位置:首页>> 网络编程>> Python编程>> Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签

Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签

作者:mrr  发布时间:2022-12-10 13:55:18 

标签:python,pycryptodome,加密,解密

Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签,具体代码如下所示:


#!/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
 对应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):
   """ 验证签名
     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 对密码做了如下处理
   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:])]
 # 加密函数,如果text不足16位就用空格补足为16位,
 # 如果大于16当时不是16的倍数,那就补足为16的倍数。
 # 补足方法:PKCS5
 def encrypt(self, text):
   cryptor = AES.new(self.key, self.mode)
   # 这里密钥key 长度必须为16(AES-128),
   # 24(AES-192),或者32 (AES-256)Bytes 长度
   # 目前AES-128 足够目前使用
   ciphertext = cryptor.encrypt(self.pkcs5_pad(text.encode('utf8')))
   # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
   # 所以这里将加密的字符串进行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中国', 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加密解密加签验签示例代码

本代码引入Pycryptodome基于Python3.50版本编译库


#!/usr/bin/env python3
# coding=utf-8
# Author: Luosu201803
"""
create_rsa_key() - 创建RSA密钥
my_encrypt_and_decrypt() - 测试加密解密功能
rsa_sign() & rsa_signverify() - 测试签名与验签功能
"""
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"):
 """
 创建RSA密钥,步骤说明:
 1、从 Crypto.PublicKey 包中导入 RSA,创建一个密码(此密码不是RSA秘钥对)
 2、生成 1024/2048 位的 RSA 密钥对(存储在私钥文件和公钥文件)
 3、调用 RSA 密钥实例的 exportKey 方法(传入"密码"、"使用的 PKCS 标准"、"加密方案"这三个参数)得到私钥。
 4、将私钥写入磁盘的文件。
 5、使用方法链调用 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编码保存数据方便查看,同样解密需要base64解码
 en_data = base64.b64encode(cipher_rsa.encrypt(b"123456,abcdesd"))
 print("加密数据信息:",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):
 #读取公钥信息用于验签
 public_key = RSA.importKey(open("my_rsa_public.pem").read())
 #message做“哈希”处理,RSA签名这么要求的
 hash_obj = SHA1.new(message)
 try:
   #因为签名被base64编码,所以这里先解码,再验签
   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))

总结

以上所述是小编给大家介绍的Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

来源:https://gitee.com/leeyi/codes/iy39w07x6hc5b8uqm2oat31

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com