如何在Python中实现RSA密钥生成、消息签名、接收方公钥加密及Base64编码的完整流程并解决相关错误?
如何在Python中实现RSA密钥生成、消息签名、接收方公钥加密及Base64编码的完整流程并解决相关错误?
我尝试用朋友的公钥recipient_public_key加密新生成的密钥,然后将最终结果用Base64编码。这个流程也可以通过安装相关工具后用Kleopatra这类工具分步完成,但我不想使用这类工具。
任务要求
生成一个1024位的RSA密钥对,使用你的用户名作为标识。针对以下消息,仅签名不加密:
待签名消息:This is my secret message
在一个文本文件中包含以下内容:你的公钥、上述消息、消息的Base64编码签名。然后用接收方的公钥加密这个文件,将最终输出Base64编码后打印出来。
我的尝试与遇到的问题
最开始我用Python的相关库(比如python-gnupg、pycryptodome)生成了以我的名字作为用户名的1024位RSA密钥对,尝试按要求签名消息,但遇到了如下错误:
ValueError: Plaintext is too long.
第一种实现方式(使用pycryptodome和pgpy)
# !pip install pycryptodome from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP from Crypto.Signature import pkcs1_15 from Crypto.Hash import SHA256 import base64 import pgpy # Import pgpy # Step 1: Generate RSA key pair key = RSA.generate(1024) private_key = key.export_key() public_key = key.publickey().export_key() # Step 2: Save your public key for submission with open("my_public_key.pem", "wb") as f: f.write(public_key) # Step 3: Prepare the message with your name message = "This is my secret messgae" message_bytes = message.encode() # Step 4: Sign the message with the private key hash_message = SHA256.new(message_bytes) signature = pkcs1_15.new(key).sign(hash_message) # Step 5: Base64 encode the signature signature_base64 = base64.b64encode(signature) # Step 6: Save the public key, message, and signature in a file with open("final-msg.txt", "wb") as f: f.write(public_key + b"\n" + message_bytes + b"\n" + signature_base64) # Step 7: Encrypt the final message with the provided public key recipient_public_key_pem = """-----BEGIN PGP PUBLIC KEY BLOCK----- ............. -----END PGP PUBLIC KEY BLOCK-----""" # Step 7: Encrypt the final message with the provided public key # **Increased key size to 2048 bits** key = RSA.generate(2048) private_key = key.export_key() public_key = key.publickey().export_key() # Use pgpy to import the PGP key recipient_key, _ = pgpy.PGPKey.from_blob(recipient_public_key_pem) # Re-initialize cipher_rsa with the new key cipher_rsa = PKCS1_OAEP.new(key) # Encrypt final-msg.txt with the recipient's public key with open("final-msg.txt", "rb") as f: final_msg = f.read() encrypted_message = cipher_rsa.encrypt(final_msg) # Step 8: Base64 encode the encrypted message encrypted_message_base64 = base64.b64encode(encrypted_message) # Step 9: Save the base64 encoded encrypted message with open("final_msg_base64.txt.gpg", "wb") as f: f.write(encrypted_message_base64) print("Encryption completed. The Base64-encoded encrypted message is saved in 'final_msg_base64.txt.gpg'")
第二种实现方式(遵循DRY原则,使用python-gnupg)
# !pip install python-gnupg import gnupg import base64 # Initialize GPG gpg = gnupg.GPG() # 1. Generate an RSA Key Pair input_data = gpg.gen_key_input( key_type="RSA", key_length=1024, name_real="Alice Bob", # Replace with your name name_email="Alice.Bob@gmail.com", # Replace with your email expire_date=0 # Key does not expire ) key = gpg.gen_key(input_data) print(f"Generated Key Fingerprint: {key.fingerprint}") # 2. Create the message message = f"This is my secret message" with open("msg.txt", "w") as f: f.write(message) # 3. Sign the message #signed_data = gpg.sign(message, default_key=key.fingerprint, detach=True) signed_data = gpg.sign(message, keyid=key.fingerprint, detach=True) # Write the signature data to a file in binary mode with open("msg.sig", "wb") as f: # Open in binary write mode ("wb") f.write(signed_data.data) # Write the bytes directly # 4. Base64 encode the signature with open("msg.sig", "rb") as sig_file: signature_base64 = base64.b64encode(sig_file.read()).decode("utf-8") with open("msg-base64.sig", "w") as encoded_sig_file: encoded_sig_file.write(signature_base64) # 5. Export your public key public_key = gpg.export_keys(key.fingerprint) with open("my_public_key.asc", "w") as pubkey_file: pubkey_file.write(public_key) # 6. Concatenate the public key, message, and Base64-encoded signature with open("final-msg.txt", "w") as final_file: final_file.write(public_key) final_file.write("\n" + message + "\n") final_file.write(signature_base64) # 7. Import recipient's public key recipient_public_key ="""-----BEGIN PGP PUBLIC KEY BLOCK----- .......... -----END PGP PUBLIC KEY BLOCK-----""" # Replace with the actual provided public key import_result = gpg.import_keys(recipient_public_key) print("Imported Recipient's Public Key:", import_result.fingerprints) # 8. Encrypt the final message with the recipient's public key with open("final-msg.txt", "rb") as final_msg_file: # Use encrypt instead of encrypt_file encrypted_data = gpg.encrypt( final_msg_file.read(), # Read the file content import_result.fingerprints, # Pass recipients as positional argument output="final-msg.txt.gpg" ) if encrypted_data.ok: print("Message encrypted successfully.") else: print(f"Encryption failed: {encrypted_data.status}") # Print the error status print(encrypted_data.stderr) # Print any error details to help with debugging # Only proceed to base64 encoding if encryption was successful if encrypted_data.ok: # 9. Base64 encode the encrypted file with open("final-msg.txt.gpg", "rb") as encrypted_file: encrypted_base64 = base64.b64encode(encrypted_file.read()).decode("utf-8") with open("final_msg_base64.txt.gpg", "w") as encoded_encrypted_file: encoded_encrypted_file.write(encrypted_base64) # Output the Base64 encoded result print("Base64 Encoded Encrypted Message:") print(encrypted_base64) else: print("Skipping base64 encoding due to encryption failure.")
运行第二种方式后,我得到了如下错误输出:
WARNING:gnupg:potential problem: ERROR: key_generate 83918950 WARNING:gnupg:gpg returned a non-zero error code: 2 WARNING:gnupg:potential problem: FAILURE: sign 17 WARNING:gnupg:gpg returned a non-zero error code: 2 WARNING:gnupg:gpg returned a non-zero error code: 2 WARNING:gnupg:gpg returned a non-zero error code: 2 Generated Key Fingerprint: Imported Recipient's Public Key: ['1AB8693860852A6B0EE7DD81B8F979BA0A99A039'] Encryption failed: invalid recipient [GNUPG:] KEY_CONSIDERED 1AB8693860852A6B0EE7DD81B8F979BA0A99A039 0 gpg: 8D7830FB995B0A91: There is no assurance this key belongs to the named user [GNUPG:] INV_RECP 10 1AB8693860852A6B0EE7DD81B8F979BA0A99A039 [GNUPG:] FAILURE encrypt 53 gpg: [stdin]: encryption failed: Unusable public key Skipping base64 encoding due to encryption failure.
我现在的疑问是:如何正确实现用目标接收方的公钥recipient_public_key加密包含密钥、消息和签名的文件,然后Base64编码,让接收方可以用自己的密钥解密并读取消息?
备注:内容来源于stack exchange,提问作者Mario




