Skip to content

Commit

Permalink
ssh-cipher: make ChaCha20Poly1305 public
Browse files Browse the repository at this point in the history
Directly exposes the `ChaCha20Poly1305` type implementing the
`[email protected]` variant (which is different from the
NaCl/libsodium "djb" variant as well as the IETF variant of
ChaCha20Poly1305).

Also improves documentation to help clarify its nature.
  • Loading branch information
tarcieri committed Jul 29, 2024
1 parent 97b31da commit 0d46c41
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 11 deletions.
28 changes: 20 additions & 8 deletions ssh-cipher/src/chacha20poly1305.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
//! OpenSSH variant of ChaCha20Poly1305: `[email protected]`
//!
//! Differences from ChaCha20Poly1305 as described in RFC8439:
//! - The input of Poly1305 is not padded
//! - The lengths of ciphertext and AAD are not authenticated using Poly1305
//!
//! [PROTOCOL.chacha20poly1305]: https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD
//! OpenSSH variant of ChaCha20Poly1305.

use crate::{Error, Nonce, Result, Tag};
use chacha20::{ChaCha20, Key};
use cipher::{KeyInit, KeyIvInit, StreamCipher, StreamCipherSeek};
use poly1305::Poly1305;
use subtle::ConstantTimeEq;

pub(crate) struct ChaCha20Poly1305 {
/// OpenSSH variant of ChaCha20Poly1305: `[email protected]`
/// as described in [PROTOCOL.chacha20poly1305].
///
/// Differences from ChaCha20Poly1305-IETF as described in [RFC8439]:
/// - The input of Poly1305 is not padded.
/// - AAD is unsupported.
/// - The lengths of ciphertext (and AAD) are not authenticated using Poly1305.
///
/// [PROTOCOL.chacha20poly1305]: https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD
/// [RFC8439]: https://datatracker.ietf.org/doc/html/rfc8439
pub struct ChaCha20Poly1305 {
cipher: ChaCha20,
mac: Poly1305,
}
Expand All @@ -36,12 +40,20 @@ impl ChaCha20Poly1305 {
Ok(Self { cipher, mac })
}

/// Encrypt the provided `buffer` in-place, returning the Poly1305 authentication tag.
#[inline]
pub fn encrypt(mut self, buffer: &mut [u8]) -> Tag {
self.cipher.apply_keystream(buffer);
self.mac.compute_unpadded(buffer).into()
}

/// Decrypt the provided `buffer` in-place, verifying it against the provided Poly1305
/// authentication `tag`.
///
/// In the event tag verification fails, [`Error::Crypto`] is returned, and `buffer` is not
/// modified.
///
/// Upon success, `Ok(())` is returned and `buffer` is rewritten with the decrypted plaintext.
#[inline]
pub fn decrypt(mut self, buffer: &mut [u8], tag: Tag) -> Result<()> {
let expected_tag = self.mac.compute_unpadded(buffer);
Expand Down
6 changes: 3 additions & 3 deletions ssh-cipher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ mod encryptor;

pub use crate::error::{Error, Result};

#[cfg(feature = "chacha20poly1305")]
pub use crate::chacha20poly1305::ChaCha20Poly1305;

#[cfg(any(feature = "aes-cbc", feature = "aes-ctr", feature = "tdes"))]
pub use crate::{decryptor::Decryptor, encryptor::Encryptor};

Expand All @@ -44,9 +47,6 @@ use encoding::{Label, LabelError};
#[cfg(feature = "aes-gcm")]
use aes_gcm::{aead::AeadInPlace, Aes128Gcm, Aes256Gcm};

#[cfg(feature = "chacha20poly1305")]
use crate::chacha20poly1305::ChaCha20Poly1305;

#[cfg(feature = "aes-gcm")]
use cipher::KeyInit;

Expand Down

0 comments on commit 0d46c41

Please sign in to comment.