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


Posted in Python onDecember 04, 2019

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加密解密、加签验签,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
zbar解码二维码和条形码示例
Feb 07 Python
Python之csv文件从MySQL数据库导入导出的方法
Jun 21 Python
scikit-learn线性回归,多元回归,多项式回归的实现
Aug 29 Python
python动态视频下载器的实现方法
Sep 16 Python
python实现上传文件到linux指定目录的方法
Jan 03 Python
python 使用递归实现打印一个数字的每一位示例
Feb 27 Python
Python3标准库之threading进程中管理并发操作方法
Mar 30 Python
解决keras backend 越跑越慢问题
Jun 18 Python
如何一键升级Python所有包
Nov 05 Python
python多线程和多进程关系详解
Dec 14 Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
Mar 01 Python
Python爬虫基础之简单说一下scrapy的框架结构
Jun 26 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
Dec 04 #Python
Python绘制二维曲线的日常应用详解
Dec 04 #Python
使用python远程操作linux过程解析
Dec 04 #Python
基于Python检测动态物体颜色过程解析
Dec 04 #Python
如何用OpenCV -python3实现视频物体追踪
Dec 04 #Python
Python绘制三角函数图(sin\cos\tan)并标注特定范围的例子
Dec 04 #Python
python 画函数曲线示例
Dec 04 #Python
You might like
php获取网页请求状态程序示例
2014/06/17 PHP
PHP 获取ip地址代码汇总
2015/07/05 PHP
SAE实时日志接口SDK用法示例
2016/10/09 PHP
解决jquery submit()提交表单提示:f[s] is not a function
2013/01/23 Javascript
JavaScript中的对象的extensible属性介绍
2014/12/30 Javascript
谈谈对offsetleft兼容性的理解
2015/11/11 Javascript
去除html代码里面的script正则方法
2016/05/19 Javascript
限制复选框最多选择项的实现代码
2016/05/30 Javascript
Javascript中从学习bind到实现bind的过程
2018/01/05 Javascript
vue-cli实现多页面多路由的示例代码
2018/01/30 Javascript
Mac下安装vue
2018/04/11 Javascript
vue在手机中通过本机IP地址访问webApp的方法
2018/08/15 Javascript
Vue实现表格中对数据进行转换、处理的方法
2018/09/06 Javascript
JS异步错误捕获的一些事小结
2019/04/26 Javascript
vue-cli在 history模式下的配置详解
2019/11/26 Javascript
[49:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 KG VS TNC
2018/03/31 DOTA
python reduce 函数使用详解
2017/12/05 Python
python实现Floyd算法
2018/01/03 Python
Python3对称加密算法AES、DES3实例详解
2018/12/06 Python
Python对象与引用的介绍
2019/01/24 Python
python面向对象实现名片管理系统文件版
2019/04/26 Python
python tkinter组件使用详解
2019/09/16 Python
TensorFlow实现打印每一层的输出
2020/01/21 Python
PyQt5中QTableWidget如何弹出菜单的示例代码
2020/02/23 Python
Python网页解析器使用实例详解
2020/05/30 Python
Python爬虫headers处理及网络超时问题解决方案
2020/06/19 Python
Python 实现微信自动回复的方法
2020/09/11 Python
Jupyter安装拓展nbextensions及解决官网下载慢的问题
2021/03/03 Python
Html5实现iPhone开机界面示例代码
2013/06/30 HTML / CSS
美国学校校服,儿童和婴儿服装:Cookie’s Kids
2016/10/14 全球购物
趣天网日本站:Qoo10 JP
2019/09/18 全球购物
设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
2014/12/30 面试题
2014年中秋寄语
2014/08/11 职场文书
九年级化学教学反思
2016/02/22 职场文书
Python闭包的定义和使用方法
2022/04/11 Python
vue ant design 封装弹窗表单的使用
2022/06/01 Vue.js