非对称加密 RSA
使用 openssl 命令行工具生成RSA公钥和私钥
这个命令将生成一个2048位的RSA私钥,并将其保存在文件 private.pem 中
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048
以下命令从私钥中提取公钥(public.pem):
openssl rsa -pubout -in private.pem -out public.pem
为什么可以从私钥中提取公钥?
钥文件通常包含了生成密钥对所需的所有信息,包括p、q、n、e和d。因此,可以从私钥文件中提取出n和e,这两者就构成了公钥
使用 python 生成 RSA 公钥和私钥
首先安装 cryptography 包.
pip install cryptography
以下代码使用 cryptography 来生成 RSA 公钥和私钥.
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
# 生成私钥
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
# 将私钥序列化为PEM格式
pem_private_key = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
# 从私钥中获取公钥
public_key = private_key.public_key()
# 将公钥序列化为PEM格式
pem_public_key = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
# 打印私钥和公钥
print("Private Key (PEM format):")
print(pem_private_key.decode('utf-8'))
print("\nPublic Key (PEM format):")
print(pem_public_key.decode('utf-8'))
# 你可以将私钥和公钥保存到文件中
with open('private_key.pem', 'wb') as f:
f.write(pem_private_key)
with open('public_key.pem', 'wb') as f:
f.write(pem_public_key)
加密和解密
公钥加密消息:
# message.txt 是要加密的原始消息文件,encrypted_message.bin 是加密后的输出文件
openssl rsautl -encrypt -in message.txt -inkey public.pem -pubin -out encrypted_message.bin
私钥解密消息:
# encrypted_message.bin 是加密后的消息文件,decrypted_message.txt 是解密后的输出文件
openssl rsautl -decrypt -in encrypted_message.bin -inkey private.pem -out decrypted_message.txt
签名和验证签名
签名涉及2步, 第一步对消息做哈希,生成 hash值, 第二步对 hash 值做加密(即签名).
python 版本签名.
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_pem_public_key
# 假设你已经有了私钥,这里我们使用之前生成的私钥
# load your private key from local file: private_key.pem
with open('private_key.pem', 'rb') as file:
pem_private_key = file.read()
# 加载私钥
private_key = load_pem_private_key(pem_private_key, password=None, backend=default_backend())
# 要签名的消息
message = b"this is a message from https://www.tianxiaohui.com"
# 生成消息的哈希值
digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
digest.update(message)
digest_value = digest.finalize()
# 使用私钥对哈希值进行签名
signature = private_key.sign(
digest_value,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
# 打印签名
print("Signature:", signature)
# 使用公钥验证签名
# public_key = private_key.public_key()
with open('public_key.pem', 'rb') as file:
public_key = load_pem_public_key(file.read())
try:
public_key.verify(
signature,
digest_value,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("Signature is valid.")
except:
print("Signature is invalid.")
openssl 版本
# 生成RSA密钥对
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private_key.pem -out public_key.pem
# 创建一个文件进行签名
echo "This is a test message." > your_file.txt
# 使用私钥进行签名
openssl dgst -sha256 -sign private_key.pem -out signature.sig your_file.txt
# -sha256 表示使用SHA-256哈希算法。
# -sign private_key.pem 指定私钥文件。
# -out signature.sig 指定输出签名文件的名称。
# your_file.txt 是你要签名的文件。
# 使用公钥验证签名
openssl dgst -sha256 -verify public_key.pem -signature signature.sig your_file.txt
# -sha256 表示使用SHA-256哈希算法。
# -verify public_key.pem 指定公钥文件。
# -signature signature.sig 指定签名文件。
# your_file.txt 是你之前签名的文件。
公钥和私钥的格式
公钥和私钥可以以多种不同的格式保存,这些格式主要分为两大类:非加密格式和加密格式。以下是一些常见的密钥保存格式:
非加密格式
PEM (Privacy Enhanced Mail) 格式:
- 以文本形式存储,可以包含Base64编码的私钥或公钥。
- 通常以
-----BEGIN PUBLIC KEY-----
和-----END PUBLIC KEY-----
或-----BEGIN PRIVATE KEY-----
和-----END PRIVATE KEY-----
这样的标记开头和结尾。
DER (Distinguished Encoding Rules) 格式:
- 二进制格式,通常用于存储证书和密钥。
- 不以文本形式存储,因此不能直接编辑。
PKCS#1 格式:
- 主要用于RSA密钥。
- 可以是PEM编码的文本格式,也可以是DER格式的二进制格式。
加密格式
PKCS#8 格式:
- 专门用于私钥的存储,可以包含加密的私钥。
- 可以是PEM编码的文本格式,也可以是DER格式的二进制格式。
- 如果加密,通常会有
-----BEGIN ENCRYPTED PRIVATE KEY-----
和-----END ENCRYPTED PRIVATE KEY-----
标记。
PKCS#12 (PFX) 格式:
- 用于存储私钥、公钥和证书,通常包含一个密码保护的档案。
- 以
.pfx
或.p12
为文件扩展名。 - 支持二进制格式,可以包含多个密钥和证书。
其他格式
SSH 格式:
- 专门用于SSH密钥。
- 私钥通常以
.ssh/id_rsa
文件形式存在,公钥以.ssh/id_rsa.pub
文件形式存在。 - 私钥文件通常是PEM格式,但公钥文件是SSH专用的格式。
XML 格式:
- 少见,但某些应用程序可能会使用XML格式来存储密钥。