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中列表、字典、元组、集合数据结构整理
Nov 20 Python
Python实现堆排序的方法详解
May 03 Python
Python的Flask框架应用调用Redis队列数据的方法
Jun 06 Python
Python实现统计给定字符串中重复模式最高子串功能示例
May 16 Python
python爬取cnvd漏洞库信息的实例
Feb 14 Python
Django对models里的objects的使用详解
Aug 17 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
Sep 10 Python
python实现的登录与提交表单数据功能示例
Sep 25 Python
DJANGO-URL反向解析REVERSE实例讲解
Oct 25 Python
python 实现兔子生兔子示例
Nov 21 Python
Python 实现判断图片格式并转换,将转换的图像存到生成的文件夹中
Jan 13 Python
python脚本框架webpy的url映射详解
Nov 20 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+java实现自动新闻滚动窗口
2006/10/09 PHP
ThinkPHP学习笔记(一)ThinkPHP部署
2014/06/22 PHP
Yii2中Restful API原理实例分析
2016/07/25 PHP
php 使用redis锁限制并发访问类示例
2016/11/02 PHP
php中get_magic_quotes_gpc()函数说明
2017/02/06 PHP
PHP中for循环与foreach的区别
2017/03/06 PHP
利用PHP访问MySql数据库的逻辑操作以及增删改查的实例讲解
2017/08/30 PHP
PHP添加PNG图片背景透明水印操作类定义与用法示例
2019/03/12 PHP
php使用json-schema模块实现json校验示例
2019/09/28 PHP
php实现快速对二维数组某一列进行组装的方法小结
2019/12/04 PHP
可缩放Reloaded-一个针对可缩放元素的复用组件
2007/03/10 Javascript
js onkeypress与onkeydown 事件区别详细说明
2012/12/13 Javascript
鼠标经过tr时,改变tr当前背景颜色
2014/01/13 Javascript
jQuery实现的图文高亮滚动切换特效实例
2015/08/10 Javascript
基于cssSlidy.js插件实现响应式手机图片轮播效果
2016/08/30 Javascript
Angular.JS去掉访问路径URL中的#号详解
2017/03/30 Javascript
微信小程序 图片上传实例详解
2017/05/05 Javascript
自定义事件解决重复请求BUG的问题
2017/07/11 Javascript
nodejs操作mongodb的增删改查功能实例
2017/11/09 NodeJs
nodejs中express入门和基础知识点学习
2018/09/13 NodeJs
[46:20]CHAOS vs Alliacne 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
python计算最小优先级队列代码分享
2013/12/18 Python
Python中创建字典的几种方法总结(推荐)
2017/04/27 Python
python实现决策树C4.5算法详解(在ID3基础上改进)
2017/05/31 Python
numpy给array增加维度np.newaxis的实例
2018/11/01 Python
windows下 兼容Python2和Python3的解决方法
2018/12/05 Python
python Django的web开发实例(入门)
2019/07/31 Python
python 实现兔子生兔子示例
2019/11/21 Python
Pytorch 之修改Tensor部分值方式
2019/12/27 Python
万得城电器土耳其网站:欧洲第一大电子产品零售商
2016/10/07 全球购物
2014年法务工作总结
2014/12/11 职场文书
个人年度总结报告
2015/03/09 职场文书
大学生支教感言
2015/08/01 职场文书
朋友圈早安励志语录!
2019/07/08 职场文书
导游词之上海东方明珠塔
2019/09/25 职场文书
Python tensorflow卷积神经Inception V3网络结构
2022/05/06 Python