使用RSA密钥对进行加密解密示例

RSA Crypto Tutorial

文章目录

  • RSA Crypto Tutorial
    • Encrypt
      • Key file
      • Password for RSA private key
      • RSA key pair
      • Encrypt messaage
    • Decrypt
    • References

Encrypt

Key file

为了确保数据的安全性,建议随机生成一个密钥文件,并将其保存在一个安全的位置,例如 U 盘等。不同于密码,密钥文件不是一个容易记忆的字符串,而是一个文件。只需在解密时使用该文件,就可以避免因密码遗忘而导致无法解密的情况。同时,只有持有该密钥文件的人才能进行解密。因此,务必妥善保管您的密钥文件,防止泄露或丢失。

import random
import uuid

# 生成一个 UUID 作为文件名
file_name = str(uuid.uuid4()).upper()

# 生成 8 个随机的 6 位数,用连字符 - 连接
key = '-'.join(['{:06d}'.format(random.randint(0, 999999)) for _ in range(8)])

# 写入文件
with open(file_name + '.txt', 'w') as f:
    f.write(key)

Password for RSA private key

RSA算法中,私钥是解密和签名等关键操作的重要组成部分。为了防止私钥被未经授权的人获取,可以为私钥添加密码。只有知道密码的人才能使用该私钥进行操作,即使私钥被窃取,攻击者也无法直接使用私钥,除非他们能够破解密码。因此,向RSA私钥添加密码是一种有效的加强私钥安全性的措施。

import hashlib
import tkinter as tk
from tkinter import filedialog


def get_rsa_private_key_password() -> bytes:
    root = tk.Tk()
    file_path = filedialog.askopenfilename(
        initialdir="./",
        title="Select a File",
        filetypes=(("Text files", "*.txt"), ("All files", "*.*")),
    )
    root.destroy()

    if not file_path:
        print("No file selected")
        return ''.encode()

    with open(file_path, "rb") as f:
        data = f.read()
        hash_value = hashlib.sha256(data).hexdigest()
        # hash_value = hashlib.file_digest(f, "sha256") # for python 3.11+

    # 获取哈希值并打印输出
    rsa_private_key_password = hash_value.encode()
    return rsa_private_key_password


password = get_rsa_private_key_password()
password
b'ca9d68c57a9c015fbb8137474a7e8e252d2f8e59e7dd1d5e5da6ebb6598153ee'

RSA key pair

RSA密钥对包括公钥和私钥,用于RSA加密算法进行加密和解密操作。公钥可以公开,任何人都可以使用它来加密数据;私钥则是保密的,只有私钥的持有者才能使用它来解密数据。RSA密钥对的安全性取决于私钥的保护程度。如果私钥被泄露,攻击者可以使用它来解密被加密的数据。因此,RSA密钥对的私钥应该被妥善保护,只有授权的人员可以使用它。

Public exponent(公共指数)

  • 公共指数是RSA加密算法中的一个参数,是公钥的一部分。公钥由公共指数和模数组成,其中模数是两个大质数的乘积。公共指数是一个小于模数的正整数,通常为65537。公共指数和模数一起构成了RSA加密算法的公钥,用于加密数据。加密后的数据只能使用相应的私钥进行解密。因为公共指数是公开的,所以任何人都可以使用公钥进行加密,但只有持有相应私钥的人才能够解密数据。公共指数需要被选择得足够大,以确保安全性。通常情况下,公共指数会选取一个较小的质数,如3、17或65537。
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
import datetime

today = datetime.datetime.today().strftime('%Y%m%d')

# 生成RSA密钥对
private_key = rsa.generate_private_key(
    public_exponent=65537, key_size=2048  # 公共指数  # 密钥长度
)

# 将私钥对象序列化为 PEM 格式的字符串,并使用密码加密私钥
private_key_pem = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,  # 指定编码格式为 PEM
    format=serialization.PrivateFormat.PKCS8,  # 指定私钥格式为 PKCS8
    encryption_algorithm=serialization.BestAvailableEncryption(password),  # 指定加密算法为密码加密
)

# 保存私钥为PEM文件
with open(f"rsa_private_{today}.pem", "wb") as f:
    f.write(private_key_pem)

# 从已有的私钥生成公钥,并将公钥对象序列化为 PEM 格式的字符串
public_key = private_key.public_key()
public_key_pem = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

# 保存公钥为 PEM 文件
with open(f"rsa_public_{today}.pem", "wb") as f:
    f.write(public_key_pem)

# 打印密钥
print("私钥:\n" + private_key_pem.decode())
print("公钥:\n" + public_key_pem.decode())
私钥:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIEJyEk+yT/I0CAggA
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDFBmhbsRGR9WjxDfySRix/BIIE
0GNZdAPm2MgQmofs1DGemfGc/OUQ1KmTSSTjzqXcyWaFdLrKoFFh9F74QoCukl74
fbXuHG+EcqUxeP3svI479+A4khRD+633sUicdbysTitxVFOpSyQ1MmC/YTQ9hRs4
3rtsjFXXcbO92C2GSOF1UMTUCmWzVjkQE5E2KCD76OZihedyQhWTwvBT2oHxob6G
H7/e+kXhtvbbEsYtAbk9r4SqWXCBzwtEN1otRXYMI3Z1k/VVR7nT6/MUCsFe9go9
vomihRsFFfne9qSosHc4j6AOBVVNkktFN57odEm3QMnrnvlneU0HkX9IoTFn2pCe
vzwndzXuUsiEEMm66AqtdYE+ZlrehuQuFzKqVLEoHGc+lnluFgksBSiE7hF5PKgq
/+QWtFWggThn5ewG/vgobViws+i2QTeoSwkg3z16NeKsU+4H2K5p9AY2X8IofmTu
sYX86v8TNdd6zphaxz4ae6oGHROdyo8It12KM79BHktPQqWBAwzMEv6nQqd6xLAt
7Vt8UHUFTHJOGROu/MvK7dDkzZXsC86U4/LQbx5vE43yF/+cMQcidt3veRGsJHs6
OKRX4IyqQWBCh5lOGH/LD7wXRlzpVSADY4vzHAGaLOemCT0f42loe6+107ijV3FC
khJPX9MDcTvU11TjaNkjcAKXNUwsfHQV+fQGLgQZg05iIB6YdU4bS2WK+B9KhnXN
T/Nui3eBFpJdS6Jn+tntws6RgqxvWBlk2v5vmOmj817KwLkz9DOiuhJkw0GgCzls
Qwa+DRiVsER1d3UjX5DL/UmQpz+rW+aBkSuIq4rDu9x+1O3HzjXv8fFNBhXhaP7D
GFH8fEyqj6pfdYQ1jM8A009UrrQccdqaCLukwJ3JHl1TwN446I+C1Jya629gYumQ
4i72macA8+gCUb94GLgzwG9pKIjoV2dX0qex+Qfzr+gMwOIB8z46eCSl1G7Z67tX
nmIDGjZLH+xTT2cMQZxb5JHkW7l2qIfvIzF7dZR27oBZ32WBqoaw5ou3nat7lOVA
eOFKjgpue35EiSJaqkNyJ525uvLIKVLWyCOwfOcCJFSI1p1cBwyCSdhebdwTmFZ1
pZJR+V0e3QAL5CuwW5iR/hppP9w8NbNBMfFoOvJ/gDu7GGw26xkoYGW2BKBqDDGo
gjhx5jhqMENdPkAVg+3RAG/YlvCP6lqv6SKZsBibqk0R9nA+9t0ynYJPLgK18F54
b+E+Mj/o9W+Qcu4oN9wMRMCY4mWCPla0uoRPNtJCXsb/RK34tHXFbwyyE3+NiXcK
Tsrfp1lzDdL9yHO2c+wqj5cJA42Y/lHNVmex6N6XpqX4quK97GZqjalXlEUbYiHo
SnJrsEX7DrctDD6yAslZ1r7AwqLj2fNdjNIblmjSbY41X1jOJKvmsNOGKF4+sewR
F+Oe8UTAiVKY3fWblNvNRjRACyzZeeMBluCGID3cK2em4pfBsNhQXjBuiP4nbbu1
meTMaNZ7zB+zEia0YpsdBMKFOHLtyBQrLhyF7vPKTHb/tDCBjWhDW7djqb4i414m
ROM0BnX3LxZFvY18L15JtlV+YVe/SYTm1pLaa+mAETNoKPke75joOqJxwod6S6KI
jcgceXmjwveiE45lIrMcGlwOCQJ9YKAa417EjLNr12yf
-----END ENCRYPTED PRIVATE KEY-----

公钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6+6OY0J3HyVK5UjOUB9H
atBLz11LUlN5FUc8aABfRaI50j7xOX5gE2FcWf+/8MbG/c6jToXYgH5FIjK3qi8U
Usnrjo0q4kWeETPo7I1Ndg/GJI/IfExfU0QW6/9cdYYNSaD1wWm2VXHhBZk2F7/A
IiXgyIur8aDbEr342bc7HFACWGQN1FNrcssZHdx4Tk2W/DJZBIy+k7Agn3EXmkOn
bHVrsjDD/pUu2Q/sLjqzfwUnuAdQsyKV/x1JPlfrce1w47Zt8DeSt8Zjy7/eln9d
z3kpdoaj/44HnI6NXN2lqsfKzhLLc/zKljRgX76CYOo64YwwD8aDSXcNM5lZaroz
UwIDAQAB
-----END PUBLIC KEY-----

Encrypt messaage

RSA算法使用随机数生成器进行加密,导致每次加密的结果都不同,增加了破解的难度。但只要使用正确的私钥进行解密,无论加密结果是否相同,都可以将密文还原成相同的明文。RSA算法的安全性依赖于私钥保密和加密算法复杂度,而不是加密结果是否相同。

import base64

message = "Hello, world!"

message_encrypted = public_key.encrypt(
    message.encode(),
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None,
    ),
)

message_encrypted_str = base64.b64encode(message_encrypted).decode()
print(f"原始文本:\n{message}\n")
print(f"加密后的密文(Base64编码):\n{message_encrypted_str}")
原始文本:
Hello, world!

加密后的密文(Base64编码):
znaI16viQLfItYwyIDPcELQirKRiWaNAPw0xp6f3cPkAvUAH1kaJio+ps7MaFPH+1Eqy3K26EmaiKbDvCUuBFOU0iy//VunnvTc125hm2py38aN5BOrA/ZZhSomNV9CVfnzVWjMsJtv/HHqBd6q2wbJrrFFEJDux+bUcg7cCGCnTYuB5799eDAbXavUUXaV5J1yfqnRs1tvTJVLOQBwQdQqZNf9O64sKFVW0JvXNYKJDdSvKHie8FjjLWQbO1wG4L44lNspTjgmMWIWWnVC5RH4WwMcIRrfhOxeUSFd4zI3lztvPQbukUOnsWrJ18ZPqekvXeFjVRZDJoMyKcZ00TQ==

Decrypt

from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.backends import default_backend

# 从文件中获取 PEM 格式的字符串
with open('rsa_private_20230719.pem', 'rb') as f:
    private_key_pem = f.read()

password = get_rsa_private_key_password()

# 从 PEM 格式的字符串中加载加密的私钥
private_key = serialization.load_pem_private_key(
    private_key_pem, password=password, backend=default_backend()
)

message_encrypted = base64.b64decode(message_encrypted_str.encode())

# 使用私钥进行加解密
message_decrypted = private_key.decrypt(
    message_encrypted,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None,
    ),
)
print(f"解密后的明文:\n{message_decrypted.decode()}")
解密后的明文:
Hello, world!

References


What is RSA encryption, and how does it work?

你可能感兴趣的:(python,密码学)