Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 82 additions & 41 deletions chacha20/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,18 @@
[![Project Chat][chat-image]][chat-link]
[![HAZMAT][hazmat-image]][hazmat-link]

Pure Rust implementation of the [ChaCha20 Stream Cipher][1].
Implementation of the [ChaCha] family of stream ciphers.

<img src="https://raw.githubusercontent.com/RustCrypto/meta/master/img/stream-ciphers/chacha20.png" width="300px">
ChaCha improves upon the previous [Salsa] family of stream ciphers
with increased per-round diffusion at no cost to performance.

## About
This crate also contains an implementation of the [XChaCha] family of stream ciphers
with an extended 192-bit (24-byte) nonce, gated under the `xchacha` Cargo feature,
and "legacy" (a.k.a "djb") variant with 64-bit nonce, gated under the `legacy` crate feature.

[ChaCha20][1] is a [stream cipher][2] which is designed to support
high-performance software implementations.

It improves upon the previous [Salsa20][3] stream cipher with increased
per-round diffusion at no cost to performance.

This crate also contains an implementation of [XChaCha20][4]: a variant
of ChaCha20 with an extended 192-bit (24-byte) nonce, gated under the
`chacha20` Cargo feature (on-by-default).

## Implementations

This crate contains the following implementations of ChaCha20, all of which
work on stable Rust with the following `RUSTFLAGS`:

- `x86` / `x86_64`
- `avx2`: (~1.4cpb) `-Ctarget-cpu=haswell -Ctarget-feature=+avx2`
- `sse2`: (~1.6cpb) `-Ctarget-feature=+sse2` (on by default on x86 CPUs)
- `avx512`: `-Ctarget-feature=+avx512f,+avx512vl --cfg chacha20_avx512` requires Rust 1.89+
- `aarch64`
- `neon` (~2-3x faster than `soft`) requires the `neon` feature enabled
- Portable
- `soft`: (~5 cpb on x86/x86_64)

NOTE: cpb = cycles per byte (smaller is better)
**WARNING:** This implementation internally uses 32-bit counter,
while the original "legacy" variant implementation uses 64-bit counter.
In other words, it does not allow encryption of more than 256 GiB of data.

## Security

Expand All @@ -48,19 +29,80 @@ This crate does not ensure ciphertexts are authentic (i.e. by using a MAC to
verify ciphertext integrity), which can lead to serious vulnerabilities
if used incorrectly!

To avoid this, use an [AEAD][5] mode based on ChaCha20, i.e. [ChaCha20Poly1305][6].
See the [RustCrypto/AEADs][7] repository for more information.
To avoid this, use an [AEAD] mode based on ChaCha20, e.g. [`chacha20poly1305`].
See the [RustCrypto/AEADs] repository for more information.

USE AT YOUR OWN RISK!

### Notes

This crate has received one [security audit by NCC Group][8], with no significant
findings. We would like to thank [MobileCoin][9] for funding the audit.
This crate has received one [security audit by NCC Group][NCC-AUDIT], with no significant
findings. We would like to thank [MobileCoin] for funding the audit.

All implementations contained in the crate (along with the underlying ChaCha20
stream cipher itself) are designed to execute in constant time.

## Examples

```rust
// This example requires `cipher` crate feature
#[cfg(feature = "cipher")] {

use chacha20::ChaCha20;
use chacha20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
use hex_literal::hex;

let key = [0x42; 32];
let nonce = [0x24; 12];
let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F");
let ciphertext = hex!("e405626e 4f1236b3 670ee428 332ea20e");

// Key and IV must be references to the `Array` type.
// Here we use the `Into` trait to convert arrays into it.
let mut cipher = ChaCha20::new(&key.into(), &nonce.into());

let mut buffer = plaintext;

// apply keystream (encrypt)
cipher.apply_keystream(&mut buffer);
assert_eq!(buffer, ciphertext);

let ciphertext = buffer;

// ChaCha ciphers support seeking
cipher.seek(0u32);

// decrypt ciphertext by applying keystream again
cipher.apply_keystream(&mut buffer);
assert_eq!(buffer, plaintext);

// stream ciphers can be used with streaming messages
cipher.seek(0u32);
for chunk in buffer.chunks_mut(3) {
cipher.apply_keystream(chunk);
}
assert_eq!(buffer, ciphertext);
}
```

## Configuration Flags

You can modify crate using the following configuration flags:

- `chacha20_backend="avx2"`: force AVX2 backend on x86/x86_64 targets.
Requires enabled AVX2 target feature. Ignored on non-x86(_64) targets.
- `chacha20_backend="avx512"`: force AVX-512 backend on x86/x86_64 targets.
Requires enabled AVX-512 target feature (MSRV 1.89). Ignored on non-x86(_64) targets.
- `chacha20_backend="soft"`: force software backend.
- `chacha20_backend="sse2"`: force SSE2 backend on x86/x86_64 targets.
Requires enabled SSE2 target feature. Ignored on non-x86(-64) targets.

To use the MSRV 1.89 AVX-512 support with autodetection, you must enable it using
`chacha20_avx512` configuration flag.

The flags can be enabled using `RUSTFLAGS` environmental variable
(e.g. `RUSTFLAGS='--cfg chacha20_backend="avx2"'`) or by modifying `.cargo/config.toml`.

## License

Licensed under either of:
Expand Down Expand Up @@ -93,12 +135,11 @@ dual licensed as above, without any additional terms or conditions.

[//]: # (footnotes)

[1]: https://en.wikipedia.org/wiki/Salsa20#ChaCha_variant
[2]: https://en.wikipedia.org/wiki/Stream_cipher
[3]: https://en.wikipedia.org/wiki/Salsa20
[4]: https://tools.ietf.org/html/draft-arciszewski-xchacha-02
[5]: https://en.wikipedia.org/wiki/Authenticated_encryption
[6]: https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305
[7]: https://github.com/RustCrypto/AEADs
[8]: https://web.archive.org/web/20240108154854/https://research.nccgroup.com/wp-content/uploads/2020/02/NCC_Group_MobileCoin_RustCrypto_AESGCM_ChaCha20Poly1305_Implementation_Review_2020-02-12_v1.0.pdf
[9]: https://www.mobilecoin.com/
[ChaCha]: https://en.wikipedia.org/wiki/Salsa20#ChaCha_variant
[Salsa]: https://en.wikipedia.org/wiki/Salsa20
[XChaCha]: https://tools.ietf.org/html/draft-arciszewski-xchacha-02
[AEAD]: https://en.wikipedia.org/wiki/Authenticated_encryption
[`chacha20poly1305`]: https://docs.rs/chacha20poly1305
[RustCrypto/AEADs]: https://github.com/RustCrypto/AEADs
[NCC-AUDIT]: https://web.archive.org/web/20240108154854/https://research.nccgroup.com/wp-content/uploads/2020/02/NCC_Group_MobileCoin_RustCrypto_AESGCM_ChaCha20Poly1305_Implementation_Review_2020-02-12_v1.0.pdf
[MobileCoin]: https://www.mobilecoin.com/
88 changes: 1 addition & 87 deletions chacha20/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,96 +1,10 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]

//! # Usage
//!
//! Cipher functionality is accessed using traits from re-exported [`cipher`] crate, or as a set
//! of random number generator types ending in `*Rng` which implement traits from the [`rand_core`]
//! crate.
//!
//! This crate contains the following variants of the ChaCha20 core algorithm:
//!
//! - [`ChaCha20`]: standard IETF variant with 96-bit nonce
//! - [`ChaCha8`] / [`ChaCha12`]: reduced round variants of ChaCha20
//! - [`XChaCha20`]: 192-bit extended nonce variant
//! - [`XChaCha8`] / [`XChaCha12`]: reduced round variants of XChaCha20
//! - [`ChaCha20Legacy`]: "djb" variant with 64-bit nonce.
//! **WARNING:** This implementation internally uses 32-bit counter,
//! while the original implementation uses 64-bit counter. In other words,
//! it does not allow encryption of more than 256 GiB of data.
//!
//! ## Example
#![cfg_attr(feature = "cipher", doc = " ```")]
#![cfg_attr(not(feature = "cipher"), doc = " ```ignore")]
//! use chacha20::ChaCha20;
//! // Import relevant traits
//! use chacha20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
//! use hex_literal::hex;
//!
//! let key = [0x42; 32];
//! let nonce = [0x24; 12];
//! let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F");
//! let ciphertext = hex!("e405626e 4f1236b3 670ee428 332ea20e");
//!
//! // Key and IV must be references to the `Array` type.
//! // Here we use the `Into` trait to convert arrays into it.
//! let mut cipher = ChaCha20::new(&key.into(), &nonce.into());
//!
//! let mut buffer = plaintext;
//!
//! // apply keystream (encrypt)
//! cipher.apply_keystream(&mut buffer);
//! assert_eq!(buffer, ciphertext);
//!
//! let ciphertext = buffer;
//!
//! // ChaCha ciphers support seeking
//! cipher.seek(0u32);
//!
//! // decrypt ciphertext by applying keystream again
//! cipher.apply_keystream(&mut buffer);
//! assert_eq!(buffer, plaintext);
//!
//! // stream ciphers can be used with streaming messages
//! cipher.seek(0u32);
//! for chunk in buffer.chunks_mut(3) {
//! cipher.apply_keystream(chunk);
//! }
//! assert_eq!(buffer, ciphertext);
//! ```
//!
//! # Configuration Flags
//!
//! You can modify crate using the following configuration flags:
//!
//! - `chacha20_backend="avx2"`: force AVX2 backend on x86/x86_64 targets.
//! Requires enabled AVX2 target feature. Ignored on non-x86(_64) targets.
//! - `chacha20_backend="avx512": force AVX-512 backend on x86/x86_64 targets.
//! Requires enabled AVX-512 target feature (MSRV 1.89). Ignored on non-x86(_64) targets.
//! - `chacha20_backend="soft"`: force software backend.
//! - `chacha20_backend="sse2"`: force SSE2 backend on x86/x86_64 targets.
//! Requires enabled SSE2 target feature. Ignored on non-x86(-64) targets.
//!
//! The flags can be enabled using `RUSTFLAGS` environmental variable
//! (e.g. `RUSTFLAGS='--cfg chacha20_backend="avx2"'`) or by modifying `.cargo/config.toml`:
//!
//! ```toml
//! # In .cargo/config.toml
//! [build]
//! rustflags = ['--cfg', 'chacha20_backend="avx2"']
//! ```
//!
//! ## AVX-512 support
//!
//! To use the MSRV 1.89 AVX-512 support, you must enable it using: `--cfg chacha20_avx512`.
//!
//! [ChaCha]: https://tools.ietf.org/html/rfc8439
//! [Salsa]: https://en.wikipedia.org/wiki/Salsa20
//! [`chacha20poly1305`]: https://docs.rs/chacha20poly1305
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod variants;

Expand Down
41 changes: 39 additions & 2 deletions hc-256/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Project Chat][chat-image]][chat-link]
[![HAZMAT][hazmat-image]][hazmat-link]

Pure Rust implementation of the [HC-256 Stream Cipher][1].
Implementation of the [HC-256] stream cipher.

## ⚠️ Security Warning: [Hazmat!][hazmat-link]

Expand All @@ -22,6 +22,43 @@ architectures.

USE AT YOUR OWN RISK!

# Examples

```rust
use hc_256::Hc256;
use hc_256::cipher::{KeyIvInit, StreamCipher};
use hex_literal::hex;

let key = [0x42; 32];
let nonce = [0x24; 32];
let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F");
let ciphertext = hex!("ca982177 325cd40e bc208045 066c420f");

// Key and IV must be references to the `Array` type.
// Here we use the `Into` trait to convert arrays into it.
let mut cipher = Hc256::new(&key.into(), &nonce.into());

let mut buffer = plaintext;

// apply keystream (encrypt)
cipher.apply_keystream(&mut buffer);
assert_eq!(buffer, ciphertext);

let ciphertext = buffer;

// decrypt ciphertext by applying keystream again
let mut cipher = Hc256::new(&key.into(), &nonce.into());
cipher.apply_keystream(&mut buffer);
assert_eq!(buffer, plaintext);

// stream ciphers can be used with streaming messages
let mut cipher = Hc256::new(&key.into(), &nonce.into());
for chunk in buffer.chunks_mut(3) {
cipher.apply_keystream(chunk);
}
assert_eq!(buffer, ciphertext);
```

## License

Licensed under either of:
Expand Down Expand Up @@ -54,4 +91,4 @@ dual licensed as above, without any additional terms or conditions.

[//]: # (footnotes)

[1]: https://en.wikipedia.org/wiki/HC-256
[HC-256]: https://en.wikipedia.org/wiki/HC-256
53 changes: 2 additions & 51 deletions hc-256/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,10 @@
//! Implementation of the [HC-256] stream cipher.
//!
//! Cipher functionality is accessed using traits from re-exported [`cipher`] crate.
//!
//! # ⚠️ Security Warning: Hazmat!
//!
//! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity
//! is not verified, which can lead to serious vulnerabilities!
//!
//! USE AT YOUR OWN RISK!
//!
//! # Example
//! ```
//! use hc_256::Hc256;
//! // Import relevant traits
//! use hc_256::cipher::{KeyIvInit, StreamCipher};
//! use hex_literal::hex;
//!
//! let key = [0x42; 32];
//! let nonce = [0x24; 32];
//! let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F");
//! let ciphertext = hex!("ca982177 325cd40e bc208045 066c420f");
//!
//! // Key and IV must be references to the `Array` type.
//! // Here we use the `Into` trait to convert arrays into it.
//! let mut cipher = Hc256::new(&key.into(), &nonce.into());
//!
//! let mut buffer = plaintext;
//!
//! // apply keystream (encrypt)
//! cipher.apply_keystream(&mut buffer);
//! assert_eq!(buffer, ciphertext);
//!
//! let ciphertext = buffer;
//!
//! // decrypt ciphertext by applying keystream again
//! let mut cipher = Hc256::new(&key.into(), &nonce.into());
//! cipher.apply_keystream(&mut buffer);
//! assert_eq!(buffer, plaintext);
//!
//! // stream ciphers can be used with streaming messages
//! let mut cipher = Hc256::new(&key.into(), &nonce.into());
//! for chunk in buffer.chunks_mut(3) {
//! cipher.apply_keystream(chunk);
//! }
//! assert_eq!(buffer, ciphertext);
//! ```
//!
//! [HC-256]: https://en.wikipedia.org/wiki/HC-256

#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]

Expand Down
Loading
Loading