RSA
关于 RSA 非对称加密算法
RSA 加密算法是一种非对称加密算法,是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在 1977 年一起提出的,RSA 就是他们三人姓氏开头字母拼在一起组成的。RSA 公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
注意
RSA 加解密涉及到密钥位数、密钥格式、密钥语法标准、填充方式等概念,请务必理解后再进行使用,否则可能在使用代码时发生各种报错,认真阅读文档,可解决 99% 的问题!!!
# 生成密钥
关于密钥各个术语的解释
什么是密钥的位数:
该位数既不是指公钥的长度,也不是私钥的长度,实际上是指生成的 RSA 密钥对中公钥和私钥所包含的模数(modulus)的位数,给定一个公钥或者私钥,均可从中解析出模数,由于 RSA 密钥对是基于一个大素数乘积生成的,因此长度也决定了其安全性和加密强度,在实际使用中,密钥位数常见的有 512 位、1024 位、2048 位、3072 位和 4096 位。但实际应用中不推荐 512 位,需要注意的是,密钥长度越长,加密的强度也就越强,但同时也会增加程序计算的时间。例如,秘钥长度增加 1 倍,密钥对生成的时间就增加 16 倍,公钥加密操作时长增加 4 倍,私钥解密操作时长增加 8 倍。因此,选择密钥长度时需要综合考虑安全性和效率。
什么是模数(modulus):
RSA 密钥的模数是公钥和私钥中的一个重要参数,通常用大素数的乘积表示,在 RSA 加密算法中,模数(modulus)是两个大素数的乘积,通常用 N 表示,在密钥生成过程中,选择两个大素数 p 和 q,然后计算它们的乘积
什么是公钥 / 私钥指数:
在 RSA 加密算法中,公钥和私钥都包含一个指数,这些指数是用来进行加密和解密操作的,公钥指数通常用 e 表示,私钥指数通常用 d 表示,这两个指数的选择是相互关联的,确保了 RSA 算法的正确性,通常情况下,公钥指数 e 和私钥指数 d 满足以下条件:
私钥签名(加密):
私钥签名,也称为私钥加密,私钥通常用于对敏感数据进行解密,如果私钥未经授权的访问者获得,可能会导致数据泄露或伪造签名等安全问题,通过加密私钥,即使未经授权的人获得了密钥文件,也需要正确的解密密码才能访问私钥,从而保护私钥的安全。在生成密钥对时,可以指定加密私钥的算法和密码,在使用私钥时,需要提供正确的解密密码才能解密私钥。
密钥输出的格式:
der
:二进制数据,序列化 ASN.1 (opens new window) 结构;pem
:最常见的类型,将 der 数据进行 base64 编码,然后加上以-----
包裹的标头,用于标识密钥类型;jwk
:JSON Web 密钥,关键数据存储在 JSON 对象中,是 JavaScript 对象签名和加密 (JOSE) 规范的一部分;openssh
:OpenSSH 密钥格式,常用于在 OpenSSH 客户端和服务器之间传输密钥,密钥以ssh-rsa
开头。
密钥的语法标准:
- 公钥语法标准:
pkcs1
或spki
- 私钥语法标准:
pkcs1
或pkcs8
有的库里面(如:JS 的 node-rsa
库),公钥语法标准支持 pkcs1
或 pkcs8
,没有 spki
,事实上这是不太规范的说法,参见 issues (opens new window)。
当密钥输出格式为 pem
时:
- 公钥使用
pkcs1
标准,得到的公钥以-----BEGIN RSA PUBLIC KEY-----
开头; - 公钥使用
spki
标准,得到的公钥以-----BEGIN PUBLIC KEY-----
开头; - 私钥使用
pkcs1
标准,得到的私钥以-----BEGIN RSA PRIVATE KEY-----
开头; - 私钥使用
pkcs8
标准,得到的私钥以-----BEGIN PRIVATE KEY-----
开头。 - 私钥使用
pkcs1
标准,如果对私钥进行了加密,则得到的私钥以-----BEGIN RSA PRIVATE KEY-----
开头,但内容里包含Proc-Type
、DEK-Info
字段; - 私钥使用
pkcs8
标准,如果对私钥进行了加密,则得到的私钥以-----BEGIN ENCRYPTED PRIVATE KEY-----
开头。
pkcs 标准科普:
公钥加密标准(Public Key Cryptography Standards, PKCS) (opens new window),是由美国 RSA 数据安全公司及其合作伙伴制定的一组公钥密码学标准,其中包括证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。PKCS#1 至 PKCS#15 是不同类型的标准,用于不同的场景,在 RSA 算法中主要会用到 PKCS#1 和 PKCS#8 两种标准:
- PKCS#1:专门针对 RSA 算法的一个标准,用于 RSA 公钥和私钥的具体实现以及加密、签名算法的规定;
- PKCS#8:通用私钥语法标准,定义了私钥的存储格式,可以用于不同密码学算法的私钥存储。
spki 标准科普:
- 公开密钥基础设施(Public Key Infrastructure, PKI) (opens new window),又称公开密钥基础架构、公钥基础建设、公钥基础设施、公开密码匙基础建设或公钥基础架构,是一组由硬件、软件、参与者、管理政策与流程组成的基础架构,其目的在于创造、管理、分配、使用、存储以及撤销数字证书;
- 简单公钥基础设施(Simple public-key infrastructure, SPKI) (opens new window),是克服传统 X.509 PKI 复杂性的一种尝试,SPKI 规范定义了授权证书格式,提供了特权、权利或其他此类属性(称为授权)的描述,并将它们绑定到公钥。
【实用参考资料】
公钥证书编码解读:https://zhuanlan.zhihu.com/p/77329250 (opens new window)
RSA密钥长度、明文长度和密文长度:https://cloud.tencent.com/developer/article/1199963 (opens new window)
安全:深入理解数字证书中的 PKCS#1 与 PKCS#8 标准 :https://cloud.tencent.com/developer/article/2390956 (opens new window)
PKCS#1、PKCS#5、PKCS#7、PKCS#8 到底是什么?:https://blog.csdn.net/weixin_45264425/article/details/127096145 (opens new window)
# Python 3.0+
# ✅ 安装依赖 pip install pycryptodome,官方文档:https://pycryptodome.readthedocs.io/
# ❌ 密钥输出格式不支持 jwk
# ❌ 公钥语法标准不支持 pkcs1,仅支持 spki
# ❌ 私钥加密:当私钥语法标准为 pkcs1 时,不支持指定算法,默认使用 DES-EDE3-CBC
# 当私钥语法标准为 pkcs8 时,protection 可以指定算法,算法名称参考:https://pycryptodome.readthedocs.io/en/latest/src/io/pkcs8.html#encryption-parameters
from Crypto.PublicKey import RSA
key = RSA.generate(
bits=2048, # 密钥位数,即模数(modulus)的位数,常见的有 512 位、1024 位、2048 位、3072 位和 4096 位
e=65537 # 公钥指数,默认 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
)
private_key = key.export_key(
format="PEM", # 私钥输出格式,支持 pem、der、openssh
pkcs=8, # 私钥语法标准,支持 pkcs1、pkcs8,该参数仅对私钥有效
# passphrase="spiderapi", # 可选参数,私钥加密的密码,如果私钥加密了,则使用时需要先解密,该参数仅对私钥有效
# protection="scryptAndAES128-GCM", # 可选参数,私钥加密的算法,该参数仅对私钥,且 pkcs=8 时有效
)
public_key = key.publickey().export_key(
format="PEM", # 公钥输出格式,支持 pem、der、openssh,公钥语法标准,仅支持且默认 spki
)
print("RSA 公钥(spki、pem):\n\n", public_key.decode("utf-8"))
print("RSA 私钥(pkcs8、pem):\n\n", private_key.decode("utf-8"))
"""
RSA 公钥(spki、pem):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4MIESlYLQMhXeh1AsIxi
XqdbyG6hMo7feRu2CsvH14iYdwaxMZ2gV3PBu+Z9gCD+zoreO4PYMqpn0koXGg2n
VRhTZVzJARVnLokmK3wVFYx2ooubABFv/duL30LzHi2qheXIz5etB0XjOPz1A9D3
OngaHH6YnyoCos0KtDbaiNOdYY2lh5tXG8JV4yaHGmPgHLYjp19EBOYaqiXj89Ut
GtTvc/bl6pO1uZbsR70zZY2yU79+B7UGhsMHTcFdZ7XokLk2uwUoKRYvsD1S/pEX
xIYwq1DJZ4/SMAidVe58jwPEg9Vonb/HZX24l35PSDDKC52oUaEynQcdvnHJoJM9
hwIDAQAB
-----END PUBLIC KEY-----
RSA 私钥(pkcs8、pem):
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDgwgRKVgtAyFd6
HUCwjGJep1vIbqEyjt95G7YKy8fXiJh3BrExnaBXc8G75n2AIP7Oit47g9gyqmfS
ShcaDadVGFNlXMkBFWcuiSYrfBUVjHaii5sAEW/924vfQvMeLaqF5cjPl60HReM4
/PUD0Pc6eBocfpifKgKizQq0NtqI051hjaWHm1cbwlXjJocaY+ActiOnX0QE5hqq
JePz1S0a1O9z9uXqk7W5luxHvTNljbJTv34HtQaGwwdNwV1nteiQuTa7BSgpFi+w
PVL+kRfEhjCrUMlnj9IwCJ1V7nyPA8SD1Widv8dlfbiXfk9IMMoLnahRoTKdBx2+
ccmgkz2HAgMBAAECggEACSTA0Zi0MX5VAgycRp0XcrwClwyvyyOWgidMncjSMvmw
INt+rELk3y9AOO7fY9iJH970u91ubLU+WbGWRK2R2qY4MlNMLBqc+CmFNNdXRj6m
JDu4t7p94LPPT2sPrUZ0qFODpV+0HtZ1hX/TpJmaN+CN82MlE13n/eEzPRykLFUY
DVhXcVYlMamHCtNT9039ByEBF7kIeODhLPYgKAcwCOY8f4fQqEDZUfshbHdOlAt+
Bx9bOToSPqNYMIrzHk/SrUfjI2+x3mVZY5PSSxyBRObroKVd4V+De+bXUyLhdnpC
RmH8JWsFEcfSILMSlkrfA+xGag36oXTD8wtf19X9XQKBgQDqMQ+B3fiicVLirdLx
PB0OD4U2noitzkyjr+qZYx3VpIRu+eK1q9esJ9KYzBUEdfTCXaKHHVcjZ/IErOsZ
eFcBS2Fwwpa3GMeOJ4hTcNuzBIsp6D/g6PwSF4I/lGXTSCep7YEgoana3VItKlqx
FbweB1guMpzS0jpWKVAPFAG3KwKBgQD1sBAXTqZqXcaVLkgZaowdFA2maFDpNp0b
tiyGcyRAhYHdbb4TBFrgSDCYdnMpQMo0H4YmqRQFI38r5ROOsSQDcTNwMf6E9nUX
QlZu1DBri0vnGgbjRTuKIDUEadVrCepCHfYyX7yEMg1vkCqdoknqFICn38R48Gq9
Ab66m+IlFQKBgBv3M9TcPt6XDcDH5RKtjQKq08uL7uJiakB5t1gNv/hNJwthh7MO
DDkgoENiy3e25j13lPrxhABUX1AznfdyqWEcMUyX0AuZR+svyVW9el7MQhoFA+vF
pqQ6bnFNNUOfsCzYkbzl0TSzjSabkiznXYlwcxVBMfzy4ch8MnU6fGH1AoGAZg3/
cR8Lg412istRybT3hLCqxt/4FBfKhRNURXkYqvCKNEd8t/uMIDP8c6hoR8+Q7rvV
hsOe/E91aO9cA17TvdZM7qLlvad+le3JZ3oert2K5vFpwQgmJkcgnrezniXdOB+n
/97CuQrth9UTzqz2FRT1KEaMH0yGmgJajrtn4c0CgYA7N7XM7oI6oH5uG0c2bcNT
oF6CbMKKY6IRmpyrTeozRrNo/luA0v89o6ETdeC/hChzVh66oECz9KW/XVXFyttt
8sOTwXEsdWE4A7oNOM1vQhx7DtKJpqtvZFAxrVhgYyuaZSAEc2isWKhIPWq2mjKD
pByL7lrJPDv9Z7za63nMBQ==
-----END PRIVATE KEY-----
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# ✅ 安装依赖 pip install cryptography,要求 Python 3.7+,官方文档:https://cryptography.io/
# ❌ 密钥输出格式不支持 jwk
# ❌ 私钥语法标准不支持 pkcs1
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.ciphers import algorithms
private_key = rsa.generate_private_key(
public_exponent=65537, # 公钥指数,推荐 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
key_size=2048 # 密钥位数,即模数(modulus)的位数,常见的有 512 位、1024 位、2048 位、3072 位和 4096 位
)
# 从私钥中提取公钥
public_key = private_key.public_key()
# 序列化私钥和公钥
public_key = public_key.public_bytes(
encoding=serialization.Encoding.PEM, # 公钥输出格式,支持 pem、der、openssh
format=serialization.PublicFormat.SubjectPublicKeyInfo # 公钥语法标准,支持 pkcs1、spki (SubjectPublicKeyInfo)
)
private_key = private_key.private_bytes(
encoding=serialization.Encoding.PEM, # 私钥输出格式,支持 pem、der、openssh
format=serialization.PrivateFormat.PKCS8, # 私钥语法标准,支持 pkcs8
encryption_algorithm=serialization.NoEncryption() # 私钥不加密
# encryption_algorithm=serialization.BestAvailableEncryption("password".encode()) # 对私钥加密
)
print("RSA 公钥(spki、pem):\n\n", public_key.decode("utf-8"))
print("RSA 私钥(pkcs8、pem):\n\n", private_key.decode("utf-8"))
"""
RSA 公钥(spki、pem):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunWw+FBw3WGzKuU9tyoP
0UWn0FOD5N7vlfhjFn0FUkeMQlgPqj+4uxNnayMA4Qxj9UeMS/N9+dN8KfIWnvjg
R+UBsSgqZuy/ONx9E23ycq6l2RjGbdIKcRSsmmEKcAjCQub/EglWhzhacwLB4nr/
HQvQS2x/J5NwR9WD8VWoYPICIa+LUSNZAbbA29Fitj7njbJkJbhNX4aaHUSQpWFG
djoFyGmpXb1HhaswmaC1jtZo5xzQfuSIeCq21VNWS2wvKdqcHg7jNbhhst54H3W5
O7Qg7IYiGseYLO2m6f4NxLuhFDfdDHjSNDONzgGvm1fAI1Xs1r01BTx0n3DfSbqz
AQIDAQAB
-----END PUBLIC KEY-----
RSA 私钥(pkcs8、pem):
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6dbD4UHDdYbMq
5T23Kg/RRafQU4Pk3u+V+GMWfQVSR4xCWA+qP7i7E2drIwDhDGP1R4xL833503wp
8hae+OBH5QGxKCpm7L843H0TbfJyrqXZGMZt0gpxFKyaYQpwCMJC5v8SCVaHOFpz
AsHiev8dC9BLbH8nk3BH1YPxVahg8gIhr4tRI1kBtsDb0WK2PueNsmQluE1fhpod
RJClYUZ2OgXIaaldvUeFqzCZoLWO1mjnHNB+5Ih4KrbVU1ZLbC8p2pweDuM1uGGy
3ngfdbk7tCDshiIax5gs7abp/g3Eu6EUN90MeNI0M43OAa+bV8AjVezWvTUFPHSf
cN9JurMBAgMBAAECggEBAKydjcKjvYjFDLf2V0b88n27LVsIJb84v7Ynp5vHC6kb
QXadzYq/yQWvNfuSARtWfCczIGejuAkSxwyR6G0tW3xTPljCJVb5byF1xXi6PUv7
8N9lNzWt0CrVh+C3W5FSGn0TGimZaXhvLBTzBYjkcs5yBFf+zkxWCwkFWkuOD/4G
F9sCAzdrxbHkn1qpbPBCf4NIJ3ETApD3AMFuZol+GzAz1E6xaCupCqf1+yjWGjhE
VjPA6MPx/RqPxI/Xn2BsX9nNEfsyxHmffbG9Hnu487ByOZFOdw/5JWsgCuhnX/0I
cERAhuuXtjya9NuJkMrXGnoXofc7Om79oE0blcXSb60CgYEA5vhlGkaXeduFHJNa
2ATDXrYGO1vEYR3fmxUKE7VYjGWZBzaUAQBFc+KFlpj6/587Hyldi6xG+PUWrMzS
nMDSEgZY+3WdyE9DmUOjp2Mf8sPQYRob3T7osL7ttyaMB5Fv+Rap/HuRla/2FAR7
77nvFsaGmUW+w4YuVWxKjUcVWMsCgYEAzqp6qBdFugCXwZyIasucqI2DKOocnfbR
Rbk0lcpyz2Fl6CqPUc1eJUesoOxZuvShMGpeqWPwiD97lsI6BJ5P7ymalR3XaGBr
nNineop0a2sxj4cbEEcxOXJfl46+MDmDY9n0kOFzULwm0cP1m0VFjMmTLXGnsCRZ
SVQFGMATBeMCgYBhF/54Y0B+K3fzoUZJFQeEIwTPoy4UnVhIezm3Oz60FmmUDK9/
FDweERWTT1AEcU2LNfprIsrbETys+5V16+DjTuPNIY5ojFmgbjy3uwXNKd/JUg5w
nWd4FWsc2Ql4jP0DOzHOP6vdvxC1LYVkK0eEzYP7nsQosZl8s39LkJw6rQKBgFYh
8zDvUh4tdRI6XRi1d7tAD3QT7o1feuTmRaZQU/1eiIx0gHsFbsF219nR56vlnPCC
xKUwg+UlICs7E9cs6/+vhT+0yjw0Q2WBXnvSDKdga614D61/HmLk6jZORbHvpnUN
N8LSU69IW519YHWwL0Z4FKESB2OAIr5PCDjChKslAoGBAIe5+HFJyOZTt3Urzwzc
7h8q97z+DXRChzTiBv8KaM3hknmKYc9qoGpOK6FqM8GcotvI55ZGlixJtmy1GMRf
nk1qENc23oadYBEzAcQA5+0me/QDxk0q0BdkDkaNH2NA6lMY/4TriNde/fSY7Dil
bDVst9Y7yqL41PYRWM/rhWas
-----END PRIVATE KEY-----
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# ✅ 安装依赖 pip install rsa,官方文档:https://stuvel.eu/python-rsa-doc/
# ❌ 密钥输出格式不支持 jwk、openssh
# ❌ 公钥语法标准不支持 spki
# ❌ 私钥语法标准不支持 pkcs8
# ❌ 不支持对私钥进行签名、加密
import rsa
(public_key, private_key) = rsa.newkeys(
nbits=1024, # 密钥位数,即模数(modulus)的位数,常见的有 512 位、1024 位、2048 位、3072 位和 4096 位
exponent=65537 # 公钥指数,默认 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
)
# 公钥和私钥输出各种都仅支持 pem 和 der,语法标准都只支持 pkcs1
public_key = public_key.save_pkcs1(format="PEM")
private_key = private_key.save_pkcs1(format="PEM")
print("RSA 公钥(pkcs1、pem):\n\n", public_key.decode("utf-8"))
print("RSA 私钥(pkcs1、pem):\n\n", private_key.decode("utf-8"))
"""
RSA 公钥(pkcs1、pem):
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
RSA 私钥(pkcs1、pem):
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Make sure to add code blocks to your code group
# JavaScript Node.js ECMAScript 5.1+
// ✅ Node.js 内置 crypto 模块,无需单独安装
// ❌ 密钥输出格式不支持 openssh
var crypto = require("crypto");
var { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
modulusLength: 1024, // 密钥位数,即模数(modulus)的位数,常见的有 512 位、1024 位、2048 位、3072 位和 4096 位
publicExponent: 65537, // 公钥指数,默认 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
publicKeyEncoding: {
type: "spki", // 公钥语法标准,支持 pkcs1、spki
format: "pem" // 公钥输出格式,支持 pem、der、jwk
},
privateKeyEncoding: {
type: "pkcs1", // 私钥语法标准,支持 pkcs1、pkcs8
format: "pem", // 私钥输出格式,支持 pem、der、jwk
// cipher: "aes-256-cbc", // 可选参数,私钥加密的算法,如 aes-256-cbc、des-ded3-cbc 等,如果私钥加密了,则使用时需要先解密
// passphrase: "spiderapi" // 可选参数,私钥加密的密码
}
});
console.log("RSA 公钥(spki、pem):\n\n", publicKey);
console.log("RSA 私钥(pkcs1、pem):\n\n", privateKey);
/*
RSA 公钥(spki、pem):
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDki91MwofoyFW+TPdkDLjvww9q
GjKzgzbEhTUrl5qBwjWQo/yr1nhbTC4i9Qso8XJS8350cwz2ixbkE0QJgdPtL8d2
lLUIVDxTy8uAFITvYie7rHNanjPyB2ytnm8p85EyYKZnAlq5V3w9hNAM5XxGnffi
y4PiS7OlhAdVLZM32QIDAQAB
-----END PUBLIC KEY-----
RSA 私钥(pkcs1、pem):
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDki91MwofoyFW+TPdkDLjvww9qGjKzgzbEhTUrl5qBwjWQo/yr
1nhbTC4i9Qso8XJS8350cwz2ixbkE0QJgdPtL8d2lLUIVDxTy8uAFITvYie7rHNa
njPyB2ytnm8p85EyYKZnAlq5V3w9hNAM5XxGnffiy4PiS7OlhAdVLZM32QIDAQAB
AoGBAJon0QxOhne4cUVcCt5cSn3Gl2Yc56f30IA7zYJqztfJVHIMeoi5sBL8zn3b
xTxHp7JV9Sy80biWVsleSV0USgoDCkTZqgJTq7pTeUg+LTRSplPb00sm1/gyS7fU
vwYtCDA8E/4NaG+gCdHAH4TDUOy2JPXF4L3VOBiDpaB+aB0BAkEA8f1qIOWQv7EY
QNPdbMx9+/2miR/DoPtyyus1Nb+FTNzcZE0/JP8NLJUh7cBhtvRRi0RzhsOYMwK6
ypCUDZ4Q+QJBAPHHMzOiFlqIedrgZxiGUTZiGovMhBd3OKVYJj8Zr7BbM7TBkf9o
U3v0LgMhFV7DEt/JXcwlexKmudYufyyo9eECQBwh7OukJJ7UdNBckRpr752TEIBS
jAi0EtVaYNY9zL5x0sFqZZPkfuCW+dnNCs8dOjmpnJCnPpN3lsWj50JqBOkCQQDq
rh0v6AvkkoYdAyZu8qlPrUfxHHG2yT1NmNN++jLDbrMwp5dMH3qxXWFwHiO9GIJw
f+ewqUzd3MGTeQxuUA5hAkBkkA65Jwhg5DrL7GFLj7m3phyPED+Uk2pP7GJ5vIFf
QgM7yYJFHvKg/enuc2w2aAni+V8Z4DfwWeDlhPjcPyhb
-----END RSA PRIVATE KEY-----
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// ✅ 安装依赖:npm install node-rsa
// ❌ 密钥输出格式不支持 jwk、openssh
// ❌ 不支持对私钥进行签名、加密
// ❓ 注意:截止 2024.03,该库中公钥语法标准支持 pkcs8,但实际上不存在这种说法,具有争议,正确应该是 spki,参见:https://github.com/rzcoder/node-rsa/issues/208
var NodeRSA = require("node-rsa");
var key = new NodeRSA({
b: 1024, // 密钥位数,默认 2048,即模数(modulus)的位数,常见的有 512 位、1024 位、2048 位、3072 位和 4096 位
e: 65537 // 公钥指数,默认 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
});
// 生成密钥,传入参数格式:语法标准-密钥类型-输出格式,即 scheme-[key_type]-[output_type]
var publicKey = key.exportKey("pkcs1-public-pem"); // 公钥语法标准支持 pkcs1、pkcs8,输出格式支持 pem、der
var privateKey = key.exportKey("pkcs8-private-pem"); // 私钥语法标准支持 pkcs1、pkcs8,输出格式支持 pem、der
console.log("RSA 公钥(pkcs1、pem):\n\n", publicKey);
console.log("RSA 私钥(pkcs8、pem):\n\n", privateKey);
/*
RSA 公钥(pkcs1、pem):
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALBIxnoOWWhdvAzaicfo5UB2DbSEa2u9LPQl0DrZSnQduRPs/EHh0EqC
QlBBJndqa0QuWAp5In/Q4Sjc2lcF7oB8MEzz1P+D/2M2vy1EunXD8XbMBDbyNAvg
k6yldcT3jEP1yhZjH9JnvgC9JsBFSjC9pUsZbhFDZwY6XLvw9oF7AgMBAAE=
-----END RSA PUBLIC KEY-----
RSA 私钥(pkcs8、pem):
-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALBIxnoOWWhdvAza
icfo5UB2DbSEa2u9LPQl0DrZSnQduRPs/EHh0EqCQlBBJndqa0QuWAp5In/Q4Sjc
2lcF7oB8MEzz1P+D/2M2vy1EunXD8XbMBDbyNAvgk6yldcT3jEP1yhZjH9JnvgC9
JsBFSjC9pUsZbhFDZwY6XLvw9oF7AgMBAAECgYEAgfs3NZpM/HJZDVU6UIf+OfiS
BG+7UTas5dzX2/yKNHISHIoaOm3JipbfVJOlTFnQe/Z7/kTxVjNrQhkOeSorf6Ee
Zg64JAMOxCb3aEJ6jABZUCK5DnBkcBv3qoPI6FrwrZNcTDypUGE6zxFfxehetGlQ
hyJ4xgddFNXg9oxoTKECQQDnpUujoYCSFITC+UDnMXCcV5LXk0wyicySL1+YeP8o
ymz3LYUTyR0p1JoMeXdg2VpQ3BVX4QDNRGv9mS79dI+xAkEAwtFv2U3egkUacdNv
vkWgMSVZc7YtlPdiW91wyVmAqxqFNBOVDOBXcuHcZ1o8mzPMgJVwSkjldvi73Ko5
s5C66wJBAMVikEVqRMg1O7t38NoPwsk1xiZzmSYnTW3zeB3QXHxBoQAuhYsKgBM4
2dtvVU3tZ4wnPPiY/bnrZ6m8cdH/FMECQAuhx6TY4mUyzQ5oym446ASnLz0aboRL
dQL5KMfM4ULWFYfzd13Kc043sBo3qBC4OgifY5H74j+FQGo/e6x+ArsCQQCtogcc
uKx8DHSON+lPQQfgD9A8vCtJVC7pyzzthMoUbmiGnv+VzbPkfuPaiamdVZy6j6qM
vuQJ+AB8c5SoY5rb
-----END PRIVATE KEY-----
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// ✅ 安装依赖:npm install jsencrypt
// ❗ 如果在 Node 环境中使用,会遇到报错 window is not defined,处理方法:
// 1.在当前 JS 文件顶部添加代码:window = global;
// 2.在 \node_modules\jsencrypt\bin\jsencrypt.js 添加代码:window = global;
// ❌ 不支持对私钥进行签名、加密
// ❌ 密钥输出格式不支持 der、jwk、openssh,仅支持 pem
// ❌ 公钥语法标准不支持 pkcs1,仅支持 spki
// ❌ 私钥语法标准不支持 pkcs8,仅支持 pkcs1
var JSEncrypt = require('jsencrypt');
var crypt = new JSEncrypt({
default_key_size: "1024", // 密钥位数,默认 1024,即模数(modulus)的位数,常见的有 512 位、1024 位、2048 位、3072 位和 4096 位
default_public_exponent: "010001" // 公钥指数,默认 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
});
var publicKey = crypt.getPublicKey(); // 公钥语法标准默认 spki,输出格式默认 pem
var privateKey = crypt.getPrivateKey(); // 私钥语法标准默认 pkcs1,输出格式默认 pem
console.log("RSA 公钥(spki、pem):\n\n", publicKey);
console.log("RSA 私钥(pkcs1、pem):\n\n", privateKey);
/*
RSA 公钥(spki、pem):
-----BEGIN PUBLIC KEY-----
MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGq2tRBEpDRG26JrXmBxxThGbufn
C2yw0biiXUf3BPzPx65TQ5vgiOoOnGYWl3wIhzlACPVWW4gto+nk2elcwin9flDb
vxtJCiBvEVqAaGb3ceiMe56xFnYs88PnDImzecguMCFmwhpbRpkLuvpF8fW4I2+M
aa3zON2rB5A2yMAxAgMBAAE=
-----END PUBLIC KEY-----
RSA 私钥(pkcs1、pem):
-----BEGIN RSA PRIVATE KEY-----
MIICWgIBAAKBgGq2tRBEpDRG26JrXmBxxThGbufnC2yw0biiXUf3BPzPx65TQ5vg
iOoOnGYWl3wIhzlACPVWW4gto+nk2elcwin9flDbvxtJCiBvEVqAaGb3ceiMe56x
FnYs88PnDImzecguMCFmwhpbRpkLuvpF8fW4I2+Maa3zON2rB5A2yMAxAgMBAAEC
gYBd5OTrq3nPhYk7H72qnnApU8/BvEkRGYNuMW5iI7b/utK3UAvs22Ocjb6PFNG1
EMvqU62OMK3Y5E+VPQd/jV5I8C8n2BymrJ2MexCFow9jKneZYX5OLdRitJw+FAxL
8OnlLHs4nRlKiWJbdZ2Y/OnlYpAmHpStmAs+2loI/AWsAQJBALNOLJYCgZcm8yOO
cjnt+Q2gbPUWUfRha+x4oZ9jKFVk/xtYQ9GrWysYyi2IBfFkP362OrAdJHdCpjT+
6DhA/30CQQCYW8p0mRb0WtNmqLF+W7c+8CbPQ4+YeCnADzldNZkRshg/BgOMM41P
zVMqYFmlhHepIrno0uA6pNqrDi6Sx8nFAkBoviX1i4lATxSBlNjNVmLCvxBnK568
b5yoCt//R+Fr4Q/VXX5goQUk69pPNsKh/LnKv5ERCDUhJeIJ2060bePRAkAUSv2P
RCi7iTFpFgT2GI8ysdfpeU0x+KdO7ngsgwwNQFRcaJemX+NtgqKWHVkzY45wl7B9
Y0D8bqK1b+EiKbwlAkBB1wPeHe97FJ1QaleMhjDIWLjZZiX1UZYrDbaUbmLwhzmM
1pXmXbW1K0VxC9jcKpN7htwYvOmXuYdOsGHdG1MW
-----END RSA PRIVATE KEY-----
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Make sure to add code blocks to your code group
# Golang 1.0+
// ✅ 无需安装依赖,官方文档:https://pkg.go.dev/crypto
// ❌ 公钥指数不支持自定义,默认 65537(0x10001),该值是除了 1、3、5、17、257 之外的最小素数
// ❌ 密钥输出格式不支持 jwk、openssh
// ❌ 对私钥进行签名、加密,只支持 pkcs1 标准的私钥,不支持 pkcs8 标准的私钥
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
func main() {
rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
fmt.Println("Generate key failed:", err)
return
}
// 私钥输出格式 der,私钥语法标准支持 pkcs1 (MarshalPKCS1PrivateKey)、pkcs8 (MarshalPKCS8PrivateKey)
privateKeyDER := x509.MarshalPKCS1PrivateKey(rsaKey)
// 可选操作:使用密码加密私钥,注意,EncryptPEMBlock 方法正在被弃用,该方法只能加密 pkcs1 标准的私钥
// blockType 参数指定密钥的标头,与私钥语法标准对应:pkcs1 加密对应 "RSA PRIVATE KEY"
// alg 参数指定加密算法,参见:https://pkg.go.dev/crypto/x509#PEMCipher
password := []byte("spiderapi")
encryptedPrivateKeyPEMBlock, err := x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", privateKeyDER, password, x509.PEMCipherAES256)
if err != nil {
fmt.Println("Private key encrypt failed:", err)
return
}
encryptedPrivateKeyPEM := pem.EncodeToMemory(encryptedPrivateKeyPEMBlock)
// 将私钥转为 pem 格式
// Type 参数指定密钥的标头,与私钥语法标准对应:pkcs1 对应 "RSA PRIVATE KEY",pkcs8 对应 "PRIVATE KEY"
privateKeyPEM := pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyDER,
})
// 公钥输出格式 der,公钥语法标准支持 pkcs1 (MarshalPKCS1PublicKey)、spki (MarshalPKIXPublicKey)
publicKeyPEM, err := x509.MarshalPKIXPublicKey(&rsaKey.PublicKey)
if err != nil {
fmt.Println("Public key encoding failed:", err)
return
}
// 将公钥转为 pem 格式
// Type 参数指定密钥的标头,与公钥语法标准对应:pkcs1 对应 "RSA PUBLIC KEY",spki 对应 "PUBLIC KEY"
publicKey := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeyPEM,
})
fmt.Println("RSA 公钥(spki、pem):\n\n", string(publicKey))
fmt.Println("RSA 私钥(pkcs1、pem):\n\n", string(privateKeyPEM))
fmt.Println("RSA 加密后的私钥(pkcs1、pem、aes-256-cbc):\n\n", string(encryptedPrivateKeyPEM))
}
/*
RSA 公钥(spki、pem):
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1P94ik8uUca0kq613hw0
dy0i/dALloDg4I32lkk7eWV/obe2I/qEY2Nz7SmmY8VZeJUfiQuAVuOxFYI7rKPM
4LvSvkKC5xcWho1319eyZKC1AYlXKHjQPrUXNrDwmM1racGw9NopFg/GyikhaZiT
vsW7NM3O3HN26irQXFO0C7vypIaZtOIB9YVA9YFpBLNnINczRyekltoZqhL4j/Of
C+VuXZOxL0wfJOML7axF4Fwt7XSir8BPJMoEc2KVFYxMMd06tfJMRzvHOEckOaob
ZLrZjHM4YzDr32ClpgCazx7QWsBiMo3AqMuNO+LBV/VynsZPymgehIiDRGr7+S0F
ywIDAQAB
-----END PUBLIC KEY-----
RSA 私钥(pkcs1、pem):
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1P94ik8uUca0kq613hw0dy0i/dALloDg4I32lkk7eWV/obe2
I/qEY2Nz7SmmY8VZeJUfiQuAVuOxFYI7rKPM4LvSvkKC5xcWho1319eyZKC1AYlX
KHjQPrUXNrDwmM1racGw9NopFg/GyikhaZiTvsW7NM3O3HN26irQXFO0C7vypIaZ
tOIB9YVA9YFpBLNnINczRyekltoZqhL4j/OfC+VuXZOxL0wfJOML7axF4Fwt7XSi
r8BPJMoEc2KVFYxMMd06tfJMRzvHOEckOaobZLrZjHM4YzDr32ClpgCazx7QWsBi
Mo3AqMuNO+LBV/VynsZPymgehIiDRGr7+S0FywIDAQABAoIBAQDSQhYFwkAhLZvX
KGwTg5gvBPmDv7mQqkxSnxEKLeRt48noI+fDAGtriSNIvFKqLogxxlNI/3eDTmTi
rJqnw1Jdjkts0U9TO7FaxY/GHADX4OSNTbwiEZDQNgdiT6xRyoX78d3y9uCUDKLZ
sVxwVtOSALLaX0eSytBaPEVOvrn+0Y06x/jiKhHvw1LCNc+E0lp3myrwW+6f0LCJ
KD4dc5AWop64psKwDXP2t8bcyK5uhLjZYiSKjSi+7y8kCNmN0LimYjbjt8nvHo1J
s24BbfE/MwrXhuV2/1ODBezPoOLBm51rzt9syHHnQBh95LPdLPr5N5r5uPvkToDu
X5eM5ughAoGBAPxvHiyoKjWTc2cYw2exsabp2OOkKHH5BP8VBErEvTzmbzr9mKFR
PG0ZcxLnSPux9xaoExdNd+NPnVWl5sR3ZLezGLSaeZw5RagTlkQ/YOXZ6b7mWZcE
hpZNlvSyG3dIP63N4ONwTCpRrjyndv/sSGARrHsp4I1mv+23cQaQfvADAoGBANgB
vUh8Uekq6SuJ2MmvX63cq5kK6BejWfEk6xFlHOTE49yzorn8yJoy1dBoO5BN1VcZ
NUPSNt7PP0HR0BAgX5pKun/dAIs9+Y4HJPojeLkkhFgjx0FxQrQ2usIAaqAwZlpC
rzClr7/8ZO5jeZMdfxcqE43KNrWOWGleyYQnr9yZAoGAcMPCmvhUQrKnrrplMAE0
9vcnqClA2AkBrmFZFX1le7sEnTmD4SxE7gecXCltdOI/GqPiQ1qb37NE+Wmu+LzN
BTLAKo2HHb6H21lEmyAkzQjXXivQgaHH7YSjlpOpqVNg/uclOvSDUbRDPV0hz5lh
i2jZv/spEIGB41M67k/GJLkCgYAzRZZsUjYPJoRaNUoj9WC8oBiLJy+YDMoYly7E
3j9RffqoNGt3wizLjS17XoJk6lSta+pcwtULZh4ZvXepnEWVFg/WsdqjMn6926xH
Q4wwRh6z3So6umue4y7JRdgJVfO1kQaMgYeKBpreivYcmW/FS9OAYHND/Rm3SSyE
FfeEYQKBgAVICBeE9LrMzoPwaTiGcRwEbx13Mo2SgzrKiwSY960Ewlu5t17197e0
EEqJ1Y+ItIA+4j9XEMu6e1hV56Zy9rNEOyUZSB83tB1TQTzasbTDLfh0vJZmbudF
6VTo4nST7kLzJYJe4A1SF2gLKasrbBL0Ye22PK2AuwHIWca2e+OS
-----END RSA PRIVATE KEY-----
RSA 加密后的私钥(pkcs1、pem、aes-256-cbc):
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,3a42d48c94f2f06b0354a04de8247917
6rr+ZAQXJXS3zv9gZUbSp+Ft1ngcjshRrlKYcbeXaBPbWwfwE0iwG47aSJIpAvR1
ac2NhCTyq8ATqbjrhdf4dSHGYwpLJZzdQ7X+g3FmvJpLJMglaLhM2ls+IN+ofOS+
Bp9DwCSvdvTQEocHqTImXS98Bb6pr49FdJmQMma8pm2U73fIro8apVTDwQD/iHIB
nEQ6+ZvUIqp+spEifYle0d1q1ADU/ZavqMt21bDhz56Ccf++6unXk+BhYVGj1WX0
LYmZS8yRVHWDPk19i8yOCeMfZSS929JhCIsRVWYomxSVdwQP6h2iG4tU2+5mvDo1
Pbr4BrLKjFCO3ixhbjmW+ySNoNB/dNkkNd4eaBvmUoC1A/sNz3rJQR2Kl5r9kOCi
iVzh7hpPHTGmW9GY3PBYsIIE84HwrMpmcHHX/qWg/P5B/qAqOXQb4n8UozwuICdn
w/i8c/k6YwOndYkIUqJjUg4KmWTdAQkyaCceBi/i4p9XgWZvq7MKQSQw0K9SeBoz
Q7zUmJjFBtaLN/N3ckyuTeWQOZtGlVjK/rZKFy99RsMum//HX+S8XciUgs2p8A0f
HMrIpgFg3XQSW5el4ykNdS216hEmMtUWfrGhn5D4UEDIHMRF5j9abR2T2BhKbh8m
KcagOdBRRdKBH8JU8l3NT+tSYI+DpbMFH7X1QwfZNVlChAZblipOT9PpW4LbuZhv
nIDU7KjodaV1JrRSOs/+9ferPKxkCXsGj3n5W/9wfbwUnChhhuYXvBVbNd48Os9m
j5jQFVdcxQNe4UyYa7L3KaEzbp9GwX6MsUbiATH7jqEqfero50oTEznWKh4GQtrZ
UL5QhESMEb+3X+JC1nu3aFzbvm+Y0dRjj5bi/R4wk1CAMIOWyT/iYSz+Oe9CNsVA
gKQ5pjY4fwrLjwXVDsm52sQT99V6fVWbUXmg1iNrZ3hbLZ7sGZ0iK6ecz+x4zzMG
m7/7Lbdb0wwGD+K5RPtDmmR9PvwCbxdfQGy8sLyUnUIB1btLRyTnPTXseuIZyFLu
BKWTeLWhqya2h7B9iDYxQq1ySKAJaD8n6Rp+plUqJiyaO/RYcJRwun/U/GVuSfct
YT1BytgfGqM6GL0S+RzFuaG7EYgg8vRuKwHw9rjdaIIz//cL/Y8YCJhJIhmVd7GJ
NE5f+DXPvhhMf/12CF/rcGy6VVGnhlCHN+6dHWeodcbQVbuMJaznasqTk8NuWV75
fZ70FmdHlJHHzTmZ/bQe6qp/1IKLYxa5v8lZEG9ER2hQ2uSjOzLt0nRc8K/HX7xA
Fi+8mRxjsOok75QKfJHNyCXL33hxDclnGbqANUp8bE45h1F3RWnQ60QYc6/EVE9Y
FOKqqOMrTjcIebJN4zYNUDT1OClB6VdyaJLmPtzIYDE07qwWoHdGWVQmrofR/hzL
5+c3LY2AtxQvIyWJc7BmP6lp46KmoUcc9BLkydi5bp9XDM2OgZGjHN9pkdhqdyNH
3zkUzf5dimvaPLHHlKtz1MNF7LTkPRJX94ATq1PDhsgX9OX0lvI10lb+MCI483Mq
IOIIMVT9256lXj+b+q+AhxkhSg4vMLmv28/O8+QZehwcqM1CeA4qzafLGziA/6tl
-----END RSA PRIVATE KEY-----
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# 解析密钥
关于解析 RSA 密钥
PKCS1 RSA 公钥和私钥格式的 ASN.1 (opens new window) 规范如下:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
为了提高效率,许多流行的加密库都使用基于中国剩余定理(CRT)来优化加速解密和签名,所以 prime1、prime2 等值已预先计算并存储为私钥的一部分,如果给定一对 RSA 密钥,那么我们就可以从中解析出以下信息:
- keySize:密钥的位数,即模数(modulus)的位数
- modulus:模数
,一个大素数的乘积,用于生成公钥和私钥,参见前面生成密钥中对模数的解释 - publicExponent:公钥指数
,参见前面生成密钥中对公钥指数的解释 - privateExponent:私钥指数
,参见前面生成密钥中对私钥指数的解释 - prime1:RSA 算法中的第一个质数
,用于生成私钥 - prime2:RSA 算法中的第二个质数
,用于生成私钥 - exponent1:私钥指数模
的模反元素,即 - exponent2:私钥指数模
的模反元素,即 - coefficient:模反元素之间的系数,即
【实用参考资料】
公钥加密标准 PKCS#1 rfc3447:https://www.rfc-editor.org/rfc/rfc3447 (opens new window)
使用中国剩余定理(CRT)来加速 RSA 算法的计算:https://www.di-mgt.com.au/crt_rsa.html (opens new window)
维基百科 Using the Chinese remainder algorithm:https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Padding_schemes (opens new window)
# Python 3.0+
# ✅ 安装依赖 pip install pycryptodome,官方文档:https://pycryptodome.readthedocs.io/
from Crypto.PublicKey import RSA
# 注意 """ 之后要紧跟着密钥标头,如果换行可能会因为无法解析导致报错:ValueError: RSA key format is not supported
# spki 标准 pem 格式的公钥
public_key_pem = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl7HWuXcOH9I/Bud7dplYxHOEC
D82fJv1WJKADhmILCxDLJLVkueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5
jrHT8zw8InrNRwlDeCyx/Q+ETpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faN
w6cBVKhFn+fuItSGfQIDAQAB
-----END PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pem = """-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCl7HWuXcOH9I/Bud7dplYxHOECD82fJv1WJKADhmILCxDLJLVk
ueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5jrHT8zw8InrNRwlDeCyx/Q+E
TpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faNw6cBVKhFn+fuItSGfQIDAQAB
AoGBAKSmc1kmfoQJciZh1gDJsTpnV/l9ySQnwrma+pbE4cHnpzCPKtnbgfcfNNWh
CJljGupfyvzbs1SZkCUL/B1yBR3uAbWw5G0uzJo61wYciufnQA1/lu3JyEyLeSxb
eFOIkuI8Ce0SCPT01+6sR77EA0VtUA+0Ak7OI4EvElFPn0qBAkEA8SvKXG6suLFL
9TjUH2B1XDwMxQFw7JOOhAyLcbNJMLgqMhHuqvTW/T4oxTQh7LbDMP977ZDnkmdt
L8S7zAHHsQJBALAgOFkbNNH4FzBQtxyWEu6+D0ZhvhIAIoH0pDBdoIO9vKalRgWy
vV6YsI3NujjBjz1p7g3Zb/zliA3vH9ieqo0CQQCdlOVmvBIzo/Vjx7wivF4y5DHb
z/M/QbMPaTr8Eg+yu8MmcD0oi06mriTppgS8rTahH26UbehB6z6Wxc+Hn2ohAkEA
r2GmOrToyBzvmmEFtiWK/MmtlDxIdMxFkHr39GGHMSiC7r6tF4eBIu2RAePWiCXW
aSVOs+PNrFs0PAvd/mshEQJAYpxilxZI7hJT89Qne6CgPXqqZf0sFX0FeR9AJaj1
g2c+B9GgZ+Nou4ne4WXjOVUWZuuch7yqn3XoxeQT4/xaCw==
-----END RSA PRIVATE KEY-----
"""
# 解析公钥和私钥
public_key = RSA.importKey(public_key_pem)
private_key = RSA.importKey(private_key_pem)
# 获取模数(modulus),使用 16 进制字符串表示,从公钥和私钥中均可获取,且值是一样的
modulus = hex(public_key.n)[2:] # 或者 private_key.n
# 计算密钥的位数,即模数(modulus)的位数,16 进制转换为位数时每个字符代表 4 位
key_length = len(modulus) * 4
# 获取公钥指数
public_exponent = hex(public_key.e)[2:]
# 获取私钥指数
private_exponent = hex(private_key.d)[2:]
# 获取私钥其他参数
private_prime1 = hex(private_key.p)[2:]
private_prime2 = hex(private_key.q)[2:]
private_exponent1 = hex(private_key.d % (private_key.p - 1))[2:]
private_exponent2 = hex(private_key.d % (private_key.q - 1))[2:]
private_coefficient = hex(pow(private_key.q, -1, private_key.p))[2:]
print("(16 进制)模数: ", modulus) # a5ec75ae5dc387f48fc1b9dedda656311ce1020fcd9f26fd5624a00386620b0b10cb24b564b9e0507f0508b4f10b17744b86cfb7f973587c68b3ecf3cf871575a5ecb98eb1d3f33c3c227acd470943782cb1fd0f844e94a94089af20b7f44411ed9ce815a5be35ba1285db8c061f8abbf9f68dc3a70154a8459fe7ee22d4867d
print("(16 进制)密钥 & 模数位数: ", key_length) # 1024
print("(16 进制)公钥指数: ", public_exponent) # 0x10001 (65537)
print("(16 进制)私钥指数: ", private_exponent) # a4a67359267e8409722661d600c9b13a6757f97dc92427c2b99afa96c4e1c1e7a7308f2ad9db81f71f34d5a10899631aea5fcafcdbb3549990250bfc1d72051dee01b5b0e46d2ecc9a3ad7061c8ae7e7400d7f96edc9c84c8b792c5b78538892e23c09ed1208f4f4d7eeac47bec403456d500fb4024ece23812f12514f9f4a81
print("(16 进制)私钥 prime1: ", private_prime1) # f12bca5c6eacb8b14bf538d41f60755c3c0cc50170ec938e840c8b71b34930b82a3211eeaaf4d6fd3e28c53421ecb6c330ff7bed90e792676d2fc4bbcc01c7b1
print("(16 进制)私钥 prime2: ", private_prime2) # b02038591b34d1f8173050b71c9612eebe0f4661be12002281f4a4305da083bdbca6a54605b2bd5e98b08dcdba38c18f3d69ee0dd96ffce5880def1fd89eaa8d
print("(16 进制)私钥 exponent1: ", private_exponent1) # 9d94e566bc1233a3f563c7bc22bc5e32e431dbcff33f41b30f693afc120fb2bbc326703d288b4ea6ae24e9a604bcad36a11f6e946de841eb3e96c5cf879f6a21
print("(16 进制)私钥 exponent2: ", private_exponent2) # af61a63ab4e8c81cef9a6105b6258afcc9ad943c4874cc45907af7f46187312882eebead17878122ed9101e3d68825d669254eb3e3cdac5b343c0bddfe6b2111
print("(16 进制)私钥 coefficient: ", private_coefficient) # 629c62971648ee1253f3d4277ba0a03d7aaa65fd2c157d05791f4025a8f583673e07d1a067e368bb89dee165e339551666eb9c87bcaa9f75e8c5e413e3fc5a0b
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# ✅ 安装依赖 pip install cryptography,要求 Python 3.7+,官方文档:https:#cryptography.io/
from cryptography.hazmat.primitives import serialization
# spki 标准 pem 格式的公钥
public_key_pem = """
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl7HWuXcOH9I/Bud7dplYxHOEC
D82fJv1WJKADhmILCxDLJLVkueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5
jrHT8zw8InrNRwlDeCyx/Q+ETpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faN
w6cBVKhFn+fuItSGfQIDAQAB
-----END PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pem = """
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCl7HWuXcOH9I/Bud7dplYxHOECD82fJv1WJKADhmILCxDLJLVk
ueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5jrHT8zw8InrNRwlDeCyx/Q+E
TpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faNw6cBVKhFn+fuItSGfQIDAQAB
AoGBAKSmc1kmfoQJciZh1gDJsTpnV/l9ySQnwrma+pbE4cHnpzCPKtnbgfcfNNWh
CJljGupfyvzbs1SZkCUL/B1yBR3uAbWw5G0uzJo61wYciufnQA1/lu3JyEyLeSxb
eFOIkuI8Ce0SCPT01+6sR77EA0VtUA+0Ak7OI4EvElFPn0qBAkEA8SvKXG6suLFL
9TjUH2B1XDwMxQFw7JOOhAyLcbNJMLgqMhHuqvTW/T4oxTQh7LbDMP977ZDnkmdt
L8S7zAHHsQJBALAgOFkbNNH4FzBQtxyWEu6+D0ZhvhIAIoH0pDBdoIO9vKalRgWy
vV6YsI3NujjBjz1p7g3Zb/zliA3vH9ieqo0CQQCdlOVmvBIzo/Vjx7wivF4y5DHb
z/M/QbMPaTr8Eg+yu8MmcD0oi06mriTppgS8rTahH26UbehB6z6Wxc+Hn2ohAkEA
r2GmOrToyBzvmmEFtiWK/MmtlDxIdMxFkHr39GGHMSiC7r6tF4eBIu2RAePWiCXW
aSVOs+PNrFs0PAvd/mshEQJAYpxilxZI7hJT89Qne6CgPXqqZf0sFX0FeR9AJaj1
g2c+B9GgZ+Nou4ne4WXjOVUWZuuch7yqn3XoxeQT4/xaCw==
-----END RSA PRIVATE KEY-----
"""
# 解析公钥和私钥
public_key = serialization.load_pem_public_key(public_key_pem.encode())
private_key = serialization.load_pem_private_key(private_key_pem.encode(), password=None)
public_numbers = public_key.public_numbers()
private_numbers = private_key.private_numbers()
# 获取模数(modulus),使用 16 进制字符串表示,从公钥和私钥中均可获取,且值是一样的
modulus = hex(public_numbers.n)[2:] # 或者 private_numbers.public_numbers.n
# 计算密钥的位数,即模数(modulus)的位数,16 进制转换为位数时每个字符代表 4 位
key_length = len(modulus) * 4
# 获取公钥指数
public_exponent = hex(public_numbers.e)[2:]
# 获取私钥指数
private_exponent = hex(private_numbers.d)[2:]
# 获取私钥其他参数
private_prime1 = hex(private_numbers.p)[2:]
private_prime2 = hex(private_numbers.q)[2:]
private_exponent1 = hex(private_numbers.dmp1)[2:]
private_exponent2 = hex(private_numbers.dmq1)[2:]
private_coefficient = hex(private_numbers.iqmp)[2:]
print("(16 进制)模数: ", modulus) # a5ec75ae5dc387f48fc1b9dedda656311ce1020fcd9f26fd5624a00386620b0b10cb24b564b9e0507f0508b4f10b17744b86cfb7f973587c68b3ecf3cf871575a5ecb98eb1d3f33c3c227acd470943782cb1fd0f844e94a94089af20b7f44411ed9ce815a5be35ba1285db8c061f8abbf9f68dc3a70154a8459fe7ee22d4867d
print("(16 进制)密钥 & 模数位数: ", key_length) # 1024
print("(16 进制)公钥指数: ", public_exponent) # 0x10001 (65537)
print("(16 进制)私钥指数: ", private_exponent) # a4a67359267e8409722661d600c9b13a6757f97dc92427c2b99afa96c4e1c1e7a7308f2ad9db81f71f34d5a10899631aea5fcafcdbb3549990250bfc1d72051dee01b5b0e46d2ecc9a3ad7061c8ae7e7400d7f96edc9c84c8b792c5b78538892e23c09ed1208f4f4d7eeac47bec403456d500fb4024ece23812f12514f9f4a81
print("(16 进制)私钥 prime1: ", private_prime1) # f12bca5c6eacb8b14bf538d41f60755c3c0cc50170ec938e840c8b71b34930b82a3211eeaaf4d6fd3e28c53421ecb6c330ff7bed90e792676d2fc4bbcc01c7b1
print("(16 进制)私钥 prime2: ", private_prime2) # b02038591b34d1f8173050b71c9612eebe0f4661be12002281f4a4305da083bdbca6a54605b2bd5e98b08dcdba38c18f3d69ee0dd96ffce5880def1fd89eaa8d
print("(16 进制)私钥 exponent1: ", private_exponent1) # 9d94e566bc1233a3f563c7bc22bc5e32e431dbcff33f41b30f693afc120fb2bbc326703d288b4ea6ae24e9a604bcad36a11f6e946de841eb3e96c5cf879f6a21
print("(16 进制)私钥 exponent2: ", private_exponent2) # af61a63ab4e8c81cef9a6105b6258afcc9ad943c4874cc45907af7f46187312882eebead17878122ed9101e3d68825d669254eb3e3cdac5b343c0bddfe6b2111
print("(16 进制)私钥 coefficient: ", private_coefficient) # 629c62971648ee1253f3d4277ba0a03d7aaa65fd2c157d05791f4025a8f583673e07d1a067e368bb89dee165e339551666eb9c87bcaa9f75e8c5e413e3fc5a0b
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# ✅ 安装依赖 pip install rsa,官方文档:https://stuvel.eu/python-rsa-doc/
# ❌ 不支持解析 spki 语法标准的公钥,只支持 pkcs1
# ❌ 不支持解析 pkcs8 语法标准的私钥,只支持 pkcs1
import rsa
# pkcs1 标准 pem 格式的公钥
public_key_pem = """
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pem = """
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
# 解析公钥和私钥
public_key = rsa.PublicKey.load_pkcs1(public_key_pem.encode(), 'PEM')
private_key = rsa.PrivateKey.load_pkcs1(private_key_pem.encode(), 'PEM')
# 获取模数(modulus),使用 16 进制字符串表示,从公钥和私钥中均可获取,且值是一样的
modulus = hex(public_key.n)[2:] # 或者 private_key.n
# 计算密钥的位数,即模数(modulus)的位数,16 进制转换为位数时每个字符代表 4 位
key_length = len(modulus) * 4
# 获取公钥指数
public_exponent = hex(public_key.e)[2:]
# 获取私钥指数
private_exponent = hex(private_key.d)[2:]
# 获取私钥其他参数
private_prime1 = hex(private_key.p)[2:]
private_prime2 = hex(private_key.q)[2:]
private_exponent1 = hex(private_key.d % (private_key.p - 1))[2:]
private_exponent2 = hex(private_key.d % (private_key.q - 1))[2:]
private_coefficient = hex(pow(private_key.q, -1, private_key.p))[2:]
print("(16 进制)模数: ", modulus) # b2c0fda504952c6abcf527942e00f1468d87ab71cab8e52ec856e3fc148166480416efa7bc958f83a20b999b6dbcaf3aa12540d86469e57c105dab66acbd9b9c21b3e8c8c75b5477224f2572f264236bdd0f2de2c4327a4eaad7e8a637a2941081eb2ef7ae62ad4bbe6c3796de76bd1cef5b0b9c615d041d26f1dc6d1bea112b
print("(16 进制)密钥 & 模数位数: ", key_length) # 1024
print("(16 进制)公钥指数: ", public_exponent) # 0x10001 (65537)
print("(16 进制)私钥指数: ", private_exponent) # ceae569876b404a765d40fef4541d1b7c1ed1c4e761752e6c4bdb2ddc4d7d96b6b4f19cad84215ae1daf4bec6af5bfa60aad084d2bcd458a2d6220cbc19f391521a921498bc2dbde32c84646f9f609717b995b3a05d3e614ae514fd1bbc6e493a90dc50de181beb46f76e006e1c8f2f4009917d0110495259a16156d9d3c401
print("(16 进制)私钥 prime1: ", private_prime1) # b87cc2c8cc4da10aaf45526479f580d21dab0f5150d6baad1e5c6f8fff42a9f71e595038d97288dc061a6c24141bc7d3f8ca0ca2623e2e530dce480f17fdf647c6a9a0fd
print("(16 进制)私钥 prime2: ", private_prime2) # f80b479533e5579a8f53e0ba1928281df7f383e7aeb2a8143fb081ce87ed089bf5a286293d31e5d2acc1979fc84fcf17e422ee131688ed7c14ad8747
print("(16 进制)私钥 exponent1: ", private_exponent1) # 6ff790444bf2855db5b84de41b3ccbdd3a125aae90707245a55a967eff7e17279aecbbca74f695676bf0d7572239261359384f68b25568ca1163f3c9ed56be051be65185
print("(16 进制)私钥 exponent2: ", private_exponent2) # 8ed3a7e761179947156ade072abf35c273e913b60fa12e2962b71737be8b1d9ef8651a4d9ac025af16ecee8b0203faa2ae29f2dea8e635a17222adb7
print("(16 进制)私钥 coefficient: ", private_coefficient) # 6b46e0fb2928b01030eea323b6c551ce627fd50aa3a4c67aedfd137aadbf88d6356eaa39b3c127d47582eacca8f513f60eb7d318d9759c73e9a73d67b15f823a4c57415e
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Make sure to add code blocks to your code group
# JavaScript Node.js ECMAScript 5.1+
// ✅ 安装依赖:npm install node-forge,官方文档:https://github.com/digitalbazaar/forge
// ❌ 不支持解析私钥的 prime1、prime2、exponent1、exponent2、coefficient 参数
var forge = require("node-forge");
// spki 标准 pem 格式的公钥
var publicKeyPEM = `
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl7HWuXcOH9I/Bud7dplYxHOEC
D82fJv1WJKADhmILCxDLJLVkueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5
jrHT8zw8InrNRwlDeCyx/Q+ETpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faN
w6cBVKhFn+fuItSGfQIDAQAB
-----END PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
var privateKeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCl7HWuXcOH9I/Bud7dplYxHOECD82fJv1WJKADhmILCxDLJLVk
ueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5jrHT8zw8InrNRwlDeCyx/Q+E
TpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faNw6cBVKhFn+fuItSGfQIDAQAB
AoGBAKSmc1kmfoQJciZh1gDJsTpnV/l9ySQnwrma+pbE4cHnpzCPKtnbgfcfNNWh
CJljGupfyvzbs1SZkCUL/B1yBR3uAbWw5G0uzJo61wYciufnQA1/lu3JyEyLeSxb
eFOIkuI8Ce0SCPT01+6sR77EA0VtUA+0Ak7OI4EvElFPn0qBAkEA8SvKXG6suLFL
9TjUH2B1XDwMxQFw7JOOhAyLcbNJMLgqMhHuqvTW/T4oxTQh7LbDMP977ZDnkmdt
L8S7zAHHsQJBALAgOFkbNNH4FzBQtxyWEu6+D0ZhvhIAIoH0pDBdoIO9vKalRgWy
vV6YsI3NujjBjz1p7g3Zb/zliA3vH9ieqo0CQQCdlOVmvBIzo/Vjx7wivF4y5DHb
z/M/QbMPaTr8Eg+yu8MmcD0oi06mriTppgS8rTahH26UbehB6z6Wxc+Hn2ohAkEA
r2GmOrToyBzvmmEFtiWK/MmtlDxIdMxFkHr39GGHMSiC7r6tF4eBIu2RAePWiCXW
aSVOs+PNrFs0PAvd/mshEQJAYpxilxZI7hJT89Qne6CgPXqqZf0sFX0FeR9AJaj1
g2c+B9GgZ+Nou4ne4WXjOVUWZuuch7yqn3XoxeQT4/xaCw==
-----END RSA PRIVATE KEY-----
`
// 解析公钥和私钥
var publicKey = forge.pki.publicKeyFromPem(publicKeyPEM);
var privateKey = forge.pki.privateKeyFromPem(privateKeyPEM);
// 获取模数(modulus),使用 16 进制字符串表示,从公钥和私钥中均可获取,且值是一样的
var modulus = publicKey.n.toString(16); // 或者 privateKey.n.toString(16);
// 计算密钥的位数,即模数(modulus)的位数,16 进制转换为位数时每个字符代表 4 位
var keyLength = modulus.length * 4;
// 获取公钥指数
var publicExponent = publicKey.e.toString(16);
// 获取私钥指数
var privateExponent = privateKey.d.toString(16);
console.log("(16 进制)模数: ", modulus); // a5ec75ae5dc387f48fc1b9dedda656311ce1020fcd9f26fd5624a00386620b0b10cb24b564b9e0507f0508b4f10b17744b86cfb7f973587c68b3ecf3cf871575a5ecb98eb1d3f33c3c227acd470943782cb1fd0f844e94a94089af20b7f44411ed9ce815a5be35ba1285db8c061f8abbf9f68dc3a70154a8459fe7ee22d4867d
console.log("(16 进制)密钥 & 模数位数: ", keyLength); // 1024
console.log("(16 进制)公钥指数: ", publicExponent); // 0x10001 (65537)
console.log("(16 进制)私钥指数: ", privateExponent); // a4a67359267e8409722661d600c9b13a6757f97dc92427c2b99afa96c4e1c1e7a7308f2ad9db81f71f34d5a10899631aea5fcafcdbb3549990250bfc1d72051dee01b5b0e46d2ecc9a3ad7061c8ae7e7400d7f96edc9c84c8b792c5b78538892e23c09ed1208f4f4d7eeac47bec403456d500fb4024ece23812f12514f9f4a81
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# Golang 1.0+
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
)
func main() {
// spki 标准 pem 格式的公钥
publicKeyPEM := `
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl7HWuXcOH9I/Bud7dplYxHOEC
D82fJv1WJKADhmILCxDLJLVkueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5
jrHT8zw8InrNRwlDeCyx/Q+ETpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faN
w6cBVKhFn+fuItSGfQIDAQAB
-----END PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
privateKeyPEM := `
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCl7HWuXcOH9I/Bud7dplYxHOECD82fJv1WJKADhmILCxDLJLVk
ueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5jrHT8zw8InrNRwlDeCyx/Q+E
TpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faNw6cBVKhFn+fuItSGfQIDAQAB
AoGBAKSmc1kmfoQJciZh1gDJsTpnV/l9ySQnwrma+pbE4cHnpzCPKtnbgfcfNNWh
CJljGupfyvzbs1SZkCUL/B1yBR3uAbWw5G0uzJo61wYciufnQA1/lu3JyEyLeSxb
eFOIkuI8Ce0SCPT01+6sR77EA0VtUA+0Ak7OI4EvElFPn0qBAkEA8SvKXG6suLFL
9TjUH2B1XDwMxQFw7JOOhAyLcbNJMLgqMhHuqvTW/T4oxTQh7LbDMP977ZDnkmdt
L8S7zAHHsQJBALAgOFkbNNH4FzBQtxyWEu6+D0ZhvhIAIoH0pDBdoIO9vKalRgWy
vV6YsI3NujjBjz1p7g3Zb/zliA3vH9ieqo0CQQCdlOVmvBIzo/Vjx7wivF4y5DHb
z/M/QbMPaTr8Eg+yu8MmcD0oi06mriTppgS8rTahH26UbehB6z6Wxc+Hn2ohAkEA
r2GmOrToyBzvmmEFtiWK/MmtlDxIdMxFkHr39GGHMSiC7r6tF4eBIu2RAePWiCXW
aSVOs+PNrFs0PAvd/mshEQJAYpxilxZI7hJT89Qne6CgPXqqZf0sFX0FeR9AJaj1
g2c+B9GgZ+Nou4ne4WXjOVUWZuuch7yqn3XoxeQT4/xaCw==
-----END RSA PRIVATE KEY-----
`
// 解析公钥和私钥
publicKeyBlock, _ := pem.Decode([]byte(publicKeyPEM))
if publicKeyBlock == nil {
fmt.Println("Failed to decode public key")
return
}
publicKeyInterface, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
fmt.Println("Failed to parse public key:", err)
return
}
publicKey := publicKeyInterface.(*rsa.PublicKey)
privateBlock, _ := pem.Decode([]byte(privateKeyPEM))
if privateBlock == nil {
fmt.Println("Failed to decode private key")
return
}
privateKey, err := x509.ParsePKCS1PrivateKey(privateBlock.Bytes)
if err != nil {
fmt.Println("Failed to parse private key:", err)
return
}
// 获取模数(modulus),使用 16 进制字符串表示,从公钥和私钥中均可获取,且值是一样的
modulus := fmt.Sprintf("%x", publicKey.N) // 或者 privateKey.N
// 计算密钥的位数,即模数(modulus)的位数,16 进制转换为位数时每个字符代表 4 位
keyLength := fmt.Sprintf("%d", publicKey.N.BitLen())
// 获取公钥指数
publicExponent := fmt.Sprintf("%x", publicKey.E)
// 获取私钥指数
privateExponent := fmt.Sprintf("%x", privateKey.D)
// 获取私钥其他参数
privatePrime1 := fmt.Sprintf("%x", privateKey.Primes[0])
privatePrime2 := fmt.Sprintf("%x", privateKey.Primes[1])
privateExponent1 := fmt.Sprintf("%x", privateKey.Precomputed.Dp)
privateExponent2 := fmt.Sprintf("%x", privateKey.Precomputed.Dq)
privateCoefficient := fmt.Sprintf("%x", privateKey.Precomputed.Qinv)
fmt.Println("(16 进制)模数: ", modulus) // a5ec75ae5dc387f48fc1b9dedda656311ce1020fcd9f26fd5624a00386620b0b10cb24b564b9e0507f0508b4f10b17744b86cfb7f973587c68b3ecf3cf871575a5ecb98eb1d3f33c3c227acd470943782cb1fd0f844e94a94089af20b7f44411ed9ce815a5be35ba1285db8c061f8abbf9f68dc3a70154a8459fe7ee22d4867d
fmt.Println("(16 进制)密钥 & 模数位数: ", keyLength) // 1024
fmt.Println("(16 进制)公钥指数: ", publicExponent) // 0x10001 (65537)
fmt.Println("(16 进制)私钥指数: ", privateExponent) // a4a67359267e8409722661d600c9b13a6757f97dc92427c2b99afa96c4e1c1e7a7308f2ad9db81f71f34d5a10899631aea5fcafcdbb3549990250bfc1d72051dee01b5b0e46d2ecc9a3ad7061c8ae7e7400d7f96edc9c84c8b792c5b78538892e23c09ed1208f4f4d7eeac47bec403456d500fb4024ece23812f12514f9f4a81
fmt.Println("(16 进制)私钥 prime1: ", privatePrime1) // f12bca5c6eacb8b14bf538d41f60755c3c0cc50170ec938e840c8b71b34930b82a3211eeaaf4d6fd3e28c53421ecb6c330ff7bed90e792676d2fc4bbcc01c7b1
fmt.Println("(16 进制)私钥 prime2: ", privatePrime2) // b02038591b34d1f8173050b71c9612eebe0f4661be12002281f4a4305da083bdbca6a54605b2bd5e98b08dcdba38c18f3d69ee0dd96ffce5880def1fd89eaa8d
fmt.Println("(16 进制)私钥 exponent1: ", privateExponent1) // 9d94e566bc1233a3f563c7bc22bc5e32e431dbcff33f41b30f693afc120fb2bbc326703d288b4ea6ae24e9a604bcad36a11f6e946de841eb3e96c5cf879f6a21
fmt.Println("(16 进制)私钥 exponent2: ", privateExponent2) // af61a63ab4e8c81cef9a6105b6258afcc9ad943c4874cc45907af7f46187312882eebead17878122ed9101e3d68825d669254eb3e3cdac5b343c0bddfe6b2111
fmt.Println("(16 进制)私钥 coefficient: ", privateCoefficient) // 629c62971648ee1253f3d4277ba0a03d7aaa65fd2c157d05791f4025a8f583673e07d1a067e368bb89dee165e339551666eb9c87bcaa9f75e8c5e413e3fc5a0b
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# 转换密钥
RSA 的公钥语法标准有:pkcs1、spki,私钥的语法标准有:pkcs1、pkcs8,已知一个语法标准的秘钥,可以将其转换成另一种语法标准的秘钥,同时秘钥最终的格式 pem、der 也是可以相互转换的。
# Python 3.0+
# ✅ 安装依赖 pip install pycryptodome,官方文档:https://pycryptodome.readthedocs.io/
# ❌ 密钥输出格式不支持 jwk
# ❌ 公钥不支持从 spki 标准转为 pkcs1 标准
from Crypto.PublicKey import RSA
def pkcs1_to_spki(public_key_pkcs1, output_format="PEM"):
# 将 pkcs1 标准的公钥转换为 spki 标准,返回 pem 或者 der 格式的公钥
public_key_pkcs1 = RSA.import_key(public_key_pkcs1)
public_key_spki = public_key_pkcs1.export_key(format=output_format.upper())
return public_key_spki.decode()
def pkcs1_to_pkcs8(private_key_pkcs1, output_format="PEM"):
# 将 pkcs1 标准的私钥转换为 pkcs8 标准,返回 pem 或者 der 格式的公钥
private_key_pkcs1 = RSA.import_key(private_key_pkcs1)
private_key_pkcs8 = private_key_pkcs1.export_key(format=output_format.upper(), pkcs=8)
return private_key_pkcs8.decode()
def pkcs8_to_pkcs1(private_key_pkcs8, output_format="PEM"):
# 将 pkcs8 标准的私钥转换为 pkcs1 标准,返回 pem 或者 der 格式的公钥
private_key_pkcs8 = RSA.import_key(private_key_pkcs8)
private_key_pkcs1 = private_key_pkcs8.export_key(format=output_format.upper(), pkcs=1)
return private_key_pkcs1.decode()
# 注意 """ 之后要紧跟着密钥标头,如果换行可能会因为无法解析导致报错:ValueError: RSA key format is not supported
# pkcs1 标准 pem 格式的公钥
public_key_pkcs1_pem = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pkcs1_pem = """-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
# 转换公钥:pkcs1 => spki
public_key_spki_pem = pkcs1_to_spki(public_key_pkcs1_pem, output_format="pem")
# 转换私钥:pkcs1 => pkcs8
private_key_pkcs8_pem = pkcs1_to_pkcs8(private_key_pkcs1_pem, output_format="pem")
print("公钥转换 pkcs1 => spki:\n\n", public_key_spki_pem)
print("\n私钥转换 pkcs1 => pkcs8:\n\n", private_key_pkcs8_pem)
"""
公钥转换 pkcs1 => spki:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCywP2lBJUsarz1J5QuAPFGjYer
ccq45S7IVuP8FIFmSAQW76e8lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPo
yMdbVHciTyVy8mQja90PLeLEMnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sL
nGFdBB0m8dxtG+oRKwIDAQAB
-----END PUBLIC KEY-----
私钥转换 pkcs1 => pkcs8:
-----BEGIN PRIVATE KEY-----
MIICegIBADANBgkqhkiG9w0BAQEFAASCAmQwggJgAgEAAoGBALLA/aUElSxqvPUn
lC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4OiC5mbbbyvOqElQNhkaeV8EF2r
Zqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q1+imN6KUEIHrLveuYq1Lvmw3
lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAECgYAM6uVph2tASnZdQP70VB0bfB7R
xOdhdS5sS9st3E19lra08ZythCFa4dr0vsavW/pgqtCE0rzUWKLWIgy8GfORUhqS
FJi8Lb3jLIRkb59glxe5lbOgXT5hSuUU/Ru8bkk6kNxQ3hgb60b3bgBuHI8vQAmR
fQEQSVJZoWFW2dPEAQJFALh8wsjMTaEKr0VSZHn1gNIdqw9RUNa6rR5cb4//Qqn3
HllQONlyiNwGGmwkFBvH0/jKDKJiPi5TDc5IDxf99kfGqaD9Aj0A+AtHlTPlV5qP
U+C6GSgoHffzg+eusqgUP7CBzoftCJv1ooYpPTHl0qzBl5/IT88X5CLuExaI7XwU
rYdHAkRv95BES/KFXbW4TeQbPMvdOhJarpBwckWlWpZ+/34XJ5rsu8p09pVna/DX
VyI5JhNZOE9oslVoyhFj88ntVr4FG+ZRhQI9AI7Tp+dhF5lHFWreByq/NcJz6RO2
D6EuKWK3Fze+ix2e+GUaTZrAJa8W7O6LAgP6oq4p8t6o5jWhciKttwJEa0bg+yko
sBAw7qMjtsVRzmJ/1QqjpMZ67f0Teq2/iNY1bqo5s8En1HWC6syo9RP2DrfTGNl1
nHPppz1nsV+COkxXQV4=
-----END PRIVATE KEY-----
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# ✅ 安装依赖 pip install cryptography,要求 Python 3.7+,官方文档:https://cryptography.io/
# ❌ 密钥输出格式不支持 jwk
# ❌ 私钥不支持从 pkcs8 标准转为 pkcs1 标准
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import load_pem_public_key, load_pem_private_key
def pkcs1_to_spki(public_key_pkcs1, output_format="PEM"):
# 将 pkcs1 标准的公钥转换为 spki 标准,返回 pem 或者 der 格式的公钥
if output_format.upper() == "DER":
encoding = serialization.Encoding.DER
else:
encoding = serialization.Encoding.PEM
public_key_pkcs1 = load_pem_public_key(public_key_pkcs1.encode())
public_key_spki = public_key_pkcs1.public_bytes(
encoding=encoding,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
return public_key_spki.decode()
def spki_to_pkcs1(public_key_spki, output_format="PEM"):
# 将 spki 标准的公钥转换为 pkcs1 标准,返回 pem 或者 der 格式的公钥
if output_format.upper() == "DER":
encoding = serialization.Encoding.DER
else:
encoding = serialization.Encoding.PEM
public_key_spki = load_pem_public_key(public_key_spki.encode())
public_key_pkcs1 = public_key_spki.public_bytes(
encoding=encoding,
format=serialization.PublicFormat.PKCS1
)
return public_key_pkcs1.decode()
def pkcs1_to_pkcs8(private_key_pkcs1, output_format="PEM"):
# 将 pkcs1 标准的私钥转换为 pkcs8 标准,返回 pem 或者 der 格式的公钥
if output_format.upper() == "DER":
encoding = serialization.Encoding.DER
else:
encoding = serialization.Encoding.PEM
private_key_pkcs1 = load_pem_private_key(private_key_pkcs1.encode(), password=None) # 可选参数 password,指定私钥的密码
private_key_pkcs8 = private_key_pkcs1.private_bytes(
encoding=encoding,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption() # 可选参数 encryption_algorithm,指定私钥的加密算法
)
return private_key_pkcs8.decode()
# spki 标准 pem 格式的公钥
public_key_spki_pem = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl7HWuXcOH9I/Bud7dplYxHOEC
D82fJv1WJKADhmILCxDLJLVkueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5
jrHT8zw8InrNRwlDeCyx/Q+ETpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faN
w6cBVKhFn+fuItSGfQIDAQAB
-----END PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pkcs1_pem = """-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCl7HWuXcOH9I/Bud7dplYxHOECD82fJv1WJKADhmILCxDLJLVk
ueBQfwUItPELF3RLhs+3+XNYfGiz7PPPhxV1pey5jrHT8zw8InrNRwlDeCyx/Q+E
TpSpQImvILf0RBHtnOgVpb41uhKF24wGH4q7+faNw6cBVKhFn+fuItSGfQIDAQAB
AoGBAKSmc1kmfoQJciZh1gDJsTpnV/l9ySQnwrma+pbE4cHnpzCPKtnbgfcfNNWh
CJljGupfyvzbs1SZkCUL/B1yBR3uAbWw5G0uzJo61wYciufnQA1/lu3JyEyLeSxb
eFOIkuI8Ce0SCPT01+6sR77EA0VtUA+0Ak7OI4EvElFPn0qBAkEA8SvKXG6suLFL
9TjUH2B1XDwMxQFw7JOOhAyLcbNJMLgqMhHuqvTW/T4oxTQh7LbDMP977ZDnkmdt
L8S7zAHHsQJBALAgOFkbNNH4FzBQtxyWEu6+D0ZhvhIAIoH0pDBdoIO9vKalRgWy
vV6YsI3NujjBjz1p7g3Zb/zliA3vH9ieqo0CQQCdlOVmvBIzo/Vjx7wivF4y5DHb
z/M/QbMPaTr8Eg+yu8MmcD0oi06mriTppgS8rTahH26UbehB6z6Wxc+Hn2ohAkEA
r2GmOrToyBzvmmEFtiWK/MmtlDxIdMxFkHr39GGHMSiC7r6tF4eBIu2RAePWiCXW
aSVOs+PNrFs0PAvd/mshEQJAYpxilxZI7hJT89Qne6CgPXqqZf0sFX0FeR9AJaj1
g2c+B9GgZ+Nou4ne4WXjOVUWZuuch7yqn3XoxeQT4/xaCw==
-----END RSA PRIVATE KEY-----
"""
# 转换公钥:spki => pkcs1
public_key_pkcs1_pem = spki_to_pkcs1(public_key_spki_pem, output_format="pem")
# 转换私钥:pkcs1 => pkcs8
private_key_pkcs8_pem = pkcs1_to_pkcs8(private_key_pkcs1_pem, output_format="pem")
print("公钥转换 spki => pkcs1:\n\n", public_key_pkcs1_pem)
print("私钥转换 pkcs1 => pkcs8:\n\n", private_key_pkcs8_pem)
"""
公钥转换 spki => pkcs1:
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKXsda5dw4f0j8G53t2mVjEc4QIPzZ8m/VYkoAOGYgsLEMsktWS54FB/
BQi08QsXdEuGz7f5c1h8aLPs88+HFXWl7LmOsdPzPDwies1HCUN4LLH9D4ROlKlA
ia8gt/REEe2c6BWlvjW6EoXbjAYfirv59o3DpwFUqEWf5+4i1IZ9AgMBAAE=
-----END RSA PUBLIC KEY-----
私钥转换 pkcs1 => pkcs8:
-----BEGIN PRIVATE KEY-----
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKXsda5dw4f0j8G5
3t2mVjEc4QIPzZ8m/VYkoAOGYgsLEMsktWS54FB/BQi08QsXdEuGz7f5c1h8aLPs
88+HFXWl7LmOsdPzPDwies1HCUN4LLH9D4ROlKlAia8gt/REEe2c6BWlvjW6EoXb
jAYfirv59o3DpwFUqEWf5+4i1IZ9AgMBAAECgYEApKZzWSZ+hAlyJmHWAMmxOmdX
+X3JJCfCuZr6lsThweenMI8q2duB9x801aEImWMa6l/K/NuzVJmQJQv8HXIFHe4B
tbDkbS7MmjrXBhyK5+dADX+W7cnITIt5LFt4U4iS4jwJ7RII9PTX7qxHvsQDRW1Q
D7QCTs4jgS8SUU+fSoECQQDxK8pcbqy4sUv1ONQfYHVcPAzFAXDsk46EDItxs0kw
uCoyEe6q9Nb9PijFNCHstsMw/3vtkOeSZ20vxLvMAcexAkEAsCA4WRs00fgXMFC3
HJYS7r4PRmG+EgAigfSkMF2gg728pqVGBbK9Xpiwjc26OMGPPWnuDdlv/OWIDe8f
2J6qjQJBAJ2U5Wa8EjOj9WPHvCK8XjLkMdvP8z9Bsw9pOvwSD7K7wyZwPSiLTqau
JOmmBLytNqEfbpRt6EHrPpbFz4efaiECQQCvYaY6tOjIHO+aYQW2JYr8ya2UPEh0
zEWQevf0YYcxKILuvq0Xh4Ei7ZEB49aIJdZpJU6z482sWzQ8C93+ayERAkBinGKX
FkjuElPz1Cd7oKA9eqpl/SwVfQV5H0AlqPWDZz4H0aBn42i7id7hZeM5VRZm65yH
vKqfdejF5BPj/FoL
-----END PRIVATE KEY-----
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Make sure to add code blocks to your code group
# JavaScript Node.js ECMAScript 5.1+
// ✅ Node.js 内置 crypto 模块,无需单独安装
const crypto = require("crypto");
function PKCS1ToSPKI(publicKeyPkcs1, outputFormat="pem") {
// 将 pkcs1 标准的公钥转换为 spki 标准,返回 pem 或者 der 格式的公钥
const publicKeySpki = crypto.createPublicKey({ key: publicKeyPkcs1, type: "pkcs1" });
return publicKeySpki.export({ type: "spki", format: outputFormat.toLowerCase() });
}
function SPKIToPKCS1(publicKeySpki, outputFormat="pem") {
// 将 spki 标准的公钥转换为 pkcs1 标准,返回 pem 或者 der 格式的公钥
const publicKeyPkcs1 = crypto.createPublicKey({ key: publicKeySpki, type: "spki" });
return publicKeyPkcs1.export({ type: "pkcs1", format: outputFormat.toLowerCase() });
}
function PKCS1ToPKCS8(privateKeyPkcs1, outputFormat="pem") {
// 将 pkcs1 标准的私钥转换为 pkcs8 标准,返回 pem 或者 der 格式的公钥
const privateKeyPkcs8 = crypto.createPrivateKey({ key: privateKeyPkcs1, type: "pkcs1" });
return privateKeyPkcs8.export({ type: "pkcs8", format: outputFormat.toLowerCase() });
}
function PKCS8ToPKCS1(privateKeyPkcs8, outputFormat="pem") {
// 将 pkcs8 标准的私钥转换为 pkcs1 标准,返回 pem 或者 der 格式的公钥
const privateKeyPkcs1 = crypto.createPrivateKey({ key: privateKeyPkcs8, type: "pkcs8" });
return privateKeyPkcs1.export({ type: "pkcs1", format: outputFormat.toLowerCase() });
}
// pkcs1 标准 pem 格式的公钥
const publicKeyPkcs1Pem = `
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
const privateKeyPkcs1Pem = `
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
`
// 转换公钥:pkcs1 => spki
var publicKeySpkiPem = PKCS1ToSPKI(publicKeyPkcs1Pem, "pem")
// 转换私钥:pkcs1 => pkcs8
var privateKeyPkcs8Pem = PKCS1ToPKCS8(privateKeyPkcs1Pem, "pem")
console.log("公钥转换 pkcs1 => spki:\n\n", publicKeySpkiPem)
console.log("私钥转换 pkcs1 => pkcs8:\n\n", privateKeyPkcs8Pem)
/*
公钥转换 pkcs1 => spki:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCywP2lBJUsarz1J5QuAPFGjYer
ccq45S7IVuP8FIFmSAQW76e8lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPo
yMdbVHciTyVy8mQja90PLeLEMnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sL
nGFdBB0m8dxtG+oRKwIDAQAB
-----END PUBLIC KEY-----
私钥转换 pkcs1 => pkcs8:
-----BEGIN PRIVATE KEY-----
MIICegIBADANBgkqhkiG9w0BAQEFAASCAmQwggJgAgEAAoGBALLA/aUElSxqvPUn
lC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4OiC5mbbbyvOqElQNhkaeV8EF2r
Zqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q1+imN6KUEIHrLveuYq1Lvmw3
lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAECgYAM6uVph2tASnZdQP70VB0bfB7R
xOdhdS5sS9st3E19lra08ZythCFa4dr0vsavW/pgqtCE0rzUWKLWIgy8GfORUhqS
FJi8Lb3jLIRkb59glxe5lbOgXT5hSuUU/Ru8bkk6kNxQ3hgb60b3bgBuHI8vQAmR
fQEQSVJZoWFW2dPEAQJFALh8wsjMTaEKr0VSZHn1gNIdqw9RUNa6rR5cb4//Qqn3
HllQONlyiNwGGmwkFBvH0/jKDKJiPi5TDc5IDxf99kfGqaD9Aj0A+AtHlTPlV5qP
U+C6GSgoHffzg+eusqgUP7CBzoftCJv1ooYpPTHl0qzBl5/IT88X5CLuExaI7XwU
rYdHAkRv95BES/KFXbW4TeQbPMvdOhJarpBwckWlWpZ+/34XJ5rsu8p09pVna/DX
VyI5JhNZOE9oslVoyhFj88ntVr4FG+ZRhQI9AI7Tp+dhF5lHFWreByq/NcJz6RO2
D6EuKWK3Fze+ix2e+GUaTZrAJa8W7O6LAgP6oq4p8t6o5jWhciKttwJEa0bg+yko
sBAw7qMjtsVRzmJ/1QqjpMZ67f0Teq2/iNY1bqo5s8En1HWC6syo9RP2DrfTGNl1
nHPppz1nsV+COkxXQV4=
-----END PRIVATE KEY-----
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# Golang 1.0+
// ✅ 无需安装依赖,官方文档:https://pkg.go.dev/crypto
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"strings"
)
// PKCS1ToSPKI 将 pkcs1 标准的公钥转换为 spki 标准,返回 pem 或者 der 格式的公钥
func PKCS1ToSPKI(publicKeyPkcs1, outputFormat string) ([]byte, error) {
block, _ := pem.Decode([]byte(publicKeyPkcs1))
if block == nil {
return nil, errors.New("failed to decode PEM block containing public key")
}
publicKey, err := x509.ParsePKCS1PublicKey(block.Bytes)
if err != nil {
return nil, err
}
publicKeySpkiBytes, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return nil, err
}
if strings.ToUpper(outputFormat) == "DER" {
return publicKeySpkiBytes, nil
}
publicKeySpki := &pem.Block{
Type: "PUBLIC KEY",
Bytes: publicKeySpkiBytes,
}
return pem.EncodeToMemory(publicKeySpki), nil
}
// SPKIToPKCS1 将 SPKI 格式的公钥转换为 PKCS1 格式
func SPKIToPKCS1(publicKeySpki, outputFormat string) ([]byte, error) {
block, _ := pem.Decode([]byte(publicKeySpki))
if block == nil {
return nil, errors.New("failed to decode PEM block containing public key")
}
publicKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
rsaPublicKey, ok := publicKey.(*rsa.PublicKey)
if !ok {
return nil, errors.New("not an RSA public key")
}
publicKeyPkcs1Bytes := x509.MarshalPKCS1PublicKey(rsaPublicKey)
if strings.ToUpper(outputFormat) == "DER" {
return publicKeyPkcs1Bytes, nil
}
publicKeyPkcs1 := &pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: publicKeyPkcs1Bytes,
}
return pem.EncodeToMemory(publicKeyPkcs1), nil
}
// PKCS1ToPKCS8 将 pkcs1 标准的私钥转换为 pkcs8 标准,返回 pem 或者 der 格式的公钥
func PKCS1ToPKCS8(privateKeyPkcs1, outputFormat string) ([]byte, error) {
block, _ := pem.Decode([]byte(privateKeyPkcs1))
if block == nil {
return nil, errors.New("failed to decode PEM block containing public key")
}
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
privateKeyPkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, err
}
if strings.ToUpper(outputFormat) == "DER" {
return privateKeyPkcs8Bytes, nil
}
privateKeyPkcs8 := &pem.Block{
Type: "PRIVATE KEY",
Bytes: privateKeyPkcs8Bytes,
}
return pem.EncodeToMemory(privateKeyPkcs8), nil
}
// PKCS8ToPKCS1 将 pkcs8 标准的私钥转换为 pkcs1 标准,返回 pem 或者 der 格式的公钥
func PKCS8ToPKCS1(privateKeyPkcs8, outputFormat string) ([]byte, error) {
block, _ := pem.Decode([]byte(privateKeyPkcs8))
if block == nil {
return nil, errors.New("failed to decode PEM block containing public key")
}
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
if !ok {
return nil, errors.New("not an RSA public key")
}
privateKeyPkcs1Bytes := x509.MarshalPKCS1PrivateKey(rsaPrivateKey)
if strings.ToUpper(outputFormat) == "DER" {
return privateKeyPkcs1Bytes, nil
}
privateKeyPkcs1 := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privateKeyPkcs1Bytes,
}
return pem.EncodeToMemory(privateKeyPkcs1), nil
}
func main() {
// pkcs1 标准 pem 格式的公钥
publicKeyPkcs1Pem := `
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
privateKeyPkcs1Pem := `
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
`
// 转换公钥:pkcs1 => spki
publicKeySpkiPem, err := PKCS1ToSPKI(publicKeyPkcs1Pem, "pem")
if err != nil {
fmt.Println("Error converting public key PKCS1 to SPKI:", err)
return
}
// 转换私钥:pkcs1 => pkcs8
privateKeyPkcs8Pem, err := PKCS1ToPKCS8(privateKeyPkcs1Pem, "pem")
if err != nil {
fmt.Println("Error converting private key PKCS1 to PKCS8:", err)
return
}
fmt.Println("公钥转换 pkcs1 => spki:\n\n", string(publicKeySpkiPem))
fmt.Println("私钥转换 pkcs1 => pkcs8:\n\n", string(privateKeyPkcs8Pem))
}
/*
公钥转换 pkcs1 => spki:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCywP2lBJUsarz1J5QuAPFGjYer
ccq45S7IVuP8FIFmSAQW76e8lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPo
yMdbVHciTyVy8mQja90PLeLEMnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sL
nGFdBB0m8dxtG+oRKwIDAQAB
-----END PUBLIC KEY-----
私钥转换 pkcs1 => pkcs8:
-----BEGIN PRIVATE KEY-----
MIICegIBADANBgkqhkiG9w0BAQEFAASCAmQwggJgAgEAAoGBALLA/aUElSxqvPUn
lC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4OiC5mbbbyvOqElQNhkaeV8EF2r
Zqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q1+imN6KUEIHrLveuYq1Lvmw3
lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAECgYAM6uVph2tASnZdQP70VB0bfB7R
xOdhdS5sS9st3E19lra08ZythCFa4dr0vsavW/pgqtCE0rzUWKLWIgy8GfORUhqS
FJi8Lb3jLIRkb59glxe5lbOgXT5hSuUU/Ru8bkk6kNxQ3hgb60b3bgBuHI8vQAmR
fQEQSVJZoWFW2dPEAQJFALh8wsjMTaEKr0VSZHn1gNIdqw9RUNa6rR5cb4//Qqn3
HllQONlyiNwGGmwkFBvH0/jKDKJiPi5TDc5IDxf99kfGqaD9Aj0A+AtHlTPlV5qP
U+C6GSgoHffzg+eusqgUP7CBzoftCJv1ooYpPTHl0qzBl5/IT88X5CLuExaI7XwU
rYdHAkRv95BES/KFXbW4TeQbPMvdOhJarpBwckWlWpZ+/34XJ5rsu8p09pVna/DX
VyI5JhNZOE9oslVoyhFj88ntVr4FG+ZRhQI9AI7Tp+dhF5lHFWreByq/NcJz6RO2
D6EuKWK3Fze+ix2e+GUaTZrAJa8W7O6LAgP6oq4p8t6o5jWhciKttwJEa0bg+yko
sBAw7qMjtsVRzmJ/1QqjpMZ67f0Teq2/iNY1bqo5s8En1HWC6syo9RP2DrfTGNl1
nHPppz1nsV+COkxXQV4=
-----END PRIVATE KEY-----
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# 加密解密
关于加密解密
在 RSA 加密解密操作中,我们需要注意的是填充方式(padding),最常见的分为以下四种:
RSA_NO_PADDING
: 不使用填充方案;RSA_PKCS1_PADDING
: 最常见,使用 PKCS#1 v1.5 填充方案;RSA_PKCS1_OAEP_PADDING
: OAEP (Optimal asymmetric encryption padding),最优非对称加密填充,在 PKCS#1 v2 中标准化;RSA_PKCS1_PSS_PADDING
: PSS (Probabilistic signature scheme),概率签名方案,在 PKCS#1 v2.1 中标准化。
【实用参考资料】
Padding 维基百科:https://en.wikipedia.org/wiki/Padding_(cryptography) (opens new window)
RSA Padding 维基百科:https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Padding (opens new window)
聊聊密码学中的Padding:https://cloud.tencent.com/developer/article/1499219 (opens new window)
PSS (Probabilistic signature scheme):https://en.wikipedia.org/wiki/Probabilistic_signature_scheme (opens new window)
OAEP (Optimal asymmetric encryption padding):https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding (opens new window)
# Python 3.0+
# ✅ 安装依赖 pip install cryptography,要求 Python 3.7+,官方文档:https://cryptography.io/
# ❌ padding 填充方式只支持 RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING,不支持 RSA_NO_PADDING、RSA_PKCS1_PSS_PADDING
import base64
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
def set_padding(padding_scheme):
if padding_scheme == "RSA_PKCS1_OAEP_PADDING":
return padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
elif padding_scheme == "RSA_PKCS1_PADDING":
return padding.PKCS1v15()
else:
raise ValueError("Unsupported padding scheme")
# pkcs1 标准 pem 格式的公钥
public_key_pkcs1_pem = """
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pkcs1_pem = """
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
public_key = serialization.load_pem_public_key(public_key_pkcs1_pem.encode())
private_key = serialization.load_pem_private_key(private_key_pkcs1_pem.encode(), password=None)
data = "spiderapi.cn - 虫术"
padding_type = set_padding("RSA_PKCS1_PADDING")
resultEncrypted = public_key.encrypt(data.encode(), padding_type)
resultDecrypted = private_key.decrypt(resultEncrypted, padding_type).decode()
print("RSA_PKCS1_PADDING 加密结果: ", base64.b64encode(resultEncrypted).decode())
print("RSA_PKCS1_PADDING 解密结果: ", resultDecrypted)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# ✅ 安装依赖 pip install pycryptodome,官方文档:https://pycryptodome.readthedocs.io/
# ❌ padding 填充方式只支持 RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING,不支持 RSA_NO_PADDING、RSA_PKCS1_PSS_PADDING
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 # 即 RSA_PKCS1_PADDING
from Crypto.Cipher import PKCS1_OAEP # 即 RSA_PKCS1_OAEP_PADDING
def rsa_decrypt(ciphertext):
cipher = PKCS1_v1_5.new(private_key)
decrypted = cipher.decrypt(ciphertext, None).decode()
return decrypted
def rsa_encrypt(plaintext):
cipher = PKCS1_v1_5.new(public_key)
encrypted = cipher.encrypt(plaintext.encode())
return encrypted
# 注意 """ 之后要紧跟着密钥标头,如果换行可能会因为无法解析导致报错:ValueError: RSA key format is not supported
# pkcs1 标准 pem 格式的公钥
public_key_pkcs1_pem = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pkcs1_pem = """-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
public_key = RSA.import_key(public_key_pkcs1_pem)
private_key = RSA.import_key(private_key_pkcs1_pem)
data = "spiderapi.cn - 虫术"
resultEncrypted = rsa_encrypt(data)
resultDecrypted = rsa_decrypt(resultEncrypted)
print("RSA_PKCS1_PADDING 加密结果: ", base64.b64encode(resultEncrypted).decode())
print("RSA_PKCS1_PADDING 解密结果: ", resultDecrypted)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# ✅ 安装依赖 pip install rsa,官方文档:https://stuvel.eu/python-rsa-doc/
# ❌ padding 填充方式只支持 RSA_PKCS1_PADDING
# ❌ 不支持使用 spki 语法标准的公钥和 pkcs8 语法标准的私钥
import rsa
import base64
# pkcs1 标准 pem 格式的公钥
public_key_pkcs1_pem = """
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pkcs1_pem = """
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
public_key = rsa.PublicKey.load_pkcs1(public_key_pkcs1_pem.encode(), "PEM")
private_key = rsa.PrivateKey.load_pkcs1(private_key_pkcs1_pem.encode(), "PEM")
data = "spiderapi.cn - 虫术"
resultEncrypted = rsa.encrypt(data.encode(), public_key)
resultDecrypted = rsa.decrypt(resultEncrypted, private_key)
print("RSA_PKCS1_PADDING 加密结果: ", base64.b64encode(resultEncrypted).decode())
print("RSA_PKCS1_PADDING 解密结果: ", resultDecrypted.decode())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# ✅ 安装依赖 pip install pycryptodome,官方文档:https://pycryptodome.readthedocs.io/
# ❌ padding 填充方式只支持 RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING,不支持 RSA_NO_PADDING、RSA_PKCS1_PSS_PADDING
# 本例由雕虫小技二群粉丝提供,ID:曹晶 Eric Cao🇨🇳
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 # 即 RSA_PKCS1_PADDING
from Crypto.Cipher import PKCS1_OAEP # 即 RSA_PKCS1_OAEP_PADDING
# 一次 RSA 加密对明文长度是有限制,实际上,RSA 算法本身要求加密内容也就是明文长度 M 必须 0 < M < N(模数)
# 如果要加密一个长度大于模数 N 的明文块,就需要对明文进行分块以满足要求
# RSA_PKCS1_PADDING,每次加密的明文必须比 RSA 密钥的模长至少少 11 个字节
# RSA_PKCS1_OAEP_PADDING,每次加密的明文必须比 RSA 密钥的模长至少少 42 个字节
# NO_PADDING,每次加密的明文与 RSA 的密钥的模长一样,或更短
def rsa_encrypt(plaintext):
plaintext = plaintext.encode('utf-8')
chunk_size = public_key.size_in_bytes() - 11 # 设置每个小段的长度,加密时要减去一个长度,PKCS1_PADDING: 至少-11, PKCS1_OAEP_PADDING: 至少-42
chunks = [plaintext[i:i + chunk_size] for i in range(0, len(plaintext), chunk_size)]
encrypted_chunks = [PKCS1_v1_5.new(public_key).encrypt(chunk) for chunk in chunks]
encrypted_data = b''.join(encrypted_chunks)
return encrypted_data
def rsa_decrypt(ciphertext):
chunk_size = private_key.size_in_bytes() # 设置每个小段的长度
chunks = [ciphertext[i:i + chunk_size] for i in range(0, len(ciphertext), chunk_size)]
decrypted_chunks = [PKCS1_v1_5.new(private_key).decrypt(chunk, None) for chunk in chunks]
decrypted_data = b''.join(decrypted_chunks)
return decrypted_data.decode('utf-8')
# 注意 """ 之后要紧跟着密钥标头,如果换行可能会因为无法解析导致报错:ValueError: RSA key format is not supported
# pkcs1 标准 pem 格式的公钥
public_key_pkcs1_pem = """-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
"""
# pkcs1 标准 pem 格式的私钥
private_key_pkcs1_pem = """-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
"""
public_key = RSA.import_key(public_key_pkcs1_pem)
private_key = RSA.import_key(private_key_pkcs1_pem)
data = "SpiderAPI - 虫术 - 汇总各种爬虫逆向常用 API,涉及各种网络请求库,自动化框架,爬虫框架,HOOK 脚本,ADB 命令等。SpiderAPI - Insect Techniques - Summarize various commonly used reverse APIs for web crawlers, involving various network request libraries, automation frameworks, web crawling frameworks, HOOK scripts, ADB commands, etc."
resultEncrypted = rsa_encrypt(data)
resultDecrypted = rsa_decrypt(resultEncrypted)
print("原文长度: ", len(data))
print("RSA_PKCS1_OAEP_PADDING 加密结果: %s" % base64.b64encode(resultEncrypted).decode())
print("RSA_PKCS1_OAEP_PADDING 解密结果: %s" % resultDecrypted)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// Make sure to add code blocks to your code group
# JavaScript Node.js ECMAScript 5.1+
// ✅ Node.js 内置 crypto 模块,无需单独安装,官方文档:https://nodejs.org/docs/latest/api/crypto.html
var crypto = require("crypto");
function rsaEncrypt(data) {
var bufferData = Buffer.from(data);
var encrypted = crypto.publicEncrypt({
key: publicKey,
// 支持 RSA_NO_PADDING、RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_PKCS1_PSS_PADDING
padding: crypto.constants.RSA_PKCS1_PADDING
}, bufferData);
return encrypted.toString("base64");
}
function rsaDecrypt(cipherText) {
var bufferData = Buffer.from(cipherText, "base64");
var decrypted = crypto.privateDecrypt({
key: privateKey,
// 支持 RSA_NO_PADDING、RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_PKCS1_PSS_PADDING
padding: crypto.constants.RSA_PKCS1_PADDING
}, bufferData);
return decrypted.toString();
}
// pkcs1 标准 pem 格式的公钥
var publicKeyPkcs1Pem = `
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
var privateKeyPkcs1Pem = `
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
`
// 将 pem 格式的密钥转换为 crypto 可以使用的对象
var publicKey = crypto.createPublicKey(publicKeyPkcs1Pem);
var privateKey = crypto.createPrivateKey(privateKeyPkcs1Pem);
// RSA 加解密,填充方式使用 RSA_PKCS1_PADDING,其他可选 RSA_NO_PADDING、RSA_PKCS1_OAEP_PADDING、RSA_PKCS1_PSS_PADDING
var data = "spiderapi.cn - 虫术";
var resultEncrypted = rsaEncrypt(data);
var resultDecrypted = rsaDecrypt(resultEncrypted);
console.log("RSA_PKCS1_PADDING 加密结果: ", resultEncrypted)
console.log("RSA_PKCS1_PADDING 解密结果: ", resultDecrypted)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// ✅ 安装依赖:npm install node-rsa,官方文档:https://github.com/rzcoder/node-rsa
// ❓ 注意:截止 2024.03,该库中公钥语法标准支持 pkcs8,但实际上不存在这种说法,具有争议,正确应该是 spki,参见:https://github.com/rzcoder/node-rsa/issues/208
// ❌ padding 填充方式只支持 RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING,不支持 RSA_NO_PADDING、RSA_PKCS1_PSS_PADDING
var NodeRSA = require("node-rsa");
// pkcs1 标准 pem 格式的公钥
var publicKeyPkcs1Pem = `
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
var privateKeyPkcs1Pem = `
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
`
var key = new NodeRSA();
key.setOptions({ encryptionScheme: "pkcs1" }); // 设置填充模式,默认 pkcs1_oaep
// 导入密钥,传入参数格式:语法标准-密钥类型-输出格式,即 scheme-[key_type]-[output_type]
key.importKey(publicKeyPkcs1Pem, "pkcs1-public-pem"); // 公钥语法标准支持 pkcs1、pkcs8,输出格式支持 pem、der
key.importKey(privateKeyPkcs1Pem, "pkcs1-private-pem"); // 私钥语法标准支持 pkcs1、pkcs8,输出格式支持 pem、der
// RSA 加解密
var data = "spiderapi.cn - 虫术";
var resultEncrypted = key.encrypt(data, "base64");
var resultDecrypted = key.decrypt(resultEncrypted, "utf8");
console.log("RSA_PKCS1_PADDING 加密结果: ", resultEncrypted)
console.log("RSA_PKCS1_PADDING 解密结果: ", resultDecrypted)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// ✅ 安装依赖:npm install jsencrypt,官方文档:https://github.com/travist/jsencrypt
// ❗ 如果在 Node 环境中使用,会遇到报错 window is not defined,处理方法:
// 1.在当前 JS 文件顶部添加代码:window = global;
// 2.在 \node_modules\jsencrypt\bin\jsencrypt.js 添加代码:window = global;
// ❌ padding 填充方式默认为 RSA_PKCS1_PADDING,不支持其他填充方式
var JSEncrypt = require("jsencrypt");
// pkcs1 标准 pem 格式的公钥
var publicKeyPkcs1Pem = `
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
var privateKeyPkcs1Pem = `
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
`
var encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKeyPkcs1Pem);
encryptor.setPrivateKey(privateKeyPkcs1Pem);
// RSA 加解密,填充方式只支持 RSA_PKCS1_PADDING
var data = "spiderapi.cn - 虫术";
var resultEncrypted = encryptor.encrypt(data);
var resultDecrypted = encryptor.decrypt(resultEncrypted);
console.log("RSA_PKCS1_PADDING 加密结果: ", resultEncrypted)
console.log("RSA_PKCS1_PADDING 解密结果: ", resultDecrypted)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Make sure to add code blocks to your code group
# Golang 1.0+
// ✅ 无需安装依赖,官方文档:https://pkg.go.dev/crypto
// ❌ padding 填充方式只支持 RSA_PKCS1_PADDING、RSA_PKCS1_OAEP_PADDING,不支持 RSA_NO_PADDING、RSA_PKCS1_PSS_PADDING
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
)
func main() {
// pkcs1 标准 pem 格式的公钥
publicKeyPkcs1Pem := `
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALLA/aUElSxqvPUnlC4A8UaNh6txyrjlLshW4/wUgWZIBBbvp7yVj4Oi
C5mbbbyvOqElQNhkaeV8EF2rZqy9m5whs+jIx1tUdyJPJXLyZCNr3Q8t4sQyek6q
1+imN6KUEIHrLveuYq1Lvmw3lt52vRzvWwucYV0EHSbx3G0b6hErAgMBAAE=
-----END RSA PUBLIC KEY-----
`
// pkcs1 标准 pem 格式的私钥
privateKeyPkcs1Pem := `
-----BEGIN RSA PRIVATE KEY-----
MIICYAIBAAKBgQCywP2lBJUsarz1J5QuAPFGjYerccq45S7IVuP8FIFmSAQW76e8
lY+DoguZm228rzqhJUDYZGnlfBBdq2asvZucIbPoyMdbVHciTyVy8mQja90PLeLE
MnpOqtfopjeilBCB6y73rmKtS75sN5bedr0c71sLnGFdBB0m8dxtG+oRKwIDAQAB
AoGADOrlaYdrQEp2XUD+9FQdG3we0cTnYXUubEvbLdxNfZa2tPGcrYQhWuHa9L7G
r1v6YKrQhNK81Fii1iIMvBnzkVIakhSYvC294yyEZG+fYJcXuZWzoF0+YUrlFP0b
vG5JOpDcUN4YG+tG924AbhyPL0AJkX0BEElSWaFhVtnTxAECRQC4fMLIzE2hCq9F
UmR59YDSHasPUVDWuq0eXG+P/0Kp9x5ZUDjZcojcBhpsJBQbx9P4ygyiYj4uUw3O
SA8X/fZHxqmg/QI9APgLR5Uz5Veaj1PguhkoKB3384PnrrKoFD+wgc6H7Qib9aKG
KT0x5dKswZefyE/PF+Qi7hMWiO18FK2HRwJEb/eQREvyhV21uE3kGzzL3ToSWq6Q
cHJFpVqWfv9+Fyea7LvKdPaVZ2vw11ciOSYTWThPaLJVaMoRY/PJ7Va+BRvmUYUC
PQCO06fnYReZRxVq3gcqvzXCc+kTtg+hLilitxc3vosdnvhlGk2awCWvFuzuiwID
+qKuKfLeqOY1oXIirbcCRGtG4PspKLAQMO6jI7bFUc5if9UKo6TGeu39E3qtv4jW
NW6qObPBJ9R1gurMqPUT9g630xjZdZxz6ac9Z7FfgjpMV0Fe
-----END RSA PRIVATE KEY-----
`
publicKeyBlock, _ := pem.Decode([]byte(publicKeyPkcs1Pem))
if publicKeyBlock == nil {
panic("Failed to parse PEM block containing the public key")
}
publicKey, err := x509.ParsePKCS1PublicKey(publicKeyBlock.Bytes)
if err != nil {
panic("Failed to parse public key: " + err.Error())
}
privateKeyBlock, _ := pem.Decode([]byte(privateKeyPkcs1Pem))
if privateKeyBlock == nil {
panic("Failed to parse PEM block containing the private key")
}
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
if err != nil {
panic("Failed to parse private key: " + err.Error())
}
data := "spiderapi.cn - 虫术"
// RSA_PKCS1_PADDING
resultEncrypted, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, []byte(data))
// RSA_PKCS1_OAEP_PADDING
// resultEncrypted, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, publicKey, []byte(data), nil)
if err != nil {
panic("Failed to encrypt data: " + err.Error())
}
// RSA_PKCS1_PADDING
resultDecrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, resultEncrypted)
// RSA_PKCS1_OAEP_PADDING
// resultDecrypted, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, privateKey, resultEncrypted, nil)
if err != nil {
panic("Failed to decrypt data: " + err.Error())
}
fmt.Println("RSA_PKCS1_PADDING 加密结果: ", base64.StdEncoding.EncodeToString(resultEncrypted))
fmt.Println("RSA_PKCS1_PADDING 解密结果: ", string(resultDecrypted))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84