Python使用Pycrypto库进行RSA加密的方法详解


Posted in Python onJune 06, 2016

密码与通信
密码技术是一门历史悠久的技术。信息传播离不开加密与解密。密码技术的用途主要源于两个方面,加密/解密和签名/验签

在信息传播中,通常有发送者,接受者和窃听者三个角色。假设发送者Master想要写信给接受者Ghost,可是又不想信的内容被别人看到,因此Master需要先对信加密,而Ghost收到信之后又能解密。这样别的人即使窃听盗取了密文也无法解密。其次,如果窃听者并不像破译内容,而是伪造Master发消息给Ghost,那么Master发消息前就得先对机密内容进行签名。

密码技术
为了进行加密以及通信,人们发明了很多公开的算法。对称与非对称算法等。常见的加密方式有RSA, AES等算法。对于选择加密算法,一个常识就是使用公开的算法。一方面是这些算法经过实践检验,另一方面对于破译难度和破译条件破译时间都有预估。对于任何加密算法,都是能破解的,不同在于时间上的投入。

Python密码库--Pycrypto
Python良好的生态,对于加密解密技术都有成熟的第三方库。大名鼎鼎的M2Crypto和Pycrypto,前者非常容易使用,可是安装却非常头疼,不同的系统依赖软件的版本还有影响。后者则比较方面,直接使用pip安装即可。

安装

pip install pycrypto

RSA 密码算法与签名
RSA是一种公钥密码算法,RSA的密文是对代码明文的数字的 E 次方求mod N 的结果。也就是将明文和自己做E次乘法,然后再将其结果除以 N 求余数,余数就是密文。RSA是一个简洁的加密算法。E 和 N 的组合就是公钥(public key)。

对于RSA的解密,即密文的数字的 D 次方求mod N 即可,即密文和自己做 D 次乘法,再对结果除以 N 求余数即可得到明文。D 和 N 的组合就是私钥(private key)。

算法的加密和解密还是很简单的,可是公钥和私钥的生成算法却不是随意的。本文在于使用,对生成秘钥对的算法就暂时忽略。使用 Pycrypto生成秘钥对很简单,我们分别为 Master和Ghost各生成一对属于自己的秘钥对。

from Crypto import Random
from Crypto.Hash import SHA
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from Crypto.PublicKey import RSA

# 伪随机数生成器
random_generator = Random.new().read
# rsa算法生成实例
rsa = RSA.generate(1024, random_generator)

# master的秘钥对的生成
private_pem = rsa.exportKey()

with open('master-private.pem', 'w') as f:
  f.write(private_pem)

public_pem = rsa.publickey().exportKey()
with open('master-public.pem', 'w') as f:
  f.write(public_pem)

# ghost的秘钥对的生成
private_pem = rsa.exportKey()
with open('master-private.pem', 'w') as f:
  f.write(private_pem)

public_pem = rsa.publickey().exportKey()
with open('master-public.pem', 'w') as f:
  f.write(public_pem)

所生成的私钥和公钥大概是这样的:

-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDR4Wq9l44lw/thTPyFmSi2hII92EPh90yGXQNL5e7zJPD16j6Q
tr+tIPNSQaVrnmNwrtqyEC2x4Meyp3tdCWPYUF11r2GgDgxKfUByetNG4XqJeUKk
kJ6D6C706mTf/2zsm8KFoNYCYPX1GhvpiTOikHcNlHLCnOD7jbMAovJg/QIDAQAB
AoGBAIz8V6+0NxC3bg4WoSs9j1PL/5F7zV3lucoogSZi9vjuP89x40Vi/a9XCxye
bHi2lSYEz3P92jQ7QuqIBx6gSCi3p2HLjD5LyQeSSMbPe8KSlf52dBUaPthbBceA
IJSBDrE8MKGpulTQKAJ7K3zQUOP2ZZgcKxq2jcQgS6iTENIBAkEA5r7emvwuL0Ob
Maav4o1Ovb5c6OL7bSm1tuLPSKl05WuNYfE6LkqiwOOn5lPvsqhwyI1dJeywVeQz
E+PvcTUR7QJBAOjZ8PxnP5T14fuhbfko4d24Ev+iiTBdq3pMXWvobEFL1ljV6aYE
2JAiMjO/Fzd1WgZhWPa3P+diyTs9mART6VECQQC0LeEXdsn9oDYEbFu1dZBB++8C
75NTJ5m8iJlB7QjZyMUq8Ln0wdUa9+n4ohxvDraa9EADSDJdr4bvBjLH3J/1AkBr
9QfO7kvDU5DXqoujVnoJ4xsj3IbAnt0vEZLKwfLW/0M84si2SU7i3IfsB+/KraT0
ilPF50ZAkEN+LNt7PjBRAkAHBBPME7IbFqxi5Cc/6R12DOMiJbOLDTS12b1J1cwG
p8WMIERsvwWdJw+4NdqjbJcjzeGrXhDBi//JU902TAwy
-----END RSA PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR4Wq9l44lw/thTPyFmSi2hII9
2EPh90yGXQNL5e7zJPD16j6Qtr+tIPNSQaVrnmNwrtqyEC2x4Meyp3tdCWPYUF11
r2GgDgxKfUByetNG4XqJeUKkkJ6D6C706mTf/2zsm8KFoNYCYPX1GhvpiTOikHcN
lHLCnOD7jbMAovJg/QIDAQAB
-----END PUBLIC KEY-----

加密与解密
通常通信的时候,发送者使用接受者的公钥加密,接受者使用接受者私钥解密。

简而言之,Master给Ghost通信,需要加密内容,那么Ghost会生成一个秘钥对,Ghost的公钥ghost-public.pem和私钥ghost-private.pem 。Ghost 把公钥公开给发送者,任何人都可以用来加密,然后Master使用ghost-public.pem进行加密,然后把内容发给Ghost,Ghost再使用ghost-private.pem进行解密。

1.加密(encrypt)

# Master使用Ghost的公钥对内容进行rsa 加密

In [12]: message = 'hello ghost, this is a plian text'
In [13]: with open('ghost-public.pem') as f:
  ....:   key = f.read()
  ....:   rsakey = RSA.importKey(key)
  ....:   cipher = Cipher_pkcs1_v1_5.new(rsakey)
  ....:   cipher_text = base64.b64encode(cipher.encrypt(message))
  ....:   print cipher_text
  ....:


HYQPGB+axWCbPp7PPGNTJEAhVPW0TX5ftvUN2v40ChBLB1pS+PVM3YGT5vfcsvmPZhW8NKVSBp8FwjLUnMn6yXP1O36NaunUzyHwI+cpjlkTwZs3DfCY/32EzeuKuJABin1FHBYUMTOKtHy+eEDOuaJTnZTC7ZBkdha+J88HXSc=

cipher_text 即 Master加密后将要发送给Ghost的密文。

2.解密(decrypt)

# Ghost使用自己的私钥对内容进行rsa 解密 

In [14]: with open('ghost-private.pem') as f:
  ....:   key = f.read()
  ....:   rsakey = RSA.importKey(key)
  ....:   cipher = Cipher_pkcs1_v1_5.new(rsakey)
  ....:   text = cipher.decrypt(base64.b64decode(encrypt_text), random_generator)
  ....:
In [15]: print text
hello ghost, this is a plian text
In [16]: assert text == message, 'decrypt falied'

这样Ghost就能看到Master所发的内容了,当然,如果Ghost想要给Master发消息,就需要Master先把其的公钥给Ghost,后者再使用公钥加密,然后发送给Master,最后Master使用自己的私钥解密。

签名与验签
当然,对于窃听者,有时候也可以对伪造Master给Ghost发送内容。为此出现了数字签名。也就是Master给Ghost发送消息的时候,先对消息进行签名,表明自己的身份,并且这个签名无法伪造。具体过程即Master使用自己的私钥对内容签名,然后Ghost使用Master的公钥进行验签。

签名

# Master 使用自己的公钥对内容进行签名
In [17]: with open('master-private.pem') as f:
  ....:    key = f.read()
  ....:    rsakey = RSA.importKey(key)
  ....:    signer = Signature_pkcs1_v1_5.new(rsakey)
  ....:    digest = SHA.new()
  ....:    digest.update(message)
  ....:    sign = signer.sign(digest)
  ....:    signature = base64.b64encode(sign)
In [18]: print signature
jVUcAYfgF5Pwlpgrct3IlCX7KezWqNI5tD5OIFTrfCOQgfyCrOkN+/gRLsMiSDOHhFPj2LnfY4Cr5u4eG2IiH8+uSF5z4gUX48AqCQlqiOTLk2EGvyp+w+iYo2Bso1MUi424Ebkx7SnuJwLiPqNzIBLfEZLA3ov69aDArh6hQiw=

验签

In [22]: with open('master-public.pem') as f:
  ....:   key = f.read()
  ....:   rsakey = RSA.importKey(key)
  ....:   verifier = Signature_pkcs1_v1_5.new(rsakey)
  ....:   digest = SHA.new()
  ....:   # Assumes the data is base64 encoded to begin with
  ....:   digest.update(message)
  ....:   is_verify = signer.verify(digest, base64.b64decode(signature))
  ....:   print is_verify
  ....:
True

总结
Pycrypto提供了比较完善的加密算法。RSA广泛用于加密与解密,还有数字签名通信领域。使用Publick/Private秘钥算法中,加密主要用对方的公钥,解密用自己的私钥。签名用自己的私钥,验签用对方的公钥。

  • 加密解密:公钥加密,私钥解密
  • 签名验签:私钥签名,公钥验签

无论是加密机密还是签名验签都使用同一对秘钥对。

Python 相关文章推荐
Python 获得13位unix时间戳的方法
Oct 20 Python
numpy自动生成数组详解
Dec 15 Python
Python三种遍历文件目录的方法实例代码
Jan 19 Python
Python常见排序操作示例【字典、列表、指定元素等】
Aug 15 Python
Python中整数的缓存机制讲解
Feb 16 Python
matplotlib实现区域颜色填充
Mar 18 Python
python 杀死自身进程的实现方法
Jul 01 Python
Django 响应数据response的返回源码详解
Aug 06 Python
Python合并多张图片成PDF
Jun 09 Python
Python上下文管理器Content Manager
Jun 26 Python
Python实现灰色关联分析与结果可视化的详细代码
Mar 25 Python
numpy array找出符合条件的数并赋值的示例代码
Jun 01 Python
Python的Flask框架应用调用Redis队列数据的方法
Jun 06 #Python
Python第三方库的安装方法总结
Jun 06 #Python
在Python程序和Flask框架中使用SQLAlchemy的教程
Jun 06 #Python
Python的socket模块源码中的一些实现要点分析
Jun 06 #Python
深入浅析python定时杀进程
Jun 06 #Python
深入理解python函数递归和生成器
Jun 06 #Python
python下调用pytesseract识别某网站验证码的实现方法
Jun 06 #Python
You might like
PHP采集相关教程之一 CURL函数库
2010/02/15 PHP
JS异常处理try..catch语句的作用和实例
2014/05/05 PHP
php输出全球各个时区列表的方法
2015/03/31 PHP
php实现mysql数据库分表分段备份
2015/06/18 PHP
Apache连接PHP后无法启动问题解决思路
2015/06/18 PHP
php文件上传的两种实现方法
2016/04/04 PHP
枚举JavaScript对象的函数
2006/12/22 Javascript
7个Javascript地图脚本整理
2009/10/20 Javascript
JS实现金额转换(将输入的阿拉伯数字)转换成中文的实现代码
2013/09/30 Javascript
JavaScript实现在数组中查找不同顺序排列的字符串
2014/09/26 Javascript
Active控件问题小结(附解决办法)
2016/06/09 Javascript
jquery实现左右轮播图效果
2017/09/28 jQuery
node实现基于token的身份验证
2018/04/09 Javascript
JS中获取 DOM 元素的绝对位置实例详解
2018/04/23 Javascript
使用elementUI实现将图片上传到本地的示例
2018/09/04 Javascript
[32:56]完美世界DOTA2联赛PWL S3 Rebirth vs CPG 第二场 12.11
2020/12/16 DOTA
python中enumerate函数用法实例分析
2015/05/20 Python
python使用电子邮件模块smtplib的方法
2016/08/28 Python
Python实现获取nginx服务器ip及流量统计信息功能示例
2018/05/18 Python
python统计字母、空格、数字等字符个数的实例
2018/06/29 Python
Appium Python自动化测试之环境搭建的步骤
2019/01/23 Python
python3 自动识别usb连接状态,即对usb重连的判断方法
2019/07/03 Python
基于Python的自媒体小助手---登录页面的实现代码
2020/06/29 Python
pip已经安装好第三方库但pycharm中import时还是标红的解决方案
2020/10/09 Python
CSS中越界问题的经典解决方案【推荐】
2016/04/19 HTML / CSS
canvas三角函数模拟水波效果的示例代码
2018/07/03 HTML / CSS
HTML5给汉字加拼音收起展开组件的实现代码
2020/04/08 HTML / CSS
What is the purpose of Void class? Void类的作用是什么?
2016/10/31 面试题
公司企业表扬信
2014/01/11 职场文书
自我评价的范文
2014/02/02 职场文书
汇源肾宝广告词
2014/03/20 职场文书
新文化运动的口号
2014/06/21 职场文书
法人授权委托书样本
2014/09/19 职场文书
乔布斯辞职信(中英文对照)
2015/05/12 职场文书
2015中学学校工作总结
2015/07/20 职场文书
Windows11 Insider Preview Build 25206今日发布 更新内容汇总
2022/09/23 数码科技