neosmart / cryptostream

Read and Write stream adapters for on-the-fly encryption and decryption for rust
https://neosmart.net/blog/2018/transparent-encryption-and-decryption-in-rust-with-cryptostreams/
Other
23 stars 6 forks source link

Implement AsyncRead and AsyncWrite #8

Closed nicolaspernoud closed 2 years ago

nicolaspernoud commented 2 years ago

Hello,

Thanks for your amazing work.

Juste wondering how (and if) it would be possible to implement async writers and readers to be used with tokio::fs::File . For the time beeing it does not seems to be possible to do something like :

let mut f =  tokio::fs::File::create(full_path).await?;
write::Encryptor::new(f, Cipher::aes_128_cbc(), &key, &iv).unwrap();
mqudsi commented 2 years ago

This is the problem with the current fragmentation of the async ecosystem in rust. Tokio doesn't use the "centralized" version of AsyncRead/AsyncWrite found in futures::io and instead has its own tokio::AsyncWrite, but cryptostream is a library that doesn't have any dependencies on tokio, async-std, or any other specific async runtime.

That said, if you are using this to do crypto operations on a file residing on disk or to/from a pipe (i.e. not a network stream), then my suggestion is to use the following instead:

tokio::task::block_in_place(|| {
    let mut f = std::fs::File::create(full_path)?;
    write::Encryptor::new(f, Cipher::aes_128_cbc(), &key, &iv).unwrap();
});

You should ideally be doing this even if you're not using crytostream because file io is not actually async under tokio (or any other mainstream reactor) and instead actually blocks a separate thread serving the IO request to make it look like an async operation. Using block_in_place with the std version of File (or pipe) will give you better performance in this case (this is well-documented in the tokio GitHub repo).

To actually make cryptostream work with any tokio AsyncRead/AsyncWrite object, the cryptostream crate would need a new (optional) feature ("tokio") that operates against those traits; you would be able to then use that version of the api to interface with any AsyncRead/AsyncWrite "stream" generic over its underlying type (network, file, pipe, etc). If you would like to work on this, I'm more than happy to help you open a PR.

nicolaspernoud commented 2 years ago

Hello, thanks for your answer. My use case is actually encrypting and decrypting a file from a network stream, so your suggestion would not be applicable, but I'll try to find another way.

Some other questions :

Best regards.

mqudsi commented 2 years ago
nicolaspernoud commented 2 years ago

Hello, Thanks a lot for your answers. Regarding the last point, it would be nice to have a library taking care of the IV generation and storage alongside the data to allow foolproof usage. But I understand that is not in the cryptostream roadmap at least for now.