Reputation: 1717
I am trying to write an API to use rust's openssl wrapper library to encrypt/decrypt files.
This is the library : https://docs.rs/openssl/0.10.25/openssl/index.html
All the examples in the documentation, show how to encrypt short strings using Padding. I want to encrypt possibly long files.
The problem is I can only encrypt up to the length of the key(using Padding::NONE
). I want to possibly encrypt longer pieces of data.
So in order to get around that problem, I break the data into chunks, encrypt/decrypt each chunk, append the encrypted/decrypted chunk into a result Vector. I then write it to file & read from file to vector before decrypting the same.
Outline of what I do:
Vec<u8>
(or string slice, ultimately)Vec<u8>
Code is here (Beware - I copy-pasted stuff to one block below, originally they were in separate modules/files) I generate the rsa key initially like
fn generate_rsa_key_pair() -> utils::Pair<Vec<u8>, Vec<u8>> {
let rsa = Rsa::generate(4096).unwrap();
let public_pem = rsa.public_key_to_pem().unwrap();
let private_pem = rsa.private_key_to_pem().unwrap();
Pair::new(public_pem, private_pem) // custom data structure (basically a tuple)
}
I then write them to a file and use the keys from the file for subsequent runs.
extern crate openssl;
use openssl::pkey::{Private, Public};
use openssl::rsa::{Padding, Rsa};
use std::cmp::max;
use std::io::{BufWriter, Result, Write};
use std::str;
fn main() {
let (public, private) = generate_rsa_from_files();
let data = read_file_into_binary_vec("./resources/example_text.txt").unwrap();
let enc_data = encrypt_data_with_pubkey(data.as_slice(), public).unwrap();
println!("{:?}", enc_data);
binary_slice_to_file(enc_data.as_slice(), "./resources/example_enc.txt").unwrap();
let dec_data = decrypt_data_with_prikey(enc_data.as_slice(), private).unwrap();
println!("{}", str::from_utf8(dec_data.as_slice()).unwrap());
binary_slice_to_file(dec_data.as_slice(), "./resources/example_dec.txt").unwrap();
}
fn generate_rsa_from_files() -> (Vec<u8>, Vec<u8>) {
let public = read_file_into_binary_vec("./resources/public_key").unwrap();
let private = read_file_into_binary_vec("./resources/private_key").unwrap();
(public, private)
}
fn read_file_into_binary_vec(file_path: &str) -> Result<Vec<u8>> {
std::fs::read(file_path)
}
fn binary_slice_to_file(data: &[u8], file_path: &str) -> Result<()> {
let file = std::fs::File::create(file_path)?;
let mut buf_writer = BufWriter::new(file);
buf_writer.write_all(data)
}
fn encrypt_data_with_pubkey(data: &[u8], pub_key: Vec<u8>) -> Result<Vec<u8>> {
let data_len = data.len();
let public_rsa: Rsa<Public> = Rsa::public_key_from_pem(pub_key.as_slice())?;
let buf_len = public_rsa.size() as usize;
let mut buffer: Vec<u8> = vec![0; buf_len];
let mut encrypted_data: Vec<u8> = Vec::with_capacity(max(data_len, buf_len));
println!("{}", public_rsa.size());
for chunk in data.chunks(buf_len) {
println!("Encrypting (len = {}): {:?}", chunk.len(), chunk);
let chunk_mod;
if chunk.len() < buf_len {
chunk_mod = pad_chunk_to_size(chunk, buf_len);
} else {
chunk_mod = Vec::from(chunk);
}
let chunk_mod = chunk_mod.as_slice();
println!("Encrypting (len = {}): {:?}", chunk_mod.len(), chunk_mod);
let enc_len = public_rsa
.public_encrypt(chunk_mod, buffer.as_mut_slice(), Padding::NONE)
.expect("Error Encrypting");
println!("Enc Data Len : {}", enc_len);
encrypted_data.extend_from_slice(buffer.as_slice());
}
Ok(encrypted_data)
}
fn decrypt_data_with_prikey(enc_data: &[u8], priv_key: Vec<u8>) -> Result<Vec<u8>> {
let data_len = enc_data.len();
let private_rsa: Rsa<Private> = Rsa::private_key_from_pem(priv_key.as_slice())?;
let buf_len = private_rsa.size() as usize;
let mut buffer: Vec<u8> = vec![0; buf_len];
let mut decrypted_data: Vec<u8> = vec![0; data_len];
println!("{}", private_rsa.size());
for chunk in enc_data.chunks(buf_len) {
private_rsa.private_decrypt(chunk, &mut buffer, Padding::NONE).expect("Error Decrypting");;
decrypted_data.extend_from_slice(buffer.as_slice());
}
Ok(decrypted_data)
}
fn pad_chunk_to_size(chunk: &[u8], desired_size: usize) -> Vec<u8> {
let mut resized_vec = Vec::with_capacity(desired_size);
for &element in chunk {
resized_vec.push(element);
}
while resized_vec.len() < desired_size {
resized_vec.push(0);
}
println!(
"Desired Length = {}, Actual Length = {}",
desired_size,
resized_vec.len()
);
resized_vec
}
The problem I face is, In my file, I find so many weird characters at the beginning and end of the decrypted file. Image from vim shown below.
I cannot seem to figure out how to get rid of those characters(which ultimately increase my file size) and, if I chose to use padding, how I would go about doing the same.
Edit: I should note, if I print the output to terminal, I cannot see those characters, but they are definitely present in the file.
Any help is appreciated.
Upvotes: 0
Views: 3606
Reputation: 23329
Those characters are NUL
bytes. They come from two areas in your code:
decrypt_data_with_prikey
function. That function:
data_len
zeroes;let mut decrypted_data: Vec<u8> = vec![0; data_len]
with let mut decrypted_data = Vec::new()
to start with an empty vector or let mut decrypted_data = Vec::with_capacity (data_len)
if you want to pre-allocate the memory for the data.As a somewhat unrelated note, when encrypting data with a public/private key pair, it is usually recommended to:
This approach has two advantages:
Upvotes: 2