RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

  RSA解决了对称加密的一个不足,比如AES算法加密和解密时使用的是同一个秘钥,因此这个秘钥不能公开,因此对于需要公开秘钥的场合,我们需要在加密和解密过程中使用不同的秘钥,加密使用的公钥可以公开,解密使用的私钥要保密,这就是非对称加密的好处。 

  常用的开发语言来实现RSA加密:

  RSA非对称加密算法实现:Java

  RSA非对称加密算法实现:C#

  RSA非对称加密算法实现:Golang

  RSA非对称加密算法实现:Python

 

  公钥与私钥

  公钥与私钥是成对的,一般的,我们认为的是公钥加密、私钥解密、私钥签名、公钥验证,有人说成私钥加密,公钥解密时不对的。

  公钥与私钥的生成有多种方式,可以通过程序生成(下文具体实现),可以通过openssl工具:  

    # 生成一个私钥,推荐使用1024位的秘钥,秘钥以pem格式保存到-out参数指定的文件中,采用PKCS1格式
openssl genrsa -out rsa.pem 1024
# 生成与私钥对应的公钥,生成的是Subject Public Key,一般配合PKCS8格式私钥使用
openssl rsa -in rsa.pem -pubout -out rsa.pub

  RSA生成公钥与私钥一般有两种格式:PKCS1和PKCS8,上面的命令生成的秘钥是PKCS1格式的,而公钥是Subject Public Key,一般配合PKCS8格式私钥使用,所以就可能会涉及到PKCS1和PKCS8之间的转换:

    # PKCS1格式私钥转换为PKCS8格式私钥,私钥直接输出到-out参数指定的文件中
openssl pkcs8 -topk8 -inform PEM -in rsa.pem -outform pem -nocrypt -out rsa_pkcs8.pem
# PKCS8格式私钥转换为PKCS1格式私钥,私钥直接输出到-out参数指定的文件中
openssl rsa -in rsa_pkcs8.pem -out rsa_pkcs1.pem # PKCS1格式公钥转换为PKCS8格式公钥,转换后的内容直接输出
openssl rsa -pubin -in rsa.pub -RSAPublicKey_out
# PKCS8格式公钥转换为PKCS1格式公钥,转换后的内容直接输出
openssl rsa -RSAPublicKey_in -pubout -in rsa.pub

  现实中,我们往往从pem、crt、pfx文件获取公私和私钥,crt、pfx的制作可以参考:简单的制作ssl证书,并在nginx和IIS中使用,或者使用现成的:https://pan.baidu.com/s/1MJ5YmuZiLBnf-DfNR_6D7A (提取码:c6tj),密码都是:123456

  Python实现

  首先使用pip两个第三方包:  

    # 用于从crt、pfx等文件读取公私秘钥
pip install pyOpenSSL
# 用RSA加密解密签名验证等(如果安装不了,先卸载旧版本再安装:pip uninstall pycrypto)
pip install pycryptodome

  接着封装一个模块RsaUtil:  

  

# 需要安装OpenSSL包:pip install pyOpenSSL
# 需要安装pycrypto包:pip install pycryptodome
from Crypto import Random, Hash
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_v1_5_Cipher
from Crypto.Signature import PKCS1_v1_5 as PKCS1_v1_5_Signature
from Crypto.IO import PEM, PKCS8
from OpenSSL import crypto
from Crypto.Util.asn1 import (DerSequence, DerBitString, DerObjectId, DerNull) # pkcs1格式转换为pkcs8
def pkcs1_to_pkcs8(buffer):
rsakey = RSA.importKey(buffer)
if rsakey.has_private():
return PKCS8.wrap(buffer, RSA.oid, None)
return rsakey.exportKey("DER") # pkcs8格式转换为pkcs1
def pkcs8_to_pkcs1(buffer):
rsakey = RSA.importKey(buffer)
if rsakey.has_private(): # 私钥
return PKCS8.unwrap(buffer, None)[1] spki = DerSequence().decode(buffer, nr_elements=2)
algo = DerSequence().decode(spki[0], nr_elements=(1, 2))
algo_oid = DerObjectId().decode(algo[0])
spk = DerBitString().decode(spki[1]).value if len(algo) == 1:
algo_params = None
else:
try:
DerNull().decode(algo[1])
algo_params = None
except:
algo_params = algo[1] if algo_oid.value != RSA.oid or algo_params is not None:
raise ValueError("No RSA subjectPublicKeyInfo")
return spk # 生成RSA加密的公私密钥
def generate_rsa_key(use_pkcs8=False):
rsa_key = RSA.generate(1024, Random.new().read) # 1024位
private_key = rsa_key.exportKey("DER", pkcs=1)
public_key = rsa_key.publickey().exportKey("DER") # subject_public_key
if use_pkcs8:
private_key = pkcs1_to_pkcs8(private_key)
else:
public_key = pkcs8_to_pkcs1(public_key) return public_key, private_key # 从pem文件中读取秘钥
def read_from_pem(pen_file_ame):
with open(pen_file_ame, 'r') as f:
t = PEM.decode(f.read())
if t[2]:
raise ValueError("fail to read pem")
return t[0] # 将秘钥写入pem文件
def write_to_pem(buffer, is_private_key, pen_file_ame):
if is_private_key:
str = PEM.encode(buffer, "RSA PRIVATE KEY")
else:
str = PEM.encode(buffer, "RSA PUBLIC KEY") with open(pen_file_ame, 'w') as f:
f.write(str) # 从crt文件中读取公钥
def read_public_key_from_crt(crt_file_name):
with open(crt_file_name, 'rb') as f:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
return crypto.dump_publickey(crypto.FILETYPE_PEM, cert.get_pubkey()) # 从pfx文件中读取公私钥
def read_from_pfx(pfx_file_name, password):
with open(pfx_file_name, 'rb') as f:
pfx = crypto.load_pkcs12(f.read(), bytes(password, encoding="utf-8"))
cert = pfx.get_certificate()
_public_key = crypto.dump_publickey(crypto.FILETYPE_PEM, cert.get_pubkey())
_privat_key = crypto.dump_privatekey(crypto.FILETYPE_PEM, pfx.get_privatekey())
return _public_key, _privat_key # RSA使用公钥加密
def rsa_encrypt(value, public_key):
rsakey = RSA.importKey(public_key)
cipher = PKCS1_v1_5_Cipher.new(rsakey)
buffer = cipher.encrypt(value.encode("utf-8"))
return buffer.hex() # 使用hex格式输出 # RSA使用私钥解密
def rsa_decrypt(value, private_key):
rsakey = RSA.importKey(private_key)
cipher = PKCS1_v1_5_Cipher.new(rsakey)
buffer = bytes.fromhex(value) # 读取hex格式数据
buffer = cipher.decrypt(buffer, Random.new().read)
return buffer.decode("utf-8") # RSA使用私钥签名
def sign(value, private_ey, halg=Hash.MD5):
rsakey = RSA.importKey(private_ey)
signer = PKCS1_v1_5_Signature.new(rsakey) hash = halg.new()
hash.update(value.encode("utf-8"))
buffer = signer.sign(hash)
return buffer.hex() # 使用hex格式输出 # RSA使用公钥验证签名
def verify(value, public_key, signature, halg=Hash.MD5):
rsakey = RSA.importKey(public_key)
verifier = PKCS1_v1_5_Signature.new(rsakey) hash = halg.new()
hash.update(value.encode("utf-8")) buffer = bytes.fromhex(signature) # 读取hex格式数据
result: bool = verifier.verify(hash, buffer)
return result

RsaUtil

  生成RSA的公私秘钥:  

# 生成rsa公私秘钥
(publicKey, privateKey) = RsaUtil.generate_rsa_key(use_pkcs8)

  生成秘钥后,需要保存,一般保存到pem文件中:  

# 将公私秘钥写入pem文件,filePath是文件目录
RsaUtil.write_to_pem(publicKey, False, os.path.join(filePath, "rsa.pub"))
RsaUtil.write_to_pem(privateKey, True, os.path.join(filePath, "rsa.pem"))

  可以保存到pem文件中,当然也可以从pem文件中读取了:  

# 从pem文件中读取秘钥,filePath是文件目录
publicKey = RsaUtil.read_from_pem(os.path.join(filePath, "rsa.pub"))
privateKey = RsaUtil.read_from_pem(os.path.join(filePath, "rsa.pem"))

  还可以从crt证书中读取公钥,而crt文件不包含私钥,因此需要单独获取私钥:

# 从crt文件读取,filePath是文件目录
publicKey = RsaUtil.read_public_key_from_crt(os.path.join(filePath, "demo.crt"))
privateKey = RsaUtil.read_from_pem(os.path.join(filePath, "demo.key"))

  pfx文件中包含了公钥和私钥,可以很方便就读取到:

# 从demo.pfx文件读取(demo.pfx采用的是pkcs1),filePath是文件目录
(publicKey, privateKey) = RsaUtil.read_from_pfx(os.path.join(filePath, "demo.pfx"), "123456")

  有时候我们还可能需要进行秘钥的转换:

# Pkcs8格式公钥转换为Pkcs1格式公钥
publicKey = RsaUtil.pkcs8_to_pkcs1(publicKey)
# Pkcs8格式私钥转换为Pkcs1格式私钥
privateKey = RsaUtil.pkcs8_to_pkcs1(privateKey)
# Pkcs1格式公钥转换为Pkcs8格式公钥
publicKey = RsaUtil.pkcs1_to_pkcs8(publicKey)
# Pkcs1格式私钥转换为Pkcs8格式私钥
privateKey = RsaUtil.pkcs1_to_pkcs8(privateKey)

  有了公钥和私钥,接下就就能实现加密、解密、签名、验证签名等操作了:

encryptText = RsaUtil.rsa_encrypt(text, publicKey)
print("【", text, "】经过【RSA】加密后:", encryptText) decryptText = RsaUtil.rsa_decrypt(encryptText, privateKey)
print("【", encryptText, "】经过【RSA】解密后:", decryptText) signature = RsaUtil.sign(text, privateKey, Hash.MD5)
print("【", text, "】经过【RSA】签名后:", signature) result = RsaUtil.verify(text, publicKey, signature, Hash.MD5)
print("【", text, "】的签名【", signature, "】经过【RSA】验证后结果是:", result)

  完整的demo代码:

import RsaUtil
from Crypto import Hash
import os text = "上山打老虎"
use_pkcs8 = True
filePath = os.getcwd()
print("文件路径:", filePath) # 生成rsa公私秘钥
(publicKey, privateKey) = RsaUtil.generate_rsa_key(use_pkcs8)
# 从pem文件中读取秘钥,filePath是文件目录
# publicKey = RsaUtil.read_from_pem(os.path.join(filePath, "rsa.pub"))
# privateKey = RsaUtil.read_from_pem(os.path.join(filePath, "rsa.pem"))
# 从demo.pfx文件读取(demo.pfx采用的是pkcs1),filePath是文件目录
# (publicKey, privateKey) = RsaUtil.read_from_pfx(os.path.join(filePath, "demo.pfx"), "123456")
# 从crt文件读取,filePath是文件目录
# publicKey = RsaUtil.read_public_key_from_crt(os.path.join(filePath, "demo.crt"))
# privateKey = RsaUtil.read_from_pem(os.path.join(filePath, "demo.key")) # 将公私秘钥写入pem文件,filePath是文件目录
RsaUtil.write_to_pem(publicKey, False, os.path.join(filePath, "rsa.pub"))
RsaUtil.write_to_pem(privateKey, True, os.path.join(filePath, "rsa.pem")) # Pkcs8格式公钥转换为Pkcs1格式公钥
publicKey = RsaUtil.pkcs8_to_pkcs1(publicKey)
# Pkcs8格式私钥转换为Pkcs1格式私钥
privateKey = RsaUtil.pkcs8_to_pkcs1(privateKey)
# Pkcs1格式公钥转换为Pkcs8格式公钥
publicKey = RsaUtil.pkcs1_to_pkcs8(publicKey)
# Pkcs1格式私钥转换为Pkcs8格式私钥
privateKey = RsaUtil.pkcs1_to_pkcs8(privateKey) encryptText = RsaUtil.rsa_encrypt(text, publicKey)
print("【", text, "】经过【RSA】加密后:", encryptText) decryptText = RsaUtil.rsa_decrypt(encryptText, privateKey)
print("【", encryptText, "】经过【RSA】解密后:", decryptText) signature = RsaUtil.sign(text, privateKey, Hash.MD5)
print("【", text, "】经过【RSA】签名后:", signature) result = RsaUtil.verify(text, publicKey, signature, Hash.MD5)
print("【", text, "】的签名【", signature, "】经过【RSA】验证后结果是:", result)

RSA非对称加密算法实现:Python的更多相关文章

  1. RSA—非对称加密算法

    RSA:非对称加密算法加解密原理如下:已知:p,q,n,e,d,m,c其中:p与q互为大质数,n=p*q 公钥Pk(n,e):加密使用,是公开的 私钥Sk(n,d):解密使用,不公开 c:明文 m:密 ...

  2. RSA非对称加密算法实现:Golang

    RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...

  3. RSA非对称加密算法实现:C#

    RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...

  4. RSA非对称加密算法实现:Java

    RSA是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院工作.RSA ...

  5. SSH加密原理、RSA非对称加密算法学习与理解

    首先声明一下,这里所说的SSH,并不是Java传统的三大框架,而是一种建立在应用层和传输层基础上的安全外壳协议,熟悉Linux的朋友经常使 用到一 个SSH Secure Shell Cilent的工 ...

  6. RSA非对称加密算法实现过程

    RSA非对称加密算法实现过程 非对称加密算法有很多,RSA算法就是其中比较出名的算法之一,下面是具体实现过程 <?php /** */ class Rsa { /** * private key ...

  7. RSA 非对称加密算法简述

    RSA概述 首先看这个加密算法的命名.很有意思,它其实是三个人的名字.早在1977年由麻省理工学院的三位数学家Rivest.Shamir 和 Adleman一起提出了这个加密算法,并且用他们三个人姓氏 ...

  8. .NET Core加解密实战系列之——RSA非对称加密算法

    目录 简介 功能依赖 生成RSA秘钥 PKCS1格式 PKCS8格式 私钥操作 PKCS1与PKCS8格式互转 PKCS1与PKCS8私钥中提取公钥 PEM操作 PEM格式密钥读取 PEM格式密钥写入 ...

  9. 【转载】非对称加密过程详解(基于RSA非对称加密算法实现)

    1.非对称加密过程:         假如现实世界中存在A和B进行通讯,为了实现在非安全的通讯通道上实现信息的保密性.完整性.可用性(即信息安全的三个性质),A和B约定使用非对称加密通道进行通讯,具体 ...

随机推荐

  1. spring boot 启动卡半天

    测试服务器到期,把环境切了,早上过来 ios 和 安卓 都说 测试环境连不上,ps -ef | grep app.jar 查看了一下进程,发现没有启动,于是 重新打包.部署,一顿骚操作后,监控启动日志 ...

  2. CountDownLatch原理

    正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中,countdownlatch的概念是一 ...

  3. 常用 HTTP 状态码

    下面是列举的我在项目中用到过的一些 HTTP 状态码,当然,在具体的使用中并不是用到的状态码越多越好,需要结合自己项目情况来选用适合自己的 HTTP 状态码.   HTTP 状态码 含义说明 200 ...

  4. 【JAVA今法修真】 第三章 关系非关系 redis法器

    您好,我是南橘,万法仙门的掌门,刚刚从九州世界穿越到地球,因为时空乱流的影响导致我的法力全失,现在不得不通过这个平台向广大修真天才们借去力量.你们的每一个点赞,每一个关注都是让我回到九州世界的助力,兄 ...

  5. Linux中定时任务

    目录 一.简介 二.crondtab file 三.crond命令的调试 四.精确到秒的任务计划 一.简介 定时任务在线测试网站 定时任务基本概念: (1).crond是一个daemon类程序,路径为 ...

  6. 背水一战——CSP2021/NOIP2021 游记

    洛谷 version 转载本文章的其他链接: 1(S00021 提供) 2(Ew_Cors 提供) \[\texttt{2021.9.10} \] 终于开坑了. 笑死,初赛根本还没开始复习,反正初赛也 ...

  7. LuoguP2556 [AHOI2002]黑白图像压缩 题解

    Content 题目描述太过于繁琐而无法简化,请前往原题面查看. 数据范围:\(1\leqslant n\leqslant 8\times 10^4\). Solution & Code 一个 ...

  8. LuoguP7534 [COCI2016-2017#4] Kartomat 题解

    Content 火车站里头有一个售票机,其键盘可以看作是一个 \(4\times 8\) 的矩阵,其中第一行的前面三个键和最后一行的最后三个键都是 *,剩余的键按照从上到下,从左到右的顺序依次按照 A ...

  9. java 网络编程基础 UDP协议的Socket:DatagramSocket;广播Socket:MulticastSocket

    什么是UDP协议: UDP协议是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket 但这两个 Socket之间并没有虚拟链路,这两个Socket只是发送.接收数据报的对象.Java 提供了 ...

  10. Django ModelForm表单验证

    ModelForm 在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义 应用场景:定制model admin 的时候可以使用.适用于小业 ...