Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSA加解密(一) #233

Open
soapgu opened this issue Jan 8, 2024 · 0 comments
Open

RSA加解密(一) #233

soapgu opened this issue Jan 8, 2024 · 0 comments
Labels

Comments

@soapgu
Copy link
Owner

soapgu commented Jan 8, 2024

  • 前言

需要进行有关加解密相关的Research,第一反应是比较流行的公钥加密RSA。
先直接跳过理论部分,用什么最快实现

  • 快速使用

对于解决方案最快捷方便的语言当然是python。
我用“通义千问”(阿里云的ChatGPT),用下来已经觉得非常不错了。简易我使用pycryptodome。
对于这种AI的回答本能的不信任,我先直接从PYPI里面找模块库,一般来说AI回答大方向出错可能性低,而细节错误率比较高。所以对GPT的使用还是以方向性的入口为主

图片 看上去AI没骗人

接下来参考相关文档开始使用

  1. 安装包
pip install pycryptodome
  1. 读取秘钥

这里我们使用固定的秘钥,从磁盘获取

recipient_key = RSA.import_key(open("publicKey").read())
private_key = RSA.import_key(open("privateKey").read())
  1. 加密和解密

这里直接给出完整代码

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

recipient_key = RSA.import_key(open("publicKey").read())
cipher_rsa = PKCS1_OAEP.new(recipient_key)
message = b'This is a secret message to be encrypted'
ciphertext = cipher_rsa.encrypt(message)

private_key = RSA.import_key(open("privateKey").read())
decipher_rsa = PKCS1_OAEP.new(private_key)
original_message = decipher_rsa.decrypt(ciphertext)
print("Decrypted original message:", original_message.decode('utf-8'))
  • RSA的加密长度限制

很快问题就来了,我例子里面用的是很短的字符串,如果我要加密一个文件怎么处理?我加密的长度在哪里?

先试试看把字符串弄长一点

Traceback (most recent call last):
  File "/Users/guhui/GitLabs/RsaDemo/demo.py", line 11, in <module>
    ciphertext = cipher_rsa.encrypt(message)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/Crypto/Cipher/PKCS1_OAEP.py", line 117, in encrypt
    raise ValueError("Plaintext is too long.")
ValueError: Plaintext is too long.

果然报错了

网上说明文的长度=密钥长度(Bytes)-11=1024/8 -11 = 117

实验了一下,果然不靠谱

guhui@guhuideMacBook-Pro RsaDemo % python3 demo.py
使用此密钥进行RSA加密时,最大明文长度是 117 字节
当前长度89
Traceback (most recent call last):
  File "/Users/guhui/GitLabs/RsaDemo/demo.py", line 11, in <module>
    ciphertext = cipher_rsa.encrypt(message)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/Crypto/Cipher/PKCS1_OAEP.py", line 117, in encrypt
    raise ValueError("Plaintext is too long.")
ValueError: Plaintext is too long.

最后还是谷歌一下

所以用11是错误的,而是具体情况具体长度。

It depends on the key size and the selected padding. The max block size is (in bytes): key_size_in_bytes - padding_margin

The padding margin is as follows:

RSA/ECB/PKCS1Padding, 11
RSA/ECB/NoPadding, 0
RSA/ECB/OAEPPadding, 42 // Actually it's OAEPWithSHA1AndMGF1Padding
RSA/ECB/OAEPWithMD5AndMGF1Padding, 34
RSA/ECB/OAEPWithSHA1AndMGF1Padding, 42
RSA/ECB/OAEPWithSHA224AndMGF1Padding, 58
RSA/ECB/OAEPWithSHA256AndMGF1Padding, 66
RSA/ECB/OAEPWithSHA384AndMGF1Padding, 98
RSA/ECB/OAEPWithSHA512AndMGF1Padding, 130
RSA/ECB/OAEPWithSHA3-224AndMGF1Padding, 58
RSA/ECB/OAEPWithSHA3-256AndMGF1Padding, 66
RSA/ECB/OAEPWithSHA3-384AndMGF1Padding, 98
RSA/ECB/OAEPWithSHA3-512AndMGF1Padding, 130

我们这里用的应该是42

实验一下果然,一字不差

max_plain_text_len = recipient_key.size_in_bytes() - 42 
print(f"使用此密钥进行RSA加密时,最大明文长度是 {max_plain_text_len} 字节")
guhui@guhuideMacBook-Pro RsaDemo % python3 demo.py
使用此密钥进行RSA加密时,最大明文长度是 86 字节
当前长度86
Ciphertext: b'\x99\xed\x90\x17J\x99v\x0eWjG\xe9\xafm\x0c\xc0@N\x80\x85\x9az\x0c>\xfb\x1b\x18|\xb9 \xb8\tm\xcfe\xc6\xefi\xe8\n\x85\xc3\x02\x7f1\xc7Y\x02\x1b\xaaY\x9392\x19\x84x\x99+c\x83\xb9\x9a\x92b\xbfu\xb4+\x1bP\x86\x86\x1a\x96\x04<\x8c\xf8a\xf5\xf7\x84\x15\x10\xe2\xfd\xfa]\x8f\x1fW\xd2\x93\xa3]1\x06D\xf0\xb1\xa4d\xc7\x0f\x83\x82\x11Mi\xa7.Cx&\x14\xc1\x08\x05\xcc\xca\xa10S\x8b(*\xf5'
128
86
Decrypted original message: This is a secret message to be encrypted,This is a secret message to be encrypted,This
  • RSA怎么实现长数据加密

既然有长度限制,就只能分块加密了

图片

下面是分块加密的代码

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import os

recipient_key = RSA.import_key(open("publicKey").read())
max_plain_text_len = recipient_key.size_in_bytes() - 42 
print(f"使用此密钥进行RSA加密时,最大明文长度是 {max_plain_text_len} 字节")
cipher_rsa = PKCS1_OAEP.new(recipient_key)

file_path = "sample.jpg"
output_filename = "cipher.data"
with open(file_path, 'rb') as in_file:
    with open(output_filename, 'wb') as out_file:
        while content := in_file.read(max_plain_text_len):  # 每次读取数据
            #print("---read data---")
            encrypted_chunk = cipher_rsa.encrypt(content)
            out_file.write(encrypted_chunk)

file_length = os.path.getsize(output_filename)
print(f"cipher file size:{file_length}")

分块解密的代码

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP

private_key = RSA.import_key(open("privateKey").read())
decipher_rsa = PKCS1_OAEP.new(private_key)
data_length = private_key.size_in_bytes()
print(f"私钥长度:{data_length}")

file_path = "cipher.data"
output_filename = "sample_restore.jpg"

with open(file_path, 'rb') as in_file:
    with open(output_filename, 'wb') as out_file:
        while content := in_file.read(data_length):  # 每次读取数据
            #print("---read data---")
            decrypted_chunk = decipher_rsa.decrypt(content)
            out_file.write(decrypted_chunk)

print("decrypt ok")
  • 小结

RSA加密解密的基础技术准备已经完成了,接下来把他做成http服务来做专门测试

@soapgu soapgu added the Research label Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant