【python】常用pycryptodome完成RSA非对称加密解密、签名验签

1.安装pycryptodome

安装pycryptodome

pip install pycryptodome

2.生成随机公私钥

生成公私钥,并且导出为PEM格式,保存问文件

from Crypto.PublicKey import RSA

key = RSA.generate(2048)

pri_key = key.export_key()
with open("./pri_key.pem", "wb") as f:
    f.write(pri_key)

pub_key = key.public_key().export_key()
with open("./pub_key.pem", "wb") as f:
    f.write(pub_key)

3.读取私钥

私钥可以转换成公钥,所以读取了私钥就相当于读取了公钥

from Crypto.PublicKey import RSA

with open("./pri_key.pem", "r") as f:
    pri_key_pem = f.read()

key = RSA.import_key(pri_key_pem)
pri_key = key.export_key()
print("pri_key:", pri_key)
pub_key = key.public_key().export_key()
print("pub_key:", pub_key)

4.加密解密

我们使用前面生成的密钥对进行加密解密操作, 使用公钥加密,然后使用私钥解密

import base64
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto.PublicKey import RSA


def get_key(path):
    with open(path) as f:
        pem_data = f.read()
        return RSA.importKey(pem_data)


def encrypt(msg, pub_path):
    key = get_key(pub_path)
    cipher = PKCS1_cipher.new(key)
    encrypt_msg = cipher.encrypt(msg.encode("utf-8"))
    return base64.b64encode(encrypt_msg).decode()


def decrypt(msg, pri_path):
    key = get_key(pri_path)
    cipher = PKCS1_cipher.new(key)
    decrypt_data = cipher.decrypt(base64.b64decode(msg), 0)
    return decrypt_data.decode("utf-8")


if __name__ == '__main__':
    original_msg = "hello world"
    encrypted_data = encrypt(original_msg, "./pub_key.pem")
    print("encrypt_data:", encrypted_data)
    decrypted_data = decrypt(encrypted_data, "./pri_key.pem")
    print("decrypt_data:", decrypted_data)

5.加密长字符串

虽然上面的方法可以加密和解密,但有一个问题,那就是字符串超出一定长度就会报错“ValueError: Plaintext is too long.”,原来能加密的字符串的长度与公私钥位数有关,max_lengt = (秘钥位数/8 - 11),比如说你的秘钥是1024位,那加密的字符串长度不能超过1024/8 - 11 = 117个。

解决方法也很简单,我们把长字符串进行分割,然后进行加密解密操作之后再拼接为一个完整的字符串即可

import base64
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
from Crypto.PublicKey import RSA

default_encoding = "utf-8"


def get_key(key_or_path):
    if "BEGIN PUBLIC KEY" in key_or_path or "BEGIN PRIVATE KEY" in key_or_path:
        pem_data = key_or_path
    else:
        with open(key_or_path) as f:
            pem_data = f.read()
    return RSA.importKey(pem_data)


def rsa_encrypt(msg, pub_path, max_length=100):
    """
    RSA加密
    :param msg: 加密字符串
    :param pub_path: 公钥路径
    :param max_length: 1024bit的秘钥不能超过117, 2048bit的秘钥不能超过245
    :return:
    """
    key = get_key(pub_path)
    cipher = PKCS1_cipher.new(key)
    res_byte = bytes()
    for i in range(0, len(msg), max_length):
        res_byte += cipher.encrypt(msg[i:i + max_length].encode(default_encoding))
    return base64.b64encode(res_byte).decode(default_encoding)


def rsa_decrypt(msg, pri_path, max_length=256):
    """
    RSA解密
    :param msg: 加密字符串
    :param pri_path: 私钥路径
    :param max_length: 1024bit的秘钥用128,2048bit的秘钥用256位
    :return:
    """
    key = get_key(pri_path)
    cipher = PKCS1_cipher.new(key)

    res_bytes = bytes()
    encrypt_data = base64.b64decode(msg)
    for i in range(0, len(encrypt_data), max_length):
        res_bytes += cipher.decrypt(encrypt_data[i:i + max_length], 0)
    return res_bytes.decode(default_encoding)


if __name__ == '__main__':
    original_msg = """很长的字符串'""" * 300
    encrypted_data = rsa_encrypt(original_msg, "./pub_key.pem")
    print("encrypt_data:", encrypted_data)
    decrypted_data = rsa_decrypt(encrypted_data, "./pri_key.pem")
    print("decrypt_data:", decrypted_data)

6.签名和验证签名

前面的做法是使用公钥加密、私钥解密,但还有一种比较常用的场景是使用私钥加密、公钥解密,这种做法的主要目的是对某些数据生成签名,使用公钥验证签名,判断数据是否被篡改

import base64

from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5


def get_key(path):
    with open(path) as f:
        pem_data = f.read()
        return RSA.importKey(pem_data)


def generate_sign(un_sign_data, pri_key):
    signer = Signature_pkcs1_v1_5.new(pri_key)
    digest = SHA256.new()
    digest.update(un_sign_data.encode("utf-8"))
    signed_data = signer.sign(digest)
    return base64.b64encode(signed_data).decode("utf-8 ")


def verify_sign(un_sign_data, signature, pub_key):
    verifier = Signature_pkcs1_v1_5.new(pub_key)
    digest = SHA256.new()
    digest.update(un_sign_data.encode("utf-8"))
    return verifier.verify(digest, base64.b64decode(signature))


if __name__ == '__main__':
    data = "hello world" * 20
    signature = generate_sign(data, get_key("./pri_key.pem"))
    print("signature:", signature)
    is_ok = verify_sign(data, signature, get_key("./pub_key.pem"))
    print("is_ok:", is_ok)

猜你喜欢

转载自blog.csdn.net/qq_39147299/article/details/127754854
今日推荐