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 相关文章推荐
Python打印scrapy蜘蛛抓取树结构的方法
Apr 08 Python
使用Python的Django框架实现事务交易管理的教程
Apr 20 Python
Python虚拟环境Virtualenv使用教程
May 18 Python
Python引用模块和查找模块路径
Mar 17 Python
django如何连接已存在数据的数据库
Aug 14 Python
python实现从文件中读取数据并绘制成 x y 轴图形的方法
Oct 14 Python
pow在python中的含义及用法
Jul 11 Python
Python Django模板之模板过滤器与自定义模板过滤器示例
Oct 18 Python
对tensorflow中tf.nn.conv1d和layers.conv1d的区别详解
Feb 11 Python
Python MySQL 日期时间格式化作为参数的操作
Mar 02 Python
python使用隐式循环快速求和的实现示例
Sep 11 Python
对PyTorch中inplace字段的全面理解
May 22 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启动windows应用程序、执行bat批处理、执行cmd命令的方法(exec、system函数详解)
2014/10/20 PHP
php表单提交与$_POST实例分析
2015/01/26 PHP
PHP实现简单汉字验证码
2015/07/28 PHP
php注册系统和使用Xajax即时验证用户名是否被占用
2017/08/31 PHP
TextArea 控件的最大长度问题(js json)
2009/12/16 Javascript
圣诞节Merry Christmas给博客添加浪漫的下雪效果基于jquery实现
2012/12/27 Javascript
js如何获取兄弟、父类等节点
2014/01/06 Javascript
javascript基于DOM实现省市级联下拉框的方法
2015/05/14 Javascript
javascript实现的图片预览功能
2017/03/25 Javascript
关于vue-router的beforeEach无限循环的问题解决
2017/09/09 Javascript
从parcel.js打包出错到选择nvm的全部过程
2018/01/23 Javascript
Vue的事件响应式进度条组件实例详解
2018/02/04 Javascript
Vue 创建组件的两种方法小结(必看)
2018/02/23 Javascript
AngularJS 前台分页实现的示例代码
2018/06/07 Javascript
JS使用tween.js动画库实现轮播图并且有切换功能
2018/07/17 Javascript
js 使用ajax设置和获取自定义header信息的方法小结
2020/03/12 Javascript
在vue-cli3中使用axios获取本地json操作
2020/07/30 Javascript
Python中的面向对象编程详解(下)
2015/04/13 Python
python分布式环境下的限流器的示例
2017/10/26 Python
使用python PIL库实现简单验证码的去噪方法步骤
2019/05/10 Python
PyQt 实现使窗口中的元素跟随窗口大小的变化而变化
2019/06/18 Python
css3中less实现文字长阴影(long shadow)
2020/04/24 HTML / CSS
HTML5之SVG 2D入门6—视窗坐标系与用户坐标系及变换概述
2013/01/30 HTML / CSS
Html5原创俄罗斯方块(基于canvas)
2019/01/07 HTML / CSS
全球酒店预订网站:Hotels.com
2016/08/10 全球购物
澳大利亚正品化妆品之家:Cosmetic Capital
2017/07/03 全球购物
英国顶级珠宝品牌之家:John Greed
2018/06/09 全球购物
马德里竞技官方网上商店:Atletico Madrid Shop
2019/03/31 全球购物
.NET remoting的两种通道是什么
2016/05/31 面试题
介绍一下linux的文件权限
2014/07/20 面试题
办公室主任竞聘演讲稿
2014/05/15 职场文书
三八妇女节标语
2014/10/09 职场文书
2016春节慰问信范文
2015/03/25 职场文书
详解CSS故障艺术
2021/05/25 HTML / CSS
python中sqllite插入numpy数组到数据库的实现方法
2021/06/21 Python
GPU服务器的多用户配置方法
2022/07/07 Servers