Зашифруйте / расшифруйте большой текст с помощью библиотеки ржавчины openssl - PullRequest
0 голосов
/ 17 октября 2019

Я пытаюсь написать API для использования библиотеки оболочки openssl rust для шифрования / дешифрования файлов.

Это библиотека: https://docs.rs/openssl/0.10.25/openssl/index.html

Все примеры в документации показываютКак зашифровать короткие строки, используя Padding. Я хочу зашифровать возможно длинные файлы.

Проблема в том, что я могу зашифровать только до длины ключа (используя Padding::NONE). Я хочу, возможно, зашифровать более длинные фрагменты данных.

Таким образом, чтобы обойти эту проблему, я разбиваю данные на фрагменты, шифрую / дешифрую каждый фрагмент, добавляю зашифрованный / дешифрованный кусок в результирующий вектор. Затем я записываю его в файл и читаю из файла в вектор перед тем, как расшифровать его.

Описание того, что я делаю:

  1. Загрузка / генерация открытых / закрытых ключей.
  2. Загрузить файл для шифрования в Vec<u8> (или, в конечном итоге, фрагмент строки)
  3. Использовать открытый ключ для шифрования данных
  4. Записать эти зашифрованные данные в файл
  5. Загрузить файл с зашифрованными данными в Vec<u8>
  6. Расшифровать с помощью закрытого ключа
  7. Записать расшифрованные данные в другой файл.
  8. Сравнить исходные данные с расшифрованными.

Код здесь (будьте осторожны - я скопировал и вставил вещи в один блок ниже, изначально они были в отдельных модулях / файлах). Сначала я генерирую ключ rsa, как

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)
}

Затем я пишуих в файл и использовать ключи из файла для последующих запусков.

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
}

Проблема, с которой я сталкиваюсь, заключается в том, что в моем файле я нахожу так много странных символов в начале и в конце расшифрованный файл. Изображение из vim показано ниже.

enter image description here

Кажется, я не могу понять, как избавиться от этих символов (которые в конечном итоге увеличивают размер моего файла) и,если бы я решил использовать отступы, то как бы я поступил так же.

Редактировать: я должен заметить, что если я печатаю вывод в терминал, я не вижу эти символы, но они определенно присутствуют в файле.

Любая помощь приветствуется.

1 Ответ

1 голос
/ 17 октября 2019

Эти символы NUL байтов. Они приходят из двух областей в вашем коде:

  • Те, что в начале, происходят из вашей функции decrypt_data_with_prikey. Эта функция:
    • Инициализирует свой выходной вектор с data_len нулями;
    • Затем добавляет расшифрованные данные к этому вектору. Начальные нули никогда не удаляются и не перезаписываются. Замените let mut decrypted_data: Vec<u8> = vec![0; data_len] на let mut decrypted_data = Vec::new(), чтобы начать с пустого вектора, или let mut decrypted_data = Vec::with_capacity (data_len), если вы хотите предварительно выделить память для данных.
  • Те, что в конце, получены иззаполнение, которое вы добавляете во время шифрования. Вам нужно будет каким-то образом передать количество заполнения, которое было добавлено из функции шифрования в функцию дешифрования, чтобы можно было усечь расшифрованные данные до соответствующей длины.

Как несколько не связанныйобратите внимание, что при шифровании данных парой открытого и закрытого ключей обычно рекомендуется:

  • Создать случайный симметричный ключ;
  • Зашифровать этот симметричный ключс открытым ключом;
  • Шифрование данных с помощью симметричного ключа;
  • Добавьте зашифрованный симметричный ключ в заголовок, чтобы получатель мог его узнать.

У этого подхода есть два преимущества:

  • Повышенная скорость, поскольку симметричные шифры намного быстрее, чем асимметричные.
  • Повышенная безопасность, поскольку утечка меньшей информации о паре асимметричных ключейпоэтому даже если злоумышленнику удастся расшифровать сообщение, он не сможет расшифровать другие сообщения, использующие ту же пару ключей.
...