Skip to content

RSA加密 in Python

Dockerfile

Dockerfile
FROM ubuntu:22.04

RUN sed -i 's/archive.ubuntu.com/cn.archive.ubuntu.com/g' /etc/apt/sources.list
RUN apt update

RUN apt install -y libpq-dev
RUN apt install -y python3.8 python3-pip python3-dev
RUN apt install -y make
RUN apt install -y libssl-dev swig

RUN DEBIAN_FRONTEND=noninteractive TZ=Asia/Shanghai apt-get -y install tzdata
ENV TZ=Asia/Shanghai

RUN python3.8 -m pip install poetry -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN ln -s /usr/bin/python3 /usr/bin/python

Anaconda

Anaconda
cd test/
conda create --name test
conda activate test

conda install python=3.11.4
# conda install -c conda-forge swig
# conda install -c conda-forge openssl
conda install -c conda-forge M2Crypto

conda env remove --name=test

m2crypto rsa

python
from M2Crypto import RSA, BIO
from base64 import b64decode


def generate_keys():
    key = RSA.gen_key(2048, 65537, callback=lambda x, y, z: None)

    bio = BIO.MemoryBuffer()
    key.save_key_bio(bio, cipher=None)
    private_key = bio.read()

    bio = BIO.MemoryBuffer()
    key.save_pub_key_bio(bio)
    public_key = bio.read()
    return private_key, public_key


class M2CryptoPubKey:
    def __init__(self, pubkey_b64: str, is_protcol: bool = False):
        self.rsa_pub = self.load_rsa_pubkey(pubkey_b64, is_protcol=is_protcol)

    @staticmethod
    def load_rsa_pubkey(pubkey_b64: str, is_protcol: bool = False) -> RSA.RSA:
        pem_string = pubkey_b64 if is_protcol else f"-----BEGIN PUBLIC KEY-----\n{pubkey_b64}\n-----END PUBLIC KEY-----"
        return RSA.load_pub_key_bio(BIO.MemoryBuffer(pem_string.encode()))

    def pub_encrypt(self, plaintext: bytes) -> bytes:
        return self.rsa_pub.public_encrypt(plaintext, RSA.pkcs1_padding)

    def pub_decrypt(self, cipher: bytes) -> bytes:
        max_length = 128
        output = b''
        while cipher:
            input_content = cipher[:max_length]
            cipher = cipher[max_length:]
            out = self.rsa_pub.public_decrypt(input_content, RSA.pkcs1_padding)
            output += out
        return output


class M2CryptoPriKey:
    def __init__(self, prikey_b64: str, is_protcol: bool = False):
        self.rsa_pri = self.load_prikey(prikey_b64, is_protcol=is_protcol)

    @staticmethod
    def load_prikey(prikey_b64: str, is_protcol: bool = False) -> RSA.RSA:
        pem_string = prikey_b64 if is_protcol else f"-----BEGIN RSA PRIVATE KEY-----\n{prikey_b64}\n-----END RSA PRIVATE KEY-----"
        return RSA.load_key_bio(BIO.MemoryBuffer(pem_string.encode()))

    def priv_encrypt(self, plaintext: bytes) -> bytes:
        max_block = 245
        padding = RSA.pkcs1_padding

        plaintext_length = len(plaintext)
        if plaintext_length < max_block:
            return self.rsa_pri.private_encrypt(plaintext, padding)
        offset = 0
        ciphers = []
        while plaintext_length - offset > 0:
            if plaintext_length - offset > max_block:
                ciphers.append(self.rsa_pri.private_encrypt(plaintext[offset:offset + max_block], padding))
            else:
                ciphers.append(self.rsa_pri.private_encrypt(plaintext[offset:], padding))
            offset += max_block
        return b"".join(ciphers)

    def priv_decrypt(self, ciphertext: bytes) -> bytes:
        max_block = 256
        padding = RSA.pkcs1_padding

        blocks = [ciphertext[i:i + max_block] for i in range(0, len(ciphertext), max_block)]
        decrypted_blocks = [self.rsa_pri.private_decrypt(block, padding) for block in blocks]
        return b''.join(decrypted_blocks)


if __name__ == '__main__':
    pri_key = ''''''
    clear_text = ''

    mp = M2CryptoPriKey(pri_key)
    e = b64decode(clear_text.encode())
    r = mp.priv_decrypt(e)
    print(r)

Released under the MIT License.