I'd like to mention that I am completely new to Rust, and the code I'm about to share is simply an exercise to help me learn the language:
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"
The code works correctly on Ubuntu, meaning it accepts, decrypts, and displays a message sent by an Android app, but it fails to work on 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 }])
I installed OpenSSL on Windows (choco install openssl
) and set the environment variables (OPENSSL_DIR
, OPENSSL_INCLUDE_DIR
, and OPENSSL_LIB_DIR
). No errors or warnings were shown during compilation.
I suspect the issue lies with the OpenSSL version on Windows (3.1.1), which differs from the one on Ubuntu (3.0.2).
I'm unsure how to resolve this. Could anyone offer some guidance or suggestions for a solution?
PS: I tried cross-compiling on Ubuntu for the x86_64-pc-windows-gnu target but was not successful.
I was using an extremely large RSA key size of 16384 bits, and I might have confused the keys because it was late at night. However, after creating a new set of keys with a smaller RSA key size (2048) and reviewing them with fresh eyes the next day, everything functioned correctly.
Update:
"I'd keep RSA key sizes to 3072 bits or higher though, 2048 is analogous to a 112 bit secret key when attacked using classical computers. We generally aim for 128 bits and higher"
I've followed @maarten-bodewes advice and regenerated my key to 4096 bits.
I hope this information will be helpful to other users experiencing the same issue in the future.