我想提一下,我对 Rust 完全陌生,我要分享的代码只是一个帮助我学习该语言的练习:
use openssl::{
pkey::PKey,
rsa::{Padding, Rsa},
symm::{Cipher, Crypter, Mode},
encrypt::Decrypter,
};
use rpassword::read_password_from_tty;
use std::net::SocketAddr;
use tokio::{
net::UdpSocket,
};
#[tokio::main]
async fn main() {
// Load the private key
println!("Enter RSA private key passphrase:");
let passphrase = read_password_from_tty(Some("Passphrase: ")).expect("Failed to read passphrase");
let private_key = include_bytes!("private_key_enc2.pem");
let rsa = Rsa::private_key_from_pem_passphrase(private_key, passphrase.as_bytes()).expect("Failed to load private key");
let pkey = PKey::from_rsa(rsa).expect("Failed to create PKey from RSA");
// Start the UDP server
let addr: SocketAddr = "0.0.0.0:12345".parse().expect("Invalid socket address");
let socket = UdpSocket::bind(&addr)
.await
.expect("Failed to bind to the socket");
println!("Server listening on {}", addr);
let mut buf = [0; 65535]; // A buffer large enough for UDP packet
loop {
// Receive the encrypted message
let (len, _src) = socket.recv_from(&mut buf).await.expect("Failed to read from socket");
let data = &buf[..len];
// Extract the RSA-encrypted AES key, IV, and encrypted message by their lengths
// encrypted AES key length = 2048 bytes (16384 bits)
let (encrypted_aes_key, rest) = data.split_at(2048);
// IV length = 16 bytes for AES-256-CBC
let (iv, encrypted_message) = rest.split_at(16);
// Decrypt the AES key
let mut decrypter = Decrypter::new(&pkey).expect("Failed to create decrypter");
decrypter.set_rsa_padding(Padding::PKCS1_OAEP).expect("Failed to set padding");
decrypter.set_rsa_oaep_md(openssl::hash::MessageDigest::sha256()).expect("Failed to set OAEP digest");
decrypter.set_rsa_mgf1_md(openssl::hash::MessageDigest::sha256()).expect("Failed to set MGF1 digest");
let mut aes_key = vec![0; pkey.size()];
let aes_key_len = decrypter.decrypt(encrypted_aes_key, &mut aes_key).expect("Failed to decrypt AES key");
aes_key.truncate(aes_key_len);
// Decrypt the message using AES-256-CBC
let cipher = Cipher::aes_256_cbc();
let mut crypter = Crypter::new(cipher, Mode::Decrypt, &aes_key, Some(iv)).expect("Failed to create AES crypter");
let mut plaintext = vec![0; encrypted_message.len() + cipher.block_size()];
let count = crypter.update(encrypted_message, &mut plaintext).expect("Failed to decrypt message");
let rest = crypter.finalize(&mut plaintext[count..]).expect("Failed to finalize decryption");
plaintext.truncate(count + rest);
// Print the decrypted message
let message = String::from_utf8(plaintext).expect("Failed to parse plaintext as UTF-8");
println!("Received and decrypted message: {}", message);
}
}
...
[dependencies]
openssl = "0.10"
tokio = { version = "1", features = ["full"] }
rpassword = "5.0.1"
该代码在 Ubuntu 上可以正常工作,这意味着它可以接受、解密并显示 Android 应用程序发送的消息,但在 Windows 上无法工作:
thread 'main' panicked at src\main.rs:36:14:
Failed to decrypt AES key: ErrorStack([Error { code: 33554553, library: "rsa routines", function: "RSA_padding_check_PKCS1_OAEP_mgf1", reason: "oaep decoding error", file: "crypto\\rsa\\rsa_oaep.c", line: 314 }, Error { code: 33554546, library: "rsa routines", function: "rsa_ossl_private_decrypt", reason: "padding check failed", file: "crypto\\rsa\\rsa_ossl.c", line: 499 }])
我在 Windows 上安装了 OpenSSL (
choco install openssl
) 并设置了环境变量 (OPENSSL_DIR
、OPENSSL_INCLUDE_DIR
和 OPENSSL_LIB_DIR
)。编译期间没有显示错误或警告。
我怀疑问题在于 Windows (3.1.1) 上的 OpenSSL 版本,它与 Ubuntu (3.0.2) 上的版本不同。
我不确定如何解决这个问题。有人可以提供一些解决方案的指导或建议吗?
PS:我尝试在 Ubuntu 上对 x86_64-pc-windows-gnu 目标进行交叉编译,但没有成功。
我使用的是 16384 位的非常大的 RSA 密钥,由于当时是深夜,我可能混淆了密钥。然而,在创建一组具有较小 RSA 密钥大小 (2048) 的新密钥并在第二天重新审视它们后,一切都正常运行。
我希望这可以帮助将来遇到同样问题的其他用户。