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笔记(2)
Oct 24 Python
python设置检查点简单实现代码
Jul 01 Python
对Python的Django框架中的项目进行单元测试的方法
Apr 11 Python
python正则实现计算器功能
Dec 14 Python
python 多个参数不为空校验方法
Feb 14 Python
opencv与numpy的图像基本操作
Mar 08 Python
Python opencv实现人眼/人脸识别以及实时打码处理
Apr 29 Python
Ubuntu+python将nii图像保存成png格式
Jul 18 Python
VSCode中自动为Python文件添加头部注释
Nov 14 Python
python爬取本站电子书信息并入库的实现代码
Jan 20 Python
python元组打包和解包过程详解
Aug 02 Python
python基础之模块的导入
Oct 24 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
《魔兽争霸3:重制版》更新 多项视觉效果调整
2020/05/04 魔兽争霸
PHP编程最快明白(第一讲 软件环境和准备工作)
2010/10/25 PHP
PHP和Mysqlweb应用开发核心技术 第1部分 Php基础-1 开始了解php
2011/07/03 PHP
Laravel 5框架学习之表单验证
2015/04/08 PHP
php发送短信验证码完成注册功能
2015/11/24 PHP
PHP简单数据库操作类实例【支持增删改查及链式操作】
2016/10/10 PHP
理清PHP在Linxu下执行时的文件权限方法
2017/06/07 PHP
window.parent与window.openner区别介绍
2012/04/12 Javascript
javascript中获取下个月一号,是星期几
2012/06/01 Javascript
javascript history对象(历史记录)使用方法(实现浏览器前进后退)
2014/01/07 Javascript
3个可以改善用户体验的AngularJS指令介绍
2015/06/18 Javascript
浅谈JS原型对象和原型链
2016/03/02 Javascript
js实现添加可信站点、修改activex安全设置,禁用弹出窗口阻止程序
2016/08/17 Javascript
移动web开发之touch事件实例详解
2018/01/17 Javascript
vue项目中导入swiper插件的方法
2018/01/30 Javascript
Angular CLI在Angular项目中如何使用scss详解
2018/04/10 Javascript
vue.js中proxyTable 转发请求的实现方法
2018/09/20 Javascript
使用Vuex解决Vue中的身份验证问题
2018/09/28 Javascript
jquery 回调操作实例分析【回调成功与回调失败的情况】
2019/09/27 jQuery
JS实现简单的表格增删
2020/01/16 Javascript
[42:22]DOTA2上海特级锦标赛C组小组赛#1 OG VS Archon第一局
2016/02/27 DOTA
基于Python socket的端口扫描程序实例代码
2018/02/09 Python
对Python中Iterator和Iterable的区别详解
2018/10/18 Python
自定义django admin model表单提交的例子
2019/08/23 Python
解决pyinstaller打包运行程序时出现缺少plotly库问题
2020/06/02 Python
Django视图、传参和forms验证操作
2020/07/15 Python
CSS3 实现的缩略图悬停效果
2020/12/09 HTML / CSS
阻止移动设备(手机、pad)浏览器双击放大网页的方法
2014/06/03 HTML / CSS
英国最大的宝石首饰超市:QP Jewellers
2018/09/23 全球购物
实现strstr功能,即在父串中寻找子串首次出现的位置
2016/08/05 面试题
空指针到底是什么
2012/08/07 面试题
经理管理专业自荐信范文
2013/12/31 职场文书
科研先进个人典型材料
2014/01/31 职场文书
2014年银行员工工作总结
2014/11/12 职场文书
电影建国大业观后感
2015/06/01 职场文书
openGauss数据库JDBC环境连接配置的详细过程(Eclipse)
2022/06/01 Java/Android