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 enumerate遍历数组示例应用
Sep 06 Python
跟老齐学Python之玩转字符串(1)
Sep 14 Python
Python操作word常见方法示例【win32com与docx模块】
Jul 17 Python
python3.6.3转化为win-exe文件发布的方法
Oct 31 Python
解决python字典对值(值为列表)赋值出现重复的问题
Jan 20 Python
Python使用paramiko操作linux的方法讲解
Feb 25 Python
基于Django的乐观锁与悲观锁解决订单并发问题详解
Jul 31 Python
在Python中使用filter去除列表中值为假及空字符串的例子
Nov 18 Python
Python操作多维数组输出和矩阵运算示例
Nov 28 Python
Pycharm最常用的快捷键及使用技巧
Mar 05 Python
如何理解python中数字列表
May 29 Python
python3定位并识别图片验证码实现自动登录功能
Jan 29 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面向对象全攻略 (四)构造方法与析构方法
2009/09/30 PHP
PHP的Yii框架的常用日志操作总结
2015/12/08 PHP
php读取qqwry.dat ip地址定位文件的类实例代码
2016/11/15 PHP
php抽象方法和抽象类实例分析
2016/12/07 PHP
js里怎么取select标签里的值并修改
2012/12/10 Javascript
jquery 面包屑导航 具体实现
2013/06/05 Javascript
jquery和javascript中如何将一元素的内容赋给另一元素
2014/01/09 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
javascript将DOM节点添加到文档的方法实例分析
2015/08/04 Javascript
jQuery ajax中使用confirm,确认是否删除的简单实例
2016/06/17 Javascript
javascript时间差插件分享
2016/07/18 Javascript
jQuery实现最简单的切换图效果【可兼容IE6、火狐、谷歌、opera等】
2016/09/04 Javascript
浅谈JS使用[ ]来访问对象属性
2016/09/21 Javascript
javascript中json基础知识详解
2017/01/19 Javascript
js中document.referrer实现移动端返回上一页
2017/02/22 Javascript
微信小程序如何获取openid及用户信息
2018/01/26 Javascript
node+koa2+mysql+bootstrap搭建一个前端论坛
2018/05/06 Javascript
puppeteer实现html截图的示例代码
2019/01/10 Javascript
Vue2.0使用嵌套路由实现页面内容切换/公用一级菜单控制页面内容切换(推荐)
2019/05/08 Javascript
Layui动态生成select下拉选择框不显示的解决方法
2019/09/24 Javascript
JQuery省市联动效果实现过程详解
2020/05/08 jQuery
解决Vue + Echarts 使用markLine标线(precision精度问题)
2020/07/20 Javascript
简单谈谈Python中的json与pickle
2017/07/19 Python
Python中list查询及所需时间计算操作示例
2018/06/21 Python
浅谈Python中的bs4基础
2018/10/21 Python
判断python对象是否可调用的三种方式及其区别详解
2019/01/31 Python
Python直接赋值及深浅拷贝原理详解
2020/09/05 Python
会计毕业生求职简历的自我评价
2013/10/20 职场文书
股指期货心得体会
2014/09/13 职场文书
反对形式主义、官僚主义、享乐主义和奢靡之风整改措施
2014/09/17 职场文书
2014年教育实习工作总结
2014/11/22 职场文书
2016年七夕情人节宣传语
2015/11/25 职场文书
党员电教片《信仰》心得体会
2016/01/15 职场文书
创业计划书之密室逃脱
2019/11/08 职场文书
《追风筝的人》:人心中的成见是座大山,但请不忘初心
2019/11/15 职场文书
apache虚拟主机配置的三种方式(小结)
2022/07/23 Servers