diff --git a/chacha20/README.md b/chacha20/README.md index 78a479aa..11359ffb 100644 --- a/chacha20/README.md +++ b/chacha20/README.md @@ -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. - +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 @@ -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: @@ -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/ diff --git a/chacha20/src/lib.rs b/chacha20/src/lib.rs index f3e47ae0..bb867e5f 100644 --- a/chacha20/src/lib.rs +++ b/chacha20/src/lib.rs @@ -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; diff --git a/hc-256/README.md b/hc-256/README.md index 290c451c..046f13c5 100644 --- a/hc-256/README.md +++ b/hc-256/README.md @@ -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] @@ -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: @@ -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 diff --git a/hc-256/src/lib.rs b/hc-256/src/lib.rs index 2365a90e..3cf09c20 100644 --- a/hc-256/src/lib.rs +++ b/hc-256/src/lib.rs @@ -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)] diff --git a/rabbit/README.md b/rabbit/README.md index 27a2c906..205776cf 100644 --- a/rabbit/README.md +++ b/rabbit/README.md @@ -8,7 +8,7 @@ [![Project Chat][chat-image]][chat-link] [![HAZMAT][hazmat-image]][hazmat-link] -Rust implementation of the [Rabbit Stream Cipher Algorithm (RFC 4503)][1]. +Implementation of the [Rabbit] stream cipher ([RFC 4503]). ## ⚠️ Security Warning: [Hazmat!][hazmat-link] @@ -22,6 +22,44 @@ architectures. **USE AT YOUR OWN RISK!** + +## Examples + +```rust +use rabbit::Rabbit; +use rabbit::cipher::{KeyIvInit, StreamCipher}; +use hex_literal::hex; + +let key = [0x42; 16]; +let nonce = [0x24; 8]; +let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F"); +let ciphertext = hex!("10298496 ceda18ee 0e257cbb 1ab43bcc"); + +// Key and IV must be references to the `Array` type. +// Here we use the `Into` trait to convert arrays into it. +let mut cipher = Rabbit::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 = Rabbit::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 = Rabbit::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: @@ -54,4 +92,5 @@ dual licensed as above, without any additional terms or conditions. [//]: # (footnotes) -[1]: https://tools.ietf.org/html/rfc4503 +[Rabbit]: https://en.wikipedia.org/wiki/Rabbit_(cipher) +[RFC 4503]: https://tools.ietf.org/html/rfc4503 diff --git a/rabbit/src/lib.rs b/rabbit/src/lib.rs index c92fe04b..5614ee6c 100644 --- a/rabbit/src/lib.rs +++ b/rabbit/src/lib.rs @@ -1,59 +1,10 @@ -//! Implementation of the [Rabbit] 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 rabbit::Rabbit; -//! // Import relevant traits -//! use rabbit::cipher::{KeyIvInit, StreamCipher}; -//! use hex_literal::hex; -//! -//! let key = [0x42; 16]; -//! let nonce = [0x24; 8]; -//! let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F"); -//! let ciphertext = hex!("10298496 ceda18ee 0e257cbb 1ab43bcc"); -//! -//! // Key and IV must be references to the `Array` type. -//! // Here we use the `Into` trait to convert arrays into it. -//! let mut cipher = Rabbit::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 = Rabbit::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 = Rabbit::new(&key.into(), &nonce.into()); -//! for chunk in buffer.chunks_mut(3) { -//! cipher.apply_keystream(chunk); -//! } -//! assert_eq!(buffer, ciphertext); -//! ``` -//! -//! [Rabbit]: https://tools.ietf.org/html/rfc4503#section-2.3 - #![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))] #![deny(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] diff --git a/rc4/README.md b/rc4/README.md index 26af2e47..8b138d20 100644 --- a/rc4/README.md +++ b/rc4/README.md @@ -24,6 +24,33 @@ relied on for security/confidentiality. **USE AT YOUR OWN RISK!** +## Examples + +```rust +use hex_literal::hex; +use rc4::{consts::*, KeyInit, StreamCipher}; +use rc4::{Key, Rc4}; + +let mut rc4 = Rc4::::new(b"Key".into()); +let mut data = b"Plaintext".to_vec(); +rc4.apply_keystream(&mut data); +assert_eq!(data, [0xBB, 0xF3, 0x16, 0xE8, 0xD9, 0x40, 0xAF, 0x0A, 0xD3]); + +let mut rc4 = Rc4::::new(b"Wiki".into()); +let mut data = b"pedia".to_vec(); +rc4.apply_keystream(&mut data); +assert_eq!(data, [0x10, 0x21, 0xBF, 0x04, 0x20]); + +let key = Key::::from_slice(b"Secret"); +let mut rc4 = Rc4::<_>::new(key); +let mut data = b"Attack at dawn".to_vec(); +rc4.apply_keystream(&mut data); +assert_eq!( + data, + [0x45, 0xA0, 0x1F, 0x64, 0x5F, 0xC3, 0x5B, 0x38, 0x35, 0x52, 0x54, 0x4B, 0x9B, 0xF5] +); +``` + ## License Licensed under either of: diff --git a/rc4/src/lib.rs b/rc4/src/lib.rs index f18bde85..bc79125e 100644 --- a/rc4/src/lib.rs +++ b/rc4/src/lib.rs @@ -1,40 +1,13 @@ #![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)] -//! # Usage -//! -//! ```rust -//! use hex_literal::hex; -//! use rc4::{consts::*, KeyInit, StreamCipher}; -//! use rc4::{Key, Rc4}; -//! -//! let mut rc4 = Rc4::::new(b"Key".into()); -//! let mut data = b"Plaintext".to_vec(); -//! rc4.apply_keystream(&mut data); -//! assert_eq!(data, [0xBB, 0xF3, 0x16, 0xE8, 0xD9, 0x40, 0xAF, 0x0A, 0xD3]); -//! -//! let mut rc4 = Rc4::::new(b"Wiki".into()); -//! let mut data = b"pedia".to_vec(); -//! rc4.apply_keystream(&mut data); -//! assert_eq!(data, [0x10, 0x21, 0xBF, 0x04, 0x20]); -//! -//! let key = Key::::from_slice(b"Secret"); -//! let mut rc4 = Rc4::<_>::new(key); -//! let mut data = b"Attack at dawn".to_vec(); -//! rc4.apply_keystream(&mut data); -//! assert_eq!( -//! data, -//! [0x45, 0xA0, 0x1F, 0x64, 0x5F, 0xC3, 0x5B, 0x38, 0x35, 0x52, 0x54, 0x4B, 0x9B, 0xF5] -//! ); -//! ``` - pub use cipher::{self, KeyInit, StreamCipher, consts}; use cipher::{ diff --git a/salsa20/README.md b/salsa20/README.md index a4ae28c3..ebbf5b17 100644 --- a/salsa20/README.md +++ b/salsa20/README.md @@ -8,18 +8,8 @@ [![Project Chat][chat-image]][chat-link] [![HAZMAT][hazmat-image]][hazmat-link] -Pure Rust implementation of the [Salsa20 Stream Cipher][1]. - - - -## About - -[Salsa20][1] is a [stream cipher][2] which is designed to support -high-performance software implementations. - -This crate also contains an implementation of [XSalsa20][3]: a variant -of Salsa20 with an extended 192-bit (24-byte) nonce, gated under the -`xsalsa20` Cargo feature (on-by-default). +Implementation of the [Salsa] family of stream ciphers, including the [XSalsa] variants with +an extended 192-bit (24-byte) nonce. ## ⚠️ Security Warning: [Hazmat!][hazmat-link] @@ -33,6 +23,45 @@ architectures. USE AT YOUR OWN RISK! +# Examples + +```rust +use salsa20::Salsa20; +use salsa20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; +use hex_literal::hex; + +let key = [0x42; 32]; +let nonce = [0x24; 8]; +let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F"); +let ciphertext = hex!("85843cc5 d58cce7b 5dd3dd04 fa005ded"); + +// Key and IV must be references to the `Array` type. +// Here we use the `Into` trait to convert arrays into it. +let mut cipher = Salsa20::new(&key.into(), &nonce.into()); + +let mut buffer = plaintext; + +// apply keystream (encrypt) +cipher.apply_keystream(&mut buffer); +assert_eq!(buffer, ciphertext); + +let ciphertext = buffer; + +// Salsa 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); +``` + ## License Licensed under either of: @@ -65,7 +94,5 @@ dual licensed as above, without any additional terms or conditions. [//]: # (footnotes) -[1]: https://en.wikipedia.org/wiki/Salsa20 -[2]: https://en.wikipedia.org/wiki/Stream_cipher -[3]: https://cr.yp.to/snuffle/xsalsa-20081128.pdf -[4]: https://github.com/RustCrypto/AEADs/tree/master/xsalsa20poly1305 +[Salsa]: https://en.wikipedia.org/wiki/Salsa20 +[XSalsa]: https://cr.yp.to/snuffle/xsalsa-20081128.pdf diff --git a/salsa20/src/lib.rs b/salsa20/src/lib.rs index 856afc82..e794b593 100644 --- a/salsa20/src/lib.rs +++ b/salsa20/src/lib.rs @@ -1,78 +1,12 @@ -//! Implementation of the [Salsa] family of stream ciphers. -//! -//! 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! -//! -//! # Diagram -//! -//! This diagram illustrates the Salsa quarter round function. -//! Each round consists of four quarter-rounds: -//! -//! -//! -//! Legend: -//! -//! - ⊞ add -//! - ‹‹‹ rotate -//! - ⊕ xor -//! -//! # Example -//! ``` -//! use salsa20::Salsa20; -//! // Import relevant traits -//! use salsa20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; -//! use hex_literal::hex; -//! -//! let key = [0x42; 32]; -//! let nonce = [0x24; 8]; -//! let plaintext = hex!("00010203 04050607 08090A0B 0C0D0E0F"); -//! let ciphertext = hex!("85843cc5 d58cce7b 5dd3dd04 fa005ded"); -//! -//! // Key and IV must be references to the `Array` type. -//! // Here we use the `Into` trait to convert arrays into it. -//! let mut cipher = Salsa20::new(&key.into(), &nonce.into()); -//! -//! let mut buffer = plaintext; -//! -//! // apply keystream (encrypt) -//! cipher.apply_keystream(&mut buffer); -//! assert_eq!(buffer, ciphertext); -//! -//! let ciphertext = buffer; -//! -//! // Salsa 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); -//! ``` -//! -//! Salsa20 will run the SSE2 backend in x86(-64) targets for Salsa20/20 variant. -//! Other variants will fallback to the software backend. -//! -//! [Salsa]: https://en.wikipedia.org/wiki/Salsa20 - #![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))] #![warn(missing_docs, rust_2018_idioms, trivial_casts, unused_qualifications)] + pub use cipher; use cipher::{