Conversation
|
Note: I left allocating APIs out of this PR as well to make it easier to review, but they're easily added in a follow-up. |
874b73e to
1c1bfb9
Compare
| if self.position == S::COUNTER_MAX { | ||
| // Counter overflow | ||
| return Err(Error); | ||
| } |
There was a problem hiding this comment.
Note that this implementation precludes calling encrypt_next_in_place/decrypt_next_in_place with the maximum counter value.
That's deliberate: it ensures any segment encrypted under the maximum counter value MUST have the "last block" flag set.
| #[doc = $obj_desc] | ||
| #[doc = "object in order to prevent further use."] | ||
| pub fn $last_method( | ||
| self, |
There was a problem hiding this comment.
Consuming self here is annoying in async encryptors, where we may need to leave poll_close after encrypting the last chunk but before we've finished writing the encrypted chunk. It can be managed by storing an Option<aead::stream::Encryptor>, but it's a bit of a hassle.
More problematic is that consuming self here is incompatible with seeking decryptors, as we may need to decrypt the last chunk, read part of it, then seek back earlier than the last chunk. Decryptor doesn't implement Clone, so we can't clone before consuming. Instead, someone trying to implement Seek would need to save the key and nonce themselves, and then reconstruct the Decryptor every time a seek is requested.
There was a problem hiding this comment.
The Encryptor and Decryptor objects are high-level misuse resistant APIs designed to ensure the STREAM is encoded/decoded correctly.
The lower-level StreamPrimitive trait is intended for the use cases you're describing.
| stream: S, | ||
|
|
||
| /// Current position in the STREAM. | ||
| position: S::Counter, |
There was a problem hiding this comment.
There is currently no way to set position manually to a specific chunk, which completely prevents Decryptor from being used in a seeking context.
str4d
left a comment
There was a problem hiding this comment.
I tried migrating the age crate to this (which uses ChaCha20Poly1305 with a nonce structured as an 11-byte big-endian counter and 1-byte last block flag), and encountered a few issues.
|
@str4d I think for something like They could potentially include seeking behavior similar to SyncStreamCipherSeek, but if you are intending to do anything in parallel the fact they keep state at all seems problematic and I think you should just use |
|
As I noted in Discord, If we could move (what is currently) |
|
@str4d it might make sense to spike things out in another crate initially, then circle back on upstreaming the parts that make sense into |
Implementation of the STREAM construction as described in the paper "Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance": https://eprint.iacr.org/2015/189.pdf The implementation is generic over AEAD ciphers and is factored into a low-level `StreamPrimitive` trait (permitting different "flavors" of STREAM) as well as higher-level stateful `Encryptor` and `Decryptor` objects which are generic over `StreamPrimitive` types. Includes two concrete implementations of `StreamPrimitive`: - `StreamBE32`: the original version of stream described in the paper, with a nonce in the form: `prefix || counter || last_block`, where `counter` is a 32-bit big endian-encoded integer, and `last_block` is a 1-byte flag. - `StreamLE31`: uses a 31-bit counter and 1-bit last block flag, packed into the last 4 bytes of the nonce as a little endian integer. Using little endian provides better performance on commonly used CPU architectures, and using a 1-bit last block flag ensures the user-facing STREAM nonce is even numbered in terms of bytes (e.g. for a 96-bit nonce it'd be 64-bits or 8-bytes instead of a 7-byte nonce using the construction described in the paper) and also avoids wasting bits.
|
Added a I'm wondering if we might reduce That would reduce duplication of code between |
|
I'm going to go ahead and land this as I think a I plan on submitting a follow-up PR to simplify the API as described above. I'm also not in a rush to cut another release of |
Implementation of the STREAM construction as described in the paper "Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance":
https://eprint.iacr.org/2015/189.pdf
The implementation is generic over AEAD ciphers and is factored into a low-level
StreamPrimitivetrait (permitting different "flavors" of STREAM) as well as higher-level statefulEncryptorandDecryptorobjects which are generic overStreamPrimitivetypes.Includes one concrete implementation of STREAM:
StreamLE31, which uses a 31-bit counter and 1-bit last block flag. Note that this implementation differs slightly from the one described in the paper, which uses a 1-byte last block flag.Using little endian provides better performance on commonly used CPU architectures, and using a 1-bit last block flag ensures the user-facing STREAM nonce is even numbered in terms of bytes (e.g. for a 96-bit nonce it'd be 64-bits or 8-bytes instead of a 7-byte nonce using the construction described in the paper) and also avoids wasting bits.
It would probably make sense to provide a concrete implementation of STREAM as described in the paper as well, especially for compatibility with existing deployments of this construction, however I wanted to both make sure we provide a useful deployed STREAM variant as such, and also wanted to keep the PR smaller for initial review.