【问题标题】:Encrypt/Decrypt Large text using rust's openssl library使用 rust 的 openssl 库加密/解密大文本
【发布时间】:2020-02-13 23:38:45
【问题描述】:

我正在尝试编写一个 API 来使用 rust 的 openssl 包装库来加密/解密文件。

这是图书馆: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 的图片如下所示。

我似乎无法弄清楚如何摆脱这些字符(这最终会增加我的文件大小),如果我选择使用填充,我将如何去做。

编辑:我应该注意,如果我将输出打印到终端,我看不到这些字符,但它们肯定存在于文件中。

感谢任何帮助。

【问题讨论】:

    标签: rust openssl


    【解决方案1】:

    这些字符是NUL 字节。它们来自代码中的两个方面:

    • 开头的那些来自你的decrypt_data_with_prikey函数。那个功能:
      • data_len 零初始化其输出向量;
      • 然后追加解密数据到这个向量。初始零永远不会被删除或覆盖。将 let mut decrypted_data: Vec&lt;u8&gt; = vec![0; data_len] 替换为 let mut decrypted_data = Vec::new() 以从空向量开始;如果您想为数据预先分配内存,则将 let mut decrypted_data = Vec::with_capacity (data_len) 替换。
    • 最后的那些来自您在加密期间添加的填充。您需要以某种方式将从加密函数添加到解密函数的填充量传达给解密函数,以便您可以将解密的数据截断为适当的长度。

    作为一个有点不相关的说明,当使用公钥/私钥对加密数据时,通常建议:

    • 创建一个随机对称密钥;
    • 用公钥加密该对称密钥;
    • 使用对称密钥加密数据;
    • 在标头中添加加密的对称密钥,以便接收方知道。

    这种方法有两个优点:

    • 提高了速度,因为对称密码比非对称密码快很多
    • 提高了安全性,因为它泄露的关于非对称密钥对的信息更少,因此即使攻击者设法解密消息,她也无法解密使用相同密钥对的其他消息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多