5 个不稳定版本

0.3.2 2022年8月13日
0.3.1 2020年3月7日
0.3.0 2019年12月14日
0.2.0 2019年12月12日
0.1.0 2018年9月3日

#505 in 加密学

32 每月下载
3 crates 中使用

MIT 许可证

48KB
789

Rust Cryptostream 库

crates.io docs.rs

cryptostream 提供了与 .NET Cryptostream 类的 Rust 等价物,为现有 ReadWrite 资源的即时加密或解密提供了一个高效且易于使用的解决方案。加密是通过 rust-openssl 提供的,并且可以完全配置。

什么是 Cryptostream?

简而言之,Cryptostream 是一个围绕流(在 Rust 术语中,是 ReadWrite 类型)的包装器,它可以透明地加密或解密底层内容。在指定了加密算法、密钥和 IV 之后创建了一个 Cryptostream 实例,写入或读取到 Cryptostream 的字节与包装的 ReadWrite 流相同,只是额外地进行了加密或解密。这使得处理加密源或目标变得非常简单,几乎不需要更改现有的管道 - 它就像任何其他的 ReadWrite 一样。

库设计

由于 Rust(无论是好是坏)缺少 Stream 类型,cryptostream 已在加密和解密模式下分别实现了两次,一次作为 Read 实现,一次作为 Write 实现(设计灵感来自 flate2 库),为了万无一失还添加了 BufRead 实现。这意味着对于任何可用的 [密文|明文] 和所需的 [读取|写入] 应用组合,cryptostream 实现之一应该符合您的用例。应创建一个与您希望消费的资源类型相匹配的 cryptostream(如果源数据是 Read 实现),或者与您希望创建的资源类型相匹配的 cryptostream(如果目标是 Write 实现)。

实现已按特性分组到命名空间中,并且具有传达其应用的名字

  • cryptostream::read::Encryptor
  • cryptostream::read::Decryptor
  • cryptostream::write::Encryptor
  • cryptostream::write::Decryptor

ReadWrite 加密流

cryptostreamReadWrite 变体之间的区别,或许通过示例最能说明。在以下两个示例中,我们都会进行解密,然而在一个情况下我们需要使用 read::Decryptor,而在另一个情况下使用 write::Decryptor

在第一种情况下,我们有一个 Read 源,其中包含我们需要解密的字节,并且我们希望在内存中获得等效的明文,以便稍后对其进行解码状态的操作


// This is the cipher text, base64-encoded to avoid any whitespace munging. In this
// contrived example, we are using a binary `Vec<u8>` as the `Read` source containing
// the encrypted data; in practice it could be a binary file, a network stream, or
// anything else.
let src: Vec<u8> = decode(concat!(
    "vuU+0SXFWQLu8vl/o1WzmPCmf7x/O6ToGQ162Aq2CHxcnc/ax/Q8nTbRlNn0OSPrFuE3yDdO",
    "VC35RmwtUIlxKIkWbnxJpRF5yRJvVByQgWX1qLW8DfMjRp7gVaFNv4qr7G65M6hbSx6hGJXv",
    "Q6s1GiFwi91q0V17DI79yVrINHCXdBnUOqeLGfJ05Edu+39EQNYn4dky7VdgTP2VYZE7Vw==",
))
.unwrap();
let key: Vec<_> = decode("kjtbxCPw3XPFThb3mKmzfg==").unwrap();
let iv: Vec<_> = decode("dB0Ej+7zWZWTS5JUCldWMg==").unwrap();

// The source can be anything implementing `Read`. In this case, a simple &[u8] slice.
let mut decryptor =
    read::Decryptor::new(src.as_slice(), Cipher::aes_128_cbc(), &key, &iv).unwrap();

let mut decrypted = [0u8; 1024]; // a buffer to decrypt into
let mut bytes_decrypted = 0;

loop {
    // Just read from the `Decryptor` as if it were any other `Read` impl,
    // the decryption takes place automatically.
    let read_count = decryptor.read(&mut decrypted[bytes_decrypted..]).unwrap();
    bytes_decrypted += read_count;
    if read_count == 0 {
        break;
    }
}

println!("{}", String::from_utf8_lossy(&decrypted));

那么,如果你想要将解密的内容 写入 而不是 读取,但仍想进行解密,怎么办呢?


// Starting again with the same encrypted bytestream, encoded as base64:
let src: Vec<u8> = decode(concat!(
    "vuU+0SXFWQLu8vl/o1WzmPCmf7x/O6ToGQ162Aq2CHxcnc/ax/Q8nTbRlNn0OSPrFuE3yDdO",
    "VC35RmwtUIlxKIkWbnxJpRF5yRJvVByQgWX1qLW8DfMjRp7gVaFNv4qr7G65M6hbSx6hGJXv",
    "Q6s1GiFwi91q0V17DI79yVrINHCXdBnUOqeLGfJ05Edu+39EQNYn4dky7VdgTP2VYZE7Vw=="
))
.unwrap();
let key: Vec<_> = decode("kjtbxCPw3XPFThb3mKmzfg==").unwrap();
let iv: Vec<_> = decode("dB0Ej+7zWZWTS5JUCldWMg==").unwrap();

// The destination can be any object implementing `Write`: in this case, a `Vec<u8>`.
let mut decrypted = Vec::new();

// When a `cryptostream` is dropped, all buffers are flushed and it is automatically
// finalized. We can either call `drop()` on the cryptostream or put its usage in a
// separate scope.
{
    let mut decryptor =
        write::Decryptor::new(&mut decrypted, Cipher::aes_128_cbc(), &key, &iv).unwrap();

    let mut bytes_decrypted = 0;

    while bytes_decrypted != src.len() {
        // Just write encrypted ciphertext to the `Decryptor` instance as if it were any
        // other `Write` impl. Decryption takes place automatically.
        let write_count = decryptor.write(&src[bytes_decrypted..]).unwrap();
        bytes_decrypted += write_count;
    }
}

// The underlying `Write` instance is only guaranteed to contain the complete and
// finalized contents after the cryptostream is either explicitly finalized with a
// call to `Cryptostream::finish()` or when it's dropped (either at the end of a scope
// or via an explicit call to `drop()`, whichever you prefer).
println!("{}", String::from_utf8_lossy(&decrypted));

依赖项

~1.8–3MB
~70K SLoC