diff --git a/Cargo.lock b/Cargo.lock index d5e399c6..6755e96e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -# version = 3 [[package]] @@ -17,9 +16,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2333ac5777aaa1beb8589f5374976ae7dc8aa4f09fd21ae3d8662ca97f5247d" +checksum = "495ee669413bfbe9e8cace80f4d3d78e6d8c8d99579f97fb93bde351b185f2d4" dependencies = [ "cfg-if", "cipher", @@ -36,7 +35,7 @@ dependencies = [ "cipher", "ctr", "ghash", - "hex-literal", + "hex-literal 0.2.1", "subtle", "zeroize", ] @@ -66,7 +65,7 @@ dependencies = [ "crypto-mac", "ctr", "dbl", - "hex-literal", + "hex-literal 0.2.1", "pmac", "zeroize", ] @@ -114,7 +113,7 @@ dependencies = [ "aead", "aes", "cipher", - "hex-literal", + "hex-literal 0.2.1", "subtle", ] @@ -242,6 +241,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "deoxys" +version = "0.1.0" +dependencies = [ + "aead", + "aes", + "hex-literal 0.3.1", + "subtle", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -334,6 +344,12 @@ dependencies = [ "proc-macro-hack", ] +[[package]] +name = "hex-literal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" + [[package]] name = "hex-literal-impl" version = "0.2.2" @@ -345,11 +361,12 @@ dependencies = [ [[package]] name = "kuznyechik" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1020a37e326b4033680520bf26d4ec7366f92827e5d2c5620a38511f2fd732c5" +checksum = "0865d64349fd4b3aaf478b279af022717585d95780c038919c60fe042aff30b0" dependencies = [ "cipher", + "opaque-debug", ] [[package]] @@ -364,7 +381,7 @@ version = "0.4.1" dependencies = [ "aead", "cipher", - "hex-literal", + "hex-literal 0.2.1", "kuznyechik", "subtle", ] @@ -510,9 +527,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2", "quote", @@ -539,9 +556,9 @@ checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" diff --git a/Cargo.toml b/Cargo.toml index 6cb65aa3..1074873d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "ccm", "chacha20poly1305", "crypto_box", + "deoxys", "eax", "mgm", "xsalsa20poly1305" diff --git a/README.md b/README.md index a0d3726f..35d4bea8 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ crate. | [`aes-gcm`] | [AES-GCM] | [![crates.io](https://img.shields.io/crates/v/aes-gcm.svg)](https://crates.io/crates/aes-gcm) | [![Documentation](https://docs.rs/aes-gcm/badge.svg)](https://docs.rs/aes-gcm) | ![aes-gcm](https://github.com/RustCrypto/AEADs/workflows/aes-gcm/badge.svg?branch=master&event=push) | | [`aes-siv`] | [AES-SIV] | [![crates.io](https://img.shields.io/crates/v/aes-siv.svg)](https://crates.io/crates/aes-siv) | [![Documentation](https://docs.rs/aes-siv/badge.svg)](https://docs.rs/aes-siv) | ![aes-siv](https://github.com/RustCrypto/AEADs/workflows/aes-siv/badge.svg?branch=master&event=push) | | [`ccm`] | [CCM] | [![crates.io](https://img.shields.io/crates/v/ccm.svg)](https://crates.io/crates/ccm) | [![Documentation](https://docs.rs/ccm/badge.svg)](https://docs.rs/ccm) | ![ccm](https://github.com/RustCrypto/AEADs/workflows/ccm/badge.svg?branch=master&event=push) | -| [`chacha20poly1305`] | [(X)ChaCha20Poly1305] | [![crates.io](https://img.shields.io/crates/v/chacha20poly1305.svg)](https://crates.io/crates/chacha20poly1305) | [![Documentation](https://docs.rs/chacha20poly1305/badge.svg)](https://docs.rs/chacha20poly1305) | ![chacha20poly1305](https://github.com/RustCrypto/AEADs/workflows/chacha20poly1305/badge.svg?branch=master&event=push) +| [`chacha20poly1305`] | [(X)ChaCha20Poly1305] | [![crates.io](https://img.shields.io/crates/v/chacha20poly1305.svg)](https://crates.io/crates/chacha20poly1305) | [![Documentation](https://docs.rs/chacha20poly1305/badge.svg)](https://docs.rs/chacha20poly1305) | ![chacha20poly1305](https://github.com/RustCrypto/AEADs/workflows/chacha20poly1305/badge.svg?branch=master&event=push) | +| [`deoxys`] | [Deoxys-I/II] | [![crates.io](https://img.shields.io/crates/v/deoxys.svg)](https://crates.io/crates/deoxys) | [![Documentation](https://docs.rs/deoxys/badge.svg)](https://docs.rs/deoxys) | ![deoxys](https://github.com/RustCrypto/AEADs/workflows/deoxys/badge.svg?branch=master&event=push) | | [`crypto_box`] | [Curve25519XSalsa20Poly1305] | [![crates.io](https://img.shields.io/crates/v/crypto_box.svg)](https://crates.io/crates/crypto_box) | [![Documentation](https://docs.rs/crypto_box/badge.svg)](https://docs.rs/crypto_box) | ![crypto_box](https://github.com/RustCrypto/AEADs/workflows/crypto_box/badge.svg?branch=master&event=push) | | [`eax`] | [EAX] | [![crates.io](https://img.shields.io/crates/v/eax.svg)](https://crates.io/crates/eax) | [![Documentation](https://docs.rs/eax/badge.svg)](https://docs.rs/eax) | ![eax](https://github.com/RustCrypto/AEADs/workflows/eax/badge.svg?branch=master&event=push) | | [`mgm`] | [MGM] | [![crates.io](https://img.shields.io/crates/v/mgm.svg)](https://crates.io/crates/mgm) | [![Documentation](https://docs.rs/mgm/badge.svg)](https://docs.rs/mgm) | ![mgm](https://github.com/RustCrypto/AEADs/workflows/mgm/badge.svg?branch=master&event=push) | @@ -72,6 +73,7 @@ dual licensed as above, without any additional terms or conditions. [`aes-siv`]: https://github.com/RustCrypto/AEADs/tree/master/aes-siv [`ccm`]: https://github.com/RustCrypto/AEADs/tree/master/ccm [`chacha20poly1305`]: https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305 +[`deoxys`]: https://github.com/RustCrypto/AEADs/tree/master/deoxys [`crypto_box`]: https://github.com/RustCrypto/AEADs/tree/master/crypto_box [`eax`]: https://github.com/RustCrypto/AEADs/tree/master/eax [`mgm`]: https://github.com/RustCrypto/AEADs/tree/master/mgm @@ -83,6 +85,7 @@ dual licensed as above, without any additional terms or conditions. [AES-GCM-SIV]: https://en.wikipedia.org/wiki/AES-GCM-SIV [AES-SIV]: https://github.com/miscreant/meta/wiki/AES-SIV [CCM]: https://en.wikipedia.org/wiki/CCM_mode +[Deoxys-I/II]: https://sites.google.com/view/deoxyscipher [EAX]: https://en.wikipedia.org/wiki/EAX_mode [MGM]: https://eprint.iacr.org/2019/123.pdf [(X)ChaCha20Poly1305]: https://tools.ietf.org/html/rfc8439 diff --git a/aes-gcm/Cargo.lock b/aes-gcm/Cargo.lock deleted file mode 100644 index 625481c6..00000000 --- a/aes-gcm/Cargo.lock +++ /dev/null @@ -1,320 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aead" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "922b33332f54fc0ad13fa3e514601e8d30fb54e1f3eadc36643f6526db645621" -dependencies = [ - "blobby", - "generic-array", - "heapless", -] - -[[package]] -name = "aes" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2333ac5777aaa1beb8589f5374976ae7dc8aa4f09fd21ae3d8662ca97f5247d" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug", -] - -[[package]] -name = "aes-gcm" -version = "0.9.1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "hex-literal", - "subtle", - "zeroize", -] - -[[package]] -name = "atomic-polyfill" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30302dda7a66f8c55932ebf208f7def840743ff64d495e9ceffcd97c18f11d39" -dependencies = [ - "cortex-m", -] - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "blobby" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc52553543ecb104069b0ff9e0fcc5c739ad16202935528a112d974e8f1a4ee8" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cortex-m" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643a210c1bdc23d0db511e2a576082f4ff4dcae9d0c37f50b431b8f8439d6d6b" -dependencies = [ - "bare-metal", - "bitfield", - "embedded-hal", - "volatile-register", -] - -[[package]] -name = "cpufeatures" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8" -dependencies = [ - "libc", -] - -[[package]] -name = "ctr" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" -dependencies = [ - "cipher", -] - -[[package]] -name = "embedded-hal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db184d3fa27bc7a2344250394c0264144dfe0bc81a4401801dcb964b8dd172ad" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "generic-array" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "ghash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bbd60caa311237d508927dbba7594b483db3ef05faa55172fcf89b1bcda7853" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - -[[package]] -name = "heapless" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ee8a997d259962217f40279f34201fdf06e669bafa69d7c1f4c7ff1893b5f6" -dependencies = [ - "atomic-polyfill", - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "hex-literal" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" -dependencies = [ - "hex-literal-impl", - "proc-macro-hack", -] - -[[package]] -name = "hex-literal-impl" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" -dependencies = [ - "proc-macro-hack", -] - -[[package]] -name = "libc" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.0.0", -] - -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "polyval" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e597450cbf209787f0e6de80bf3795c6b2356a380ee87837b545aded8dbc1823" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "subtle" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" - -[[package]] -name = "typenum" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" - -[[package]] -name = "universal-hash" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" -dependencies = [ - "vcell", -] - -[[package]] -name = "zeroize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 02dc3dba..d364a11d 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -16,6 +16,7 @@ aes = "0.7.0-pre" aes-gcm = { path = "../aes-gcm/" } aes-gcm-siv = { path = "../aes-gcm-siv/" } chacha20poly1305 = { path = "../chacha20poly1305/" } +deoxys = { path = "../deoxys/" } eax = { path = "../eax/" } [[bench]] @@ -33,6 +34,11 @@ name = "chacha20poly1305" path = "src/chacha20poly1305.rs" harness = false +[[bench]] +name = "deoxys" +path = "src/deoxys.rs" +harness = false + [[bench]] name = "eax" path = "src/eax.rs" diff --git a/benches/src/deoxys.rs b/benches/src/deoxys.rs new file mode 100644 index 00000000..9b89f2ff --- /dev/null +++ b/benches/src/deoxys.rs @@ -0,0 +1,63 @@ +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; +use criterion_cycles_per_byte::CyclesPerByte; + +use deoxys::aead::{Aead, NewAead}; +use deoxys::{DeoxysI128, DeoxysI256, DeoxysII128, DeoxysII256}; + +const KB: usize = 1024; + +fn bench(c: &mut Criterion) { + let mut group = c.benchmark_group("deoxys"); + + for size in &[KB, 2 * KB, 4 * KB, 8 * KB, 16 * KB] { + let buf = vec![0u8; *size]; + + group.throughput(Throughput::Bytes(*size as u64)); + + group.bench_function(BenchmarkId::new("encrypt-I-128", size), |b| { + let cipher = DeoxysI128::new(&Default::default()); + b.iter(|| cipher.encrypt(&Default::default(), &*buf)) + }); + group.bench_function(BenchmarkId::new("decrypt-I-128", size), |b| { + let cipher = DeoxysI128::new(&Default::default()); + b.iter(|| cipher.decrypt(&Default::default(), &*buf)) + }); + + group.bench_function(BenchmarkId::new("encrypt-I-256", size), |b| { + let cipher = DeoxysI256::new(&Default::default()); + b.iter(|| cipher.encrypt(&Default::default(), &*buf)) + }); + group.bench_function(BenchmarkId::new("decrypt-I-256", size), |b| { + let cipher = DeoxysI256::new(&Default::default()); + b.iter(|| cipher.decrypt(&Default::default(), &*buf)) + }); + + + group.bench_function(BenchmarkId::new("encrypt-II-128", size), |b| { + let cipher = DeoxysII128::new(&Default::default()); + b.iter(|| cipher.encrypt(&Default::default(), &*buf)) + }); + group.bench_function(BenchmarkId::new("decrypt-II-128", size), |b| { + let cipher = DeoxysII128::new(&Default::default()); + b.iter(|| cipher.decrypt(&Default::default(), &*buf)) + }); + + group.bench_function(BenchmarkId::new("encrypt-II-256", size), |b| { + let cipher = DeoxysII256::new(&Default::default()); + b.iter(|| cipher.encrypt(&Default::default(), &*buf)) + }); + group.bench_function(BenchmarkId::new("decrypt-II-256", size), |b| { + let cipher = DeoxysII256::new(&Default::default()); + b.iter(|| cipher.decrypt(&Default::default(), &*buf)) + }); + } + + group.finish(); +} + +criterion_group!( + name = benches; + config = Criterion::default().with_measurement(CyclesPerByte); + targets = bench +); +criterion_main!(benches); diff --git a/deoxys/Cargo.toml b/deoxys/Cargo.toml new file mode 100644 index 00000000..ea5aac6c --- /dev/null +++ b/deoxys/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "deoxys" +version = "0.1.0" +authors = ["RustCrypto Developers, zer0x64"] +edition = "2018" +license = "Apache-2.0 OR MIT" +readme = "README.md" +documentation = "https://docs.rs/deoxys" +repository = "https://github.com/RustCrypto/AEADs" +keywords = ["aead", "deoxys", "deoxys-i", "deoxys-ii"] +categories = ["cryptography", "no-std"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aead = { version = "0.4", default-features = false } +subtle = "2.4.0" +zeroize = { version = "1", default-features = false } +aes = { version = "0.7.4", features=["hazmat"], default-features = false} + +[dev-dependencies] +aead = { version = "0.4", features = ["dev"], default-features = false } +hex-literal = "0.3.1" + +[features] +default = ["alloc"] +std = ["aead/std", "alloc"] +alloc = ["aead/alloc"] +heapless = ["aead/heapless"] +stream = ["aead/stream"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] diff --git a/deoxys/LICENSE-APACHE b/deoxys/LICENSE-APACHE new file mode 100644 index 00000000..69d3d818 --- /dev/null +++ b/deoxys/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2021 The RustCrypto Project Developers + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/deoxys/LICENSE-MIT b/deoxys/LICENSE-MIT new file mode 100644 index 00000000..c869ada5 --- /dev/null +++ b/deoxys/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2021 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/deoxys/src/deoxys_bc.rs b/deoxys/src/deoxys_bc.rs new file mode 100644 index 00000000..ff974edf --- /dev/null +++ b/deoxys/src/deoxys_bc.rs @@ -0,0 +1,181 @@ +use aead::{ + consts::{U15, U16, U17, U32, U48}, + generic_array::{ArrayLength, GenericArray}, +}; + +use crate::DeoxysBcType; + +const H_PERM: [u8; 16] = [1, 6, 11, 12, 5, 10, 15, 0, 9, 14, 3, 4, 13, 2, 7, 8]; + +macro_rules! gen_rcon { + ($value:expr) => { + [ + 1, 2, 4, 8, $value, $value, $value, $value, 0, 0, 0, 0, 0, 0, 0, 0, + ] + }; +} + +const RCON: [[u8; 16]; 17] = [ + gen_rcon!(0x2f), + gen_rcon!(0x5e), + gen_rcon!(0xbc), + gen_rcon!(0x63), + gen_rcon!(0xc6), + gen_rcon!(0x97), + gen_rcon!(0x35), + gen_rcon!(0x6a), + gen_rcon!(0xd4), + gen_rcon!(0xb3), + gen_rcon!(0x7d), + gen_rcon!(0xfa), + gen_rcon!(0xef), + gen_rcon!(0xc5), + gen_rcon!(0x91), + gen_rcon!(0x39), + gen_rcon!(0x72), +]; + +/// Implementation of the Deoxys-BC256 block cipher +pub struct DeoxysBc256; + +/// Implementation of the Deoxys-BC384 block cipher +pub struct DeoxysBc384; + +pub trait DeoxysBcInternal { + type SubkeysSize: ArrayLength<[u8; 16]>; + type TweakKeySize: ArrayLength; + + fn key_schedule( + tweak: &[u8; 16], + subkeys: &GenericArray<[u8; 16], Self::SubkeysSize>, + ) -> GenericArray<[u8; 16], Self::SubkeysSize> { + let mut subtweakeys: GenericArray<[u8; 16], Self::SubkeysSize> = Default::default(); + let mut tweak = *tweak; + + // First key + for (i, (s, t)) in tweak.iter().zip(subkeys[0].iter()).enumerate() { + subtweakeys[0][i] = s ^ t + } + + // Other keys + for (stk, sk) in subtweakeys[1..].iter_mut().zip(subkeys[1..].iter()) { + h_substitution(&mut tweak); + + for i in 0..16 { + stk[i] = sk[i] ^ tweak[i]; + } + } + + subtweakeys + } +} + +impl DeoxysBcInternal for DeoxysBc256 { + type SubkeysSize = U15; + type TweakKeySize = U32; +} + +impl DeoxysBcType for DeoxysBc256 { + type KeySize = U16; + + fn precompute_subkeys( + key: &GenericArray, + ) -> GenericArray<[u8; 16], Self::SubkeysSize> { + let mut subkeys: GenericArray<[u8; 16], Self::SubkeysSize> = Default::default(); + + let mut tk2 = [0u8; 16]; + + tk2.copy_from_slice(key); + + // First key + let rcon = RCON[0]; + + for i in 0..16 { + subkeys[0][i] = tk2[i] ^ rcon[i]; + } + + // Other keys + for (index, subkey) in subkeys[1..].iter_mut().enumerate() { + h_substitution(&mut tk2); + lfsr2(&mut tk2); + + let rcon = RCON[index + 1]; + + for i in 0..16 { + subkey[i] = tk2[i] ^ rcon[i]; + } + } + + subkeys + } +} + +impl DeoxysBcInternal for DeoxysBc384 { + type SubkeysSize = U17; + type TweakKeySize = U48; +} + +impl DeoxysBcType for DeoxysBc384 { + type KeySize = U32; + + fn precompute_subkeys( + key: &GenericArray, + ) -> GenericArray<[u8; 16], Self::SubkeysSize> { + let mut subkeys: GenericArray<[u8; 16], Self::SubkeysSize> = Default::default(); + + let mut tk3 = [0u8; 16]; + let mut tk2 = [0u8; 16]; + + tk3.copy_from_slice(&key[..16]); + tk2.copy_from_slice(&key[16..]); + + // First key + let rcon = RCON[0]; + + for i in 0..16 { + subkeys[0][i] = tk3[i] ^ tk2[i] ^ rcon[i]; + } + + // Other keys + for (index, subkey) in subkeys[1..].iter_mut().enumerate() { + h_substitution(&mut tk2); + lfsr2(&mut tk2); + h_substitution(&mut tk3); + lfsr3(&mut tk3); + + let rcon = RCON[index + 1]; + + for i in 0..16 { + subkey[i] = tk3[i] ^ tk2[i] ^ rcon[i]; + } + } + + subkeys + } +} + +fn h_substitution(tk: &mut [u8; 16]) { + let mut result = [0u8; 16]; + + for i in 0..16 { + result[i] = tk[H_PERM[i] as usize]; + } + + tk.copy_from_slice(&result); +} + +fn lfsr2(tk: &mut [u8; 16]) { + let mut data = u128::from_ne_bytes(*tk); + data = ((data << 1) & 0xFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE) + | (((data >> 7) ^ (data >> 5)) & 0x01010101010101010101010101010101); + + tk.copy_from_slice(&data.to_ne_bytes()) +} + +fn lfsr3(tk: &mut [u8; 16]) { + let mut data = u128::from_ne_bytes(*tk); + data = ((data >> 1) & 0x7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F) + | (((data << 7) ^ (data << 1)) & 0x80808080808080808080808080808080); + + tk.copy_from_slice(&data.to_ne_bytes()) +} diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs new file mode 100644 index 00000000..21441077 --- /dev/null +++ b/deoxys/src/lib.rs @@ -0,0 +1,311 @@ +//! The [Deoxys][2] [Authenticated Encryption and Associated Data (AEAD)][1]. +//! The Deoxys-II variant has been selected as the first choice for defense in-depth scenario during the [CAESAR competition][3]. +//! +//! ## Security Notes +//! +//! This crate has NOT received any security audit. +//! Although encryption and decryption passes the test vector, there is no guarantee that operations happens in constant time. +//! +//! **USE AT YOUR OWN RISK.** +//! +//! # Usage +//! ``` +//! use deoxys::{DeoxysII256, Key, Nonce}; // Can be `DeoxysI128`, `DeoxysI256`, `DeoxysII128` of `DeoxysII256` +//! use deoxys::aead::{Aead, NewAead}; +//! +//! let key = Key::from_slice(b"an example very very secret key."); +//! let cipher = DeoxysII256::new(key); +//! +//! let nonce = Nonce::from_slice(b"unique nonce123"); // 64-bits for Deoxys-I or 120-bits for Deoxys-II; unique per message +//! +//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref()) +//! .expect("encryption failure!"); // NOTE: handle this error to avoid panics! +//! +//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref()) +//! .expect("decryption failure!"); // NOTE: handle this error to avoid panics! +//! +//! assert_eq!(&plaintext, b"plaintext message"); +//! ``` +//! +//! ## Usage with AAD +//! Deoxys can authenticate additionnal data that is not encrypted alongside with the ciphertext. +//! ``` +//! use deoxys::{DeoxysII256, Key, Nonce}; // Can be `DeoxysI128`, `DeoxysI256`, `DeoxysII128` of `DeoxysII256` +//! use deoxys::aead::{Aead, NewAead, Payload}; +//! +//! let key = Key::from_slice(b"an example very very secret key."); +//! let cipher = DeoxysII256::new(key); +//! +//! let nonce = Nonce::from_slice(b"unique nonce123"); // 64-bits for Deoxys-I or 120-bits for Deoxys-II; unique per message +//! +//!let payload = Payload { +//! msg: &b"this will be encrypted".as_ref(), +//! aad: &b"this will NOT be encrypted, but will be authenticated".as_ref(), +//!}; +//! +//! let ciphertext = cipher.encrypt(nonce, payload) +//! .expect("encryption failure!"); // NOTE: handle this error to avoid panics! +//! +//!let payload = Payload { +//! msg: &ciphertext, +//! aad: &b"this will NOT be encrypted, but will be authenticated".as_ref(), +//!}; +//! +//! let plaintext = cipher.decrypt(nonce, payload) +//! .expect("decryption failure!"); // NOTE: handle this error to avoid panics! +//! +//! assert_eq!(&plaintext, b"this will be encrypted"); +//! ``` +//! +//! ## In-place Usage (eliminates `alloc` requirement) +//! +//! This crate has an optional `alloc` feature which can be disabled in e.g. +//! microcontroller environments that don't have a heap. +//! +//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! methods accept any type that impls the [`aead::Buffer`] trait which +//! contains the plaintext for encryption or ciphertext for decryption. +//! +//! Note that if you enable the `heapless` feature of this crate, +//! you will receive an impl of [`aead::Buffer`] for `heapless::Vec` +//! (re-exported from the [`aead`] crate as [`aead::heapless::Vec`]), +//! which can then be passed as the `buffer` parameter to the in-place encrypt +//! and decrypt methods: +//! +//! ``` +//! # #[cfg(feature = "heapless")] +//! # { +//! use deoxys::{DeoxysII256, Key, Nonce}; // Can be `DeoxysI128`, `DeoxysI256`, `DeoxysII128` of `DeoxysII256` +//! use deoxys::aead::{AeadInPlace, NewAead}; +//! use deoxys::aead::heapless::Vec; +//! +//! let key = Key::from_slice(b"an example very very secret key."); +//! let cipher = DeoxysII256::new(key); +//! +//! let nonce = Nonce::from_slice(b"unique nonce123"); // 64-bits for Deoxys-I or 120-bits for Deoxys-II; unique per message +//! +//! let mut buffer: Vec = Vec::new(); // Buffer needs 16-bytes overhead for tag +//! buffer.extend_from_slice(b"plaintext message"); +//! +//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext +//! cipher.encrypt_in_place(nonce, b"", &mut buffer).expect("encryption failure!"); +//! +//! // `buffer` now contains the message ciphertext +//! assert_ne!(&buffer, b"plaintext message"); +//! +//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext +//! cipher.decrypt_in_place(nonce, b"", &mut buffer).expect("decryption failure!"); +//! assert_eq!(&buffer, b"plaintext message"); +//! # } +//! ``` +//! +//! [1]: https://en.wikipedia.org/wiki/Authenticated_encryption +//! [2]: https://sites.google.com/view/deoxyscipher +//! [3]: https://competitions.cr.yp.to/caesar-submissions.html + +#![no_std] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" +)] +#![warn(missing_docs, rust_2018_idioms)] + +/// Deoxys-BC implementations. +mod deoxys_bc; + +/// Operation modes for Deoxys. +mod modes; + +use core::marker::PhantomData; + +pub use aead; + +use aead::{ + consts::{U0, U16}, + generic_array::{ArrayLength, GenericArray}, + AeadCore, AeadInPlace, Error, NewAead, +}; + +use zeroize::Zeroize; + +/// Deoxys-I with 128-bit keys +pub type DeoxysI128 = Deoxys, deoxys_bc::DeoxysBc256>; + +/// Deoxys-I with 256-bit keys +pub type DeoxysI256 = Deoxys, deoxys_bc::DeoxysBc384>; + +/// Deoxys-II with 128-bit keys +#[allow(clippy::upper_case_acronyms)] +pub type DeoxysII128 = Deoxys, deoxys_bc::DeoxysBc256>; + +/// Deoxys-II with 256-bit keys +#[allow(clippy::upper_case_acronyms)] +pub type DeoxysII256 = Deoxys, deoxys_bc::DeoxysBc384>; + +/// Deoxys keys +pub type Key = GenericArray; + +/// Deoxys nonces +pub type Nonce = GenericArray; + +/// Deoxys tags +pub type Tag = GenericArray; + +/// Deoxys encryption modes. +/// This type contains the public API for a Deoxys mode, like Deoxys-I and Deoxys-II. +pub trait DeoxysMode: modes::DeoxysModeInternal +where + B: DeoxysBcType, +{ + /// The size of the required nonce + type NonceSize: ArrayLength; + + /// Encrypts the data in place with the specified parameters + /// Returns the tag + fn encrypt_in_place( + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8], + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + ) -> [u8; 16]; + + /// Decrypts the data in place with the specified parameters + /// Returns an error if the tag verification fails + fn decrypt_in_place( + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8], + tag: &Tag, + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + ) -> Result<(), aead::Error>; +} + +/// Deoxys-BC trait. +/// This type contains the public API for Deoxys-BC implementations, which varies depending on the size of the key. +pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal { + /// The size of the required tweakey. + type KeySize: ArrayLength; + + /// Precompute the subkeys + fn precompute_subkeys(key: &Key) -> GenericArray<[u8; 16], Self::SubkeysSize>; + + /// Encrypts a block of data in place. + fn encrypt_in_place( + block: &mut [u8; 16], + tweak: &[u8; 16], + subkeys: &GenericArray<[u8; 16], Self::SubkeysSize>, + ) { + let keys = Self::key_schedule(tweak, subkeys); + + for (b, k) in block.iter_mut().zip(keys[0].iter()) { + *b ^= k; + } + + for k in &keys[1..] { + aes::hazmat::cipher_round(block.into(), k.into()); + } + } + + /// Decrypts a block of data in place. + fn decrypt_in_place( + block: &mut [u8; 16], + tweak: &[u8; 16], + subkeys: &GenericArray<[u8; 16], Self::SubkeysSize>, + ) { + let mut keys = Self::key_schedule(tweak, subkeys); + + let r = keys.len(); + + for (b, k) in block.iter_mut().zip(keys[r - 1].iter()) { + *b ^= k; + } + + aes::hazmat::inv_mix_columns(block.into()); + + for k in keys[..r - 1].iter_mut().rev() { + aes::hazmat::inv_mix_columns(k.into()); + aes::hazmat::equiv_inv_cipher_round(block.into(), (&*k).into()); + } + + aes::hazmat::mix_columns(block.into()); + } +} + +/// Generic Deoxys implementation. +/// +/// This type is generic to support multiple Deoxys modes(namely Deoxys-I and Deoxys-II) and key size. +pub struct Deoxys +where + M: DeoxysMode, + B: DeoxysBcType, +{ + subkeys: GenericArray<[u8; 16], B::SubkeysSize>, + mode: PhantomData, +} + +impl NewAead for Deoxys +where + M: DeoxysMode, + B: DeoxysBcType, +{ + type KeySize = B::KeySize; + + fn new(key: &Key) -> Self { + Self { + subkeys: B::precompute_subkeys(key), + mode: PhantomData, + } + } +} + +impl AeadCore for Deoxys +where + M: DeoxysMode, + B: DeoxysBcType, +{ + type NonceSize = M::NonceSize; + type TagSize = U16; + type CiphertextOverhead = U0; +} + +impl AeadInPlace for Deoxys +where + M: DeoxysMode, + B: DeoxysBcType, +{ + fn encrypt_in_place_detached( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + ) -> Result { + Ok(Tag::from(M::encrypt_in_place( + nonce, + associated_data, + buffer, + &self.subkeys, + ))) + } + + fn decrypt_in_place_detached( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + tag: &Tag, + ) -> Result<(), Error> { + M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys) + } +} + +impl Drop for Deoxys +where + M: DeoxysMode, + B: DeoxysBcType, +{ + fn drop(&mut self) { + for s in self.subkeys.iter_mut() { + s.zeroize(); + } + } +} diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs new file mode 100644 index 00000000..098c4dee --- /dev/null +++ b/deoxys/src/modes.rs @@ -0,0 +1,442 @@ +use core::convert::TryFrom; +use core::marker::PhantomData; + +use aead::{ + consts::{U15, U16, U8}, + generic_array::GenericArray, +}; +use subtle::ConstantTimeEq; + +use super::DeoxysBcType; +use super::DeoxysMode; + +const TWEAK_AD: u8 = 0x20; +const TWEAK_AD_LAST: u8 = 0x60; +const TWEAK_M: u8 = 0x00; +const TWEAK_TAG: u8 = 0x10; +const TWEAK_M_LAST: u8 = 0x40; +const TWEAK_CHKSUM: u8 = 0x50; + +/// Implementation of the Deoxys-I mode of operation. +pub struct DeoxysI { + _ptr: PhantomData, +} + +/// Implementation of the Deoxys-II mode of operation. +#[allow(clippy::upper_case_acronyms)] +pub struct DeoxysII { + _ptr: PhantomData, +} + +pub trait DeoxysModeInternal +where + B: DeoxysBcType, +{ + fn compute_ad_tag( + associated_data: &[u8], + tweak: &mut [u8; 16], + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + tag: &mut [u8; 16], + ) { + if !associated_data.is_empty() { + tweak[0] = TWEAK_AD; + + for (index, ad) in associated_data.chunks(16).enumerate() { + // Copy block number + tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); + + if ad.len() == 16 { + let mut block = [0u8; 16]; + block.copy_from_slice(ad); + + B::encrypt_in_place(&mut block, tweak, subkeys); + + for (t, b) in tag.iter_mut().zip(block.iter()) { + *t ^= b; + } + } else { + // Last block + tweak[0] = TWEAK_AD_LAST; + + let mut block = [0u8; 16]; + block[0..ad.len()].copy_from_slice(ad); + + block[ad.len()] = 0x80; + + B::encrypt_in_place(&mut block, tweak, subkeys); + + for (t, b) in tag.iter_mut().zip(block.iter()) { + *t ^= b; + } + } + } + } + } +} + +impl DeoxysModeInternal for DeoxysI where B: DeoxysBcType {} + +impl DeoxysModeInternal for DeoxysII where B: DeoxysBcType {} + +impl DeoxysMode for DeoxysI +where + B: DeoxysBcType, +{ + type NonceSize = U8; + + fn encrypt_in_place( + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8], + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + ) -> [u8; 16] { + let mut tag = [0u8; 16]; + let mut checksum = [0u8; 16]; + let mut tweak = [0u8; 16]; + + // Associated Data + >::compute_ad_tag( + associated_data, + &mut tweak, + subkeys, + &mut tag, + ); + + // Add the nonce to the tweak + tweak[0] = nonce[0] >> 4; + for i in 1..nonce.len() { + tweak[i] = (nonce[i - 1] << 4) | (nonce[i] >> 4); + } + + tweak[8] = nonce[7] << 4; + + // Message authentication and encryption + if !buffer.is_empty() { + tweak[0] = (tweak[0] & 0xf) | TWEAK_M; + + for (index, data) in buffer.chunks_mut(16).enumerate() { + // Copy block number + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + if data.len() == 16 { + for (c, d) in checksum.iter_mut().zip(data.iter()) { + *c ^= d; + } + + B::encrypt_in_place(<&mut [u8; 16]>::try_from(data).unwrap(), &tweak, subkeys); + } else { + // Last block checksum + tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; + + let mut block = [0u8; 16]; + block[0..data.len()].copy_from_slice(data); + + block[data.len()] = 0x80; + + for (c, d) in checksum.iter_mut().zip(block.iter()) { + *c ^= d; + } + + block.fill(0); + + // Last block encryption + B::encrypt_in_place(&mut block, &tweak, subkeys); + + for (d, b) in data.iter_mut().zip(block.iter()) { + *d ^= b; + } + + // Tag computing. + tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; + + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + B::encrypt_in_place(&mut checksum, &tweak, subkeys); + + for (t, c) in tag.iter_mut().zip(checksum.iter()) { + *t ^= c; + } + } + } + } + + if buffer.len() % 16 == 0 { + // Tag computing without last block + tweak[0] = (tweak[0] & 0xf) | TWEAK_TAG; + + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&((buffer.len() / 16) as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + B::encrypt_in_place(&mut checksum, &tweak, subkeys); + + for (t, c) in tag.iter_mut().zip(checksum.iter()) { + *t ^= c; + } + } + + tag + } + + fn decrypt_in_place( + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8], + tag: &GenericArray, + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + ) -> Result<(), aead::Error> { + let mut computed_tag = [0u8; 16]; + let mut checksum = [0u8; 16]; + let mut tweak = [0u8; 16]; + + // Associated Data + >::compute_ad_tag( + associated_data, + &mut tweak, + subkeys, + &mut computed_tag, + ); + + // Add the nonce to the tweak + tweak[0] = nonce[0] >> 4; + for i in 1..nonce.len() { + tweak[i] = (nonce[i - 1] << 4) | (nonce[i] >> 4); + } + + tweak[8] = nonce[7] << 4; + + // Message authentication and encryption + if !buffer.is_empty() { + tweak[0] = (tweak[0] & 0xf) | TWEAK_M; + + for (index, data) in buffer.chunks_mut(16).enumerate() { + // Copy block number + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + if data.len() == 16 { + let data = <&mut [u8; 16]>::try_from(data).unwrap(); + B::decrypt_in_place(data, &tweak, subkeys); + + for (c, d) in checksum.iter_mut().zip(data.iter()) { + *c ^= d; + } + } else { + // Last block checksum + tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; + + let mut block = [0u8; 16]; + B::encrypt_in_place(&mut block, &tweak, subkeys); + + for (d, b) in data.iter_mut().zip(block.iter()) { + *d ^= b; + } + + block.fill(0); + + block[0..data.len()].copy_from_slice(data); + block[data.len()] = 0x80; + + for (c, d) in checksum.iter_mut().zip(block.iter()) { + *c ^= d; + } + + // Tag computing. + tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; + + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + B::encrypt_in_place(&mut checksum, &tweak, subkeys); + + for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { + *t ^= c; + } + } + } + } + + if buffer.len() % 16 == 0 { + // Tag computing without last block + tweak[0] = (tweak[0] & 0xf) | TWEAK_TAG; + + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&((buffer.len() / 16) as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + B::encrypt_in_place(&mut checksum, &tweak, subkeys); + + for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { + *t ^= c; + } + } + + if tag.ct_eq(&computed_tag).into() { + Ok(()) + } else { + Err(aead::Error) + } + } +} + +impl DeoxysII +where + B: DeoxysBcType, +{ + fn authenticate_message( + buffer: &[u8], + tweak: &mut [u8; 16], + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + tag: &mut [u8; 16], + ) { + if !buffer.is_empty() { + tweak[0] = TWEAK_M; + + for (index, data) in buffer.chunks(16).enumerate() { + // Copy block number + tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); + + if data.len() == 16 { + let mut block = [0u8; 16]; + block.copy_from_slice(data); + + B::encrypt_in_place(&mut block, &tweak, subkeys); + + for (t, b) in tag.iter_mut().zip(block.iter()) { + *t ^= b; + } + } else { + // Last block + tweak[0] = TWEAK_M_LAST; + + let mut block = [0u8; 16]; + block[0..data.len()].copy_from_slice(data); + + block[data.len()] = 0x80; + + B::encrypt_in_place(&mut block, &tweak, subkeys); + + for (t, b) in tag.iter_mut().zip(block.iter()) { + *t ^= b; + } + } + } + } + } + + fn encrypt_decrypt_message( + buffer: &mut [u8], + tweak: &mut [u8; 16], + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + tag: &GenericArray, + nonce: &GenericArray, + ) { + if !buffer.is_empty() { + tweak.copy_from_slice(tag); + tweak[0] |= 0x80; + + for (index, data) in buffer.chunks_mut(16).enumerate() { + let index_array = (index as u64).to_be_bytes(); + + // XOR in block numbers + for (t, i) in tweak[8..].iter_mut().zip(&index_array) { + *t ^= i + } + + let mut block = [0u8; 16]; + block[1..].copy_from_slice(nonce); + + B::encrypt_in_place(&mut block, &tweak, subkeys); + + for (t, b) in data.iter_mut().zip(block.iter()) { + *t ^= b; + } + + // XOR out block numbers + for (t, i) in tweak[8..].iter_mut().zip(&index_array) { + *t ^= i + } + } + } + } +} + +impl DeoxysMode for DeoxysII +where + B: DeoxysBcType, +{ + type NonceSize = U15; + + fn encrypt_in_place( + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8], + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + ) -> [u8; 16] { + let mut tag = [0u8; 16]; + let mut tweak = [0u8; 16]; + + // Associated Data + >::compute_ad_tag( + associated_data, + &mut tweak, + subkeys, + &mut tag, + ); + + // Message authentication + Self::authenticate_message(buffer, &mut tweak, subkeys, &mut tag); + + tweak[0] = TWEAK_TAG; + tweak[1..].copy_from_slice(&nonce); + B::encrypt_in_place(&mut tag, &tweak, subkeys); + + // Message encryption + Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, &tag.into(), nonce); + + tag + } + + fn decrypt_in_place( + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8], + tag: &GenericArray, + subkeys: &GenericArray<[u8; 16], B::SubkeysSize>, + ) -> Result<(), aead::Error> { + let mut computed_tag = [0u8; 16]; + let mut tweak = [0u8; 16]; + + // Associated Data + >::compute_ad_tag( + associated_data, + &mut tweak, + subkeys, + &mut computed_tag, + ); + + // Message decryption + Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, tag, nonce); + + tweak.fill(0); + + // Message authentication + Self::authenticate_message(buffer, &mut tweak, subkeys, &mut computed_tag); + + tweak[0] = TWEAK_TAG; + tweak[1..].copy_from_slice(&nonce); + B::encrypt_in_place(&mut computed_tag, &tweak, &subkeys); + + if tag.ct_eq(&computed_tag).into() { + Ok(()) + } else { + Err(aead::Error) + } + } +} diff --git a/deoxys/tests/deoxys_i_128.rs b/deoxys/tests/deoxys_i_128.rs new file mode 100644 index 00000000..2af8646c --- /dev/null +++ b/deoxys/tests/deoxys_i_128.rs @@ -0,0 +1,305 @@ +// Uses the official test vectors. +use deoxys::aead::generic_array::GenericArray; +use deoxys::aead::{Aead, NewAead, Payload}; +use deoxys::DeoxysI128; + +use hex_literal::hex; + +#[test] +fn test_deoxys_i_128_1() { + let plaintext = Vec::new(); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("eec87dce98d29d4078598abd16d550ff"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_i_128_2() { + let plaintext = Vec::new(); + + let aad = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("b507e4aee5f9d7cb9eaebd8370f25a98"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_i_128_3() { + let plaintext = Vec::new(); + + let aad = hex!("0429974cda6665fb9bb4b67d50859258dd69883d50c1eff4bd5962bf4038ad0497"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("fbb9c589e3a54df11e8573d94e6b1000"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_i_128_4() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext = hex!("4bf8c5ecec375b25acabd687aa605f1a8bb296face74f82527d4944dbb11b757"); + + let tag: [u8; 16] = hex!("f32754de1727da4909413815a64e6a69"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_128_5() { + let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext = hex!("cded5a43d3c76e942277c2a1517530ad66037897c985305ede345903ed7585a626"); + + let tag: [u8; 16] = hex!("cbf5faa6b8398c47f4278d2019161776"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_128_6() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: [u8; 32] = + hex!("4bf8c5ecec375b25acabd687aa605f1a8bb296face74f82527d4944dbb11b757"); + + let tag: [u8; 16] = hex!("a1b897f1901e5d98e17936ec1b4d85b3"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_128_7() { + let plaintext = hex!("ee8f487e01f5a101dee6cfd5915d6b5b2c5b6305c782bc7e727bd08096e4208216"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f10"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: [u8; 33] = + hex!("09af865850abc0bce7d35f664a63e41b1475d0385e31a6551edf69ea9f2f8b8ed4"); + + let tag: [u8; 16] = hex!("9326c6c2a0b7f065e591eb9050169603"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_128_8() { + let plaintext = hex!("1857d4edf080e8e2c83aa9e794ebf90d1ea0ccb977287a019aca3daa7af2ad5709d63f05b5b00f4b004b56e802d298ea78afd5d21fd2619248a0897b8e141dc6e1f8b49056d570571a294152a7d7387dbac1ab9ff799dbe0e6c3ae23a14908a3e48eb224824eee8ea4ee3b4ab1bd12a81e3a393ca1344fd9ca5309b116ab2e49e12020f1d6d3bbf608c4e33472c33c6a8d088124c0de4161d94833d75a9bfde908d57d182675c992ad8545198ad2565bac43ce1786e92ec01961c424c1b4c23bc97959ed185193c08e49c6741061e300c94216e505569bcc528f4ced786d1939b4568be157a4b9231b1baf19fc90ee35e97dbfb2965468c2882f1706c6ccec31be7759640c4a2a8a22ecac433eba2223d9685215a8e12bf262f4a72a8bb85ef4181b1d513218a657a24f2903da166f06abd27fbd757ad87473deb844c24e7f7a9295299580bdb1a99acf53a2cc3b1234fb9b0976b6b0ae42605536f46239d1ebd1283adf41f250761d54280e65d79e16200b16d899702530314c6eb5bcb0f1de6d61eaa7ea4c097075ac691754cb1eebbe7ff8cfc39000d9eca154ea37a9d635385b1e132ac3a0d3ffdc362b4333db6b56960cd0d86d02f08ea6e6e1e20a12b7d0b0fe897ab2fcb43f44afb2d42326b2d8d0531e6c9c64aae896caa74299c6d8e10a45360d67373aae7326a1b0484aa42e970510ecb02ca739c38183a43881e6"); + + let aad = hex!("d4e7fc007c9f462d3c2f3ee1c2b92597a838be68930fcc770d3f4a6e8d3f245567c28772c7891c8a605e3f64dd584c264685794c23458c0faf8bbfc5925fe8278eaa1f35322b78c27fcfad42da7f1e9c4ab3aea98c236846690eeb63a26eb60f4cdaef83c3941b57b81529704e404444ed541269428baecd17f4e7f3bde62566b65b578eba069990e8fb10696d94e925ec41b9142de25cd30750cabd41d0a100bebe5eeada44caabff9ede3c251bb57bb48dfb90f7bb9f7d82f131ee20788ff3d9435f8c4f1590cd3cf2dbda143d8a6bcec5e95834578d46561ea209b4d29b1bb74c2c5d1f1bb765cd1d3a1e95984e7f257f4a8a91b3d3d587b43a4023593948d0a58fb1be920f493e5615abd2ecd38f45ed8c440c427a0d2eb76f91adee4c119ac980f28d87585a68039761dbea738a006ec0d9a7dde2ea873c4cf27c8b3565d776473f247b30198e62d4bc722b84d6260bb9e4b8c36dbf1ce6a2b91211bc25d1c0797c5b992920810e78ea6e474f69c9f14550eac375e896a2e5facebcf97bbf5bfdb547ef202222693b4c3120fe8a9559bee514e0b6d9a711a632a7d55398ddd8de66ef3b6f8dd8fa468d27ca455a5fcda20dd12aa426053e9f8454d9598e2d6a528aa4ffe272a4f1341e695dbb1b43bd720ab87ba62290e2d3f78a497a20d1bb0ed72430698b857774d6414ca856019660aba783ff9794d395c82de41a031a"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext= + hex!("f86ecad0d69d2c573cdeee96c90f37ac3c861bd5f4d82ac7396dda102adfa7a94f1daab1e537f03b2a6665eaa8ee057eee403db7ced61adbd77b5c286b7afc5ec23f3f9333773f02d533b0c49ecfc6bcd359bc8a3db6ab16b423efc93e2591e5485a5b21a8cf9312a10d76c840bd1a7e9f5a9954cb636b01ebc8e91a550a0123a50883627d5535f0f6a7960f005d5f340e054ea145dd756e37efd91bc774f93d385da7135372bc51d0401e6499784618da55c31e0b7ad1aa09a3e002f3021ce02926c79741992d9d0252761a7ca6667a56f78e81eaf08cf36d4117d9b2349262d411bef955d7408562ed040e1ea85e3aa3dcf942ea5205edec164dbd6304f90da59b9fb4f8fdeb2c2df473f90494cf09c6af69d191abd7baf97058a3694872d01f63afc225e3796251375a7520a5f755b24b8fd153f362ff09c7e85f02e789ed8cf8adabfcde4c764ebdd703dee39b4e90a91ab0377e0bebc61b2ec9b3c4e3ac7fd893e13c5d0e303e7e625281c988a48dcfd9ee4b698a1c2a82927168e754c99338ea24d24b9bba11cdb4472badc038ab01f250d359c4ade703329062c6260d8fcfda3a6b50b641f9e1e5f2107fd6ca77140dba9048919cab4ea21e4178fde08e7213bf0b730c0415331775039e99f11146b0ebb99a8f5f2d2c4e1767b6fed9c7140dfcf01c793e88889cf34b4ecb044fc740f3d4a2cad1f93455cc36b9a0c6"); + + let tag: [u8; 16] = hex!("5c89d78dbef3d727013b59af859f17da"); + + let encrypted = DeoxysI128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} diff --git a/deoxys/tests/deoxys_i_256.rs b/deoxys/tests/deoxys_i_256.rs new file mode 100644 index 00000000..fe453fdc --- /dev/null +++ b/deoxys/tests/deoxys_i_256.rs @@ -0,0 +1,305 @@ +// Uses the official test vectors. +use deoxys::aead::generic_array::GenericArray; +use deoxys::aead::{Aead, NewAead, Payload}; +use deoxys::DeoxysI256; + +use hex_literal::hex; + +#[test] +fn test_deoxys_i_256_1() { + let plaintext = Vec::new(); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("50b0deaa3c3129d1ea1ef96b7c8db67f"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_i_256_2() { + let plaintext = Vec::new(); + + let aad = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("0e641b45bcffb3c07fa7f7d31edc37d2"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_i_256_3() { + let plaintext = Vec::new(); + + let aad = hex!("52d15808134c3c2e8acbc154299df5c6f86f48ec5dafa5363989b33ba7e0299565"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("f343b91c303180ae2ae4f379022087fa"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_i_256_4() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext = hex!("2c36c041fa3b1436c5153214131d493be9d014689a6a1e93e4a50989f0342941"); + + let tag: [u8; 16] = hex!("ae66f78a3abf1bb7608c6fe949effb57"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_256_5() { + let plaintext = hex!("9d63bc34aceebe70b21768e4f1cfd87bacbcae1e2577b6018de1d72707a42b2569"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext = hex!("fd1ea6745fb5b435751d92be58f5973b84c7589501fcfaff6ce07e2a0e9a72c23e"); + + let tag: [u8; 16] = hex!("e957add57b7c5924d9a22db6fe03cce7"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_256_6() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: [u8; 32] = + hex!("2c36c041fa3b1436c5153214131d493be9d014689a6a1e93e4a50989f0342941"); + + let tag: [u8; 16] = hex!("6da67607bad9cdd34d702325d52abcdd"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_256_7() { + let plaintext = hex!("8a968861ccb4aa1b7744ffff4812e001d1a749df3f66497c1c717681c43987b4eb"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f10"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext: [u8; 33] = + hex!("705f9db5d50ec6ff0ae28557a5640d32b19504833d5fc6de3baf638cef4cda50bc"); + + let tag: [u8; 16] = hex!("88f06bac360362824401c8f1385073a8"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_i_256_8() { + let plaintext = hex!("d18db1b44ad16fe5623ccd73c250c27240daf512e97de1ca770983f262d36e1c9eafdf925c9786aeb556c1d058e1d3d0d92b8a5fed45bff46204f7cc1db8b23e69f271593f4c8427ee5660fad6edf209f903921c1eba5c884777be45ca7875c72e5b44b550dc30ee875798a19a0d61965bf9ec6a17bdebb91b9e503dbf70e5ec314e67d199296cd6375c510b04dbe30ac3b6a083f655627ab3859c168263babfbd5ca2f9c33df7deefd46f37693ba4350b69e3ddbde6b0d5711c4a0a7c8dcadf8b2340ed7a0748c3e9ef6ae72022fd3799b0561f00b255cdde1199b1c2def3b6324508f28b1f1935aeb1083072598d8cea7e420ad8ce090922fca2be67b68e0b8fe5db2f06faca945480f4831a6fd9bbeb40084403a8a2617184f8c9d3340c2720b19f838d64a82eff4b2020ee92a72291102487788d8f774a32d5b1a6752cd80118f400806fe613d312d8d65cc21f4af83b50407fedec7ed4972a54b8d2260cb652f3d9f3868d3081b20a719a1ff8611fe19ec41dc92570b74688506746cf96c7f5db878446b0fdcc554a1c3e7fa62b611077a65e29bb460699a6187fa4c52b91f58cc103a7dce86d3feefd9dcbc86fa5bf67b13fc0157c6da22d5dda3f0443a05b2d7b286b5da2372013f18a361cab696219d84f8677588d8500b7ebb34b29b1520258bcaa19f77229ddab6fcba75faaf4e09ecaa590e77e027477f5399b47"); + + let aad = hex!("bbc9aa3017a7ee71293eb2ea451f2efa6794e41c55b7505df1f2073f5babe332a479619f855a39e45ef469b0c6329a786dbfc2b05b27983683d5edf26949cf964d75d7110bd4dba14a76f88353e3c652b46aca2f661d37dc7ffcf8da13c7aa48f25095ce16c8834c3d2c9c813197926d47c9f73895fdf70f2574d7f8539a9ef2aba78e80ec138ef1f702daf007ba337e1e0dfc49e6bd3f3eb4ff5a5c4e0ca2bdcf3e5b6fea5401dfaa40e66db6fc63a6e306755492684bbc6021e2a1bbf1245422377664475b22cdd83960e47852b474da196e67db018b87839966ffe52c665cabe0c021df68d0c1454505b0458fe3dc3acc6b8400ec04a3129266ae9368c15bbf13aabd05f859e2e9ea7cc937e899cc5c5bd72d2b72bd16d9024db4706fcf5195bbe25eb807fea01840f4b572f0fadb8a4246d6895547a37cd8a9b756425b31872a1d51c0ef2d53ca000711388228b76490780e3a10389c72ccc0deded32a5d9e723aa31dddd3344b068bcde9d483c9249375a88dce482a819361993fde555603cea01cede77fe64190906157ded418c3c21bc5274034b8d9edf09daf2aa90fb3b5f7d3b7da5c018144e54af9737227d2c13210c861fd5b4246d1a290fd054fd15d59d2e08894239d000b1076055771f7a7da54b2fcd7cd1f5a9e1da5a25a0ddbaa8d4397d74828a2b75a8da4730b87ac6c2fc5ef4985b9915320ea4942690df6"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("0001020304050607"); + let nonce = GenericArray::from_slice(&nonce[..8]); + + let ciphertext = + hex!("e94c5c6df7c19474bbdd292baa2555fdbd5e90a35fb94627cdd7dd3b424ca47d6779f3e6997809204263bdbd4825b7d6510995b1c371e582942bd7f6ab909f993cd5b7db5f95e8b8b56e4cdf016f5cab37f662329b32801fda4403f731fa61f7aa16b9a23f2637b1f75fa0b36ced90ce6a1f73aafbb5adca756e0d59b8ae6661f2d3fc409c88d8baf3836fac55df78b9ba522221345f42bd794c26d5d1a83fed0114d1d1b04d3c3b77ff0083647710b316e17896b2081d9375fde1f2fe063e66423a0d413919ffa6b5754d10de8de64d32ede0d02ebe8f8791d8e9f59462b615f4122dd8c3b97671a8c156eb32ebebb3fb91832fd01f6afee9d4ab045fea83ec87743823ea3bd18f7826229c312ad8a4bc9e2f6d1ad520e6d850bd189b4538d10005abf5a7c50f4f8ded6a62b18cd2a7e6bd3159edc3e9b553cbddd419af540da10576e9ea7d49e2fd0dc1c5ee7693504b63b928e4e23b1753147a3d0ad00cc2e6390fba10e925dc536db4eb30cf152ddb0420f8e8eaa8460feb9a7f0be589ccb877732d8d606085536c405c2ba6c03cb68e12f7d14609587a6c478e2a32794290ba35ce6dba21784d8f6faf401920bfc2aa172c3b4d9bea2eae8542b18410d3a40414247a406379855cb78c28e82ab67b62433a4016b15c4abf4f01c372ba4f1562596531cb0337117ad769eaa666b497b7822eba924e358693bc48cf555f70"); + + let tag: [u8; 16] = hex!("e404257c9cf7eb9774fc288a9ef1592e"); + + let encrypted = DeoxysI256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysI256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} diff --git a/deoxys/tests/deoxys_ii_128.rs b/deoxys/tests/deoxys_ii_128.rs new file mode 100644 index 00000000..4beea8ec --- /dev/null +++ b/deoxys/tests/deoxys_ii_128.rs @@ -0,0 +1,306 @@ +// Uses the official test vectors. +use deoxys::aead::generic_array::GenericArray; +use deoxys::aead::{Aead, NewAead, Payload}; +use deoxys::DeoxysII128; + +use hex_literal::hex; + +#[test] +fn test_deoxys_ii_128_1() { + let plaintext = Vec::new(); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("97d951f2fd129001483e831f2a6821e9"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_ii_128_2() { + let plaintext = Vec::new(); + + let aad = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("3c197ca5317af5a2b95b178a60553132"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_ii_128_3() { + let plaintext = Vec::new(); + + let aad = hex!("a754f3387be992ffee5bee80e18b151900c6d69ec59786fb12d2eadb0750f82cf5"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("0a989ed78fa16776cd6c691ea734d874"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_ii_128_4() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext = hex!("fa22f8eb84ee6d2388bdb16150232e856cd5fa3508bc589dad16d284208048c9"); + + let tag: [u8; 16] = hex!("a381b06ef16db99df089e738c3b4064a"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_128_5() { + let plaintext = hex!("06ac1756eccece62bd743fa80c299f7baa3872b556130f52265919494bdc136db3"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext = hex!("82bf241958b324ed053555d23315d3cc20935527fc970ff34a9f521a95e302136d"); + + let tag: [u8; 16] = hex!("0eadc8612d5208c491e93005195e9769"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_128_6() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: [u8; 32] = + hex!("9cdb554dfc03bff4feeb94df7736038361a76532b6b5a9c0bdb64a74dee983ff"); + + let tag: [u8; 16] = hex!("bc1a7b5b8e961e65ceff6877ef9e4a98"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_128_7() { + let plaintext = hex!("039ca0907aa315a0d5ba020c84378840023d4ad3ba639787d3f6f46cb446bd63dc"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f10"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: [u8; 33] = + hex!("801f1b81878faca562c8c6c0859b166c2669fbc54b1784be637827b4905729bdf9"); + + let tag: [u8; 16] = hex!("fe4e9bcd26b96647350eda1e550cc994"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_128_8() { + let plaintext = + hex!("95330042c3d48419798f9285fbd8d24968d7cee311f637463f8c0a1778f79d758a84e35b7d4a9fde2ed56fa796ad5a0f7004490ed32664ad69069678f53dfd7ee92e00a8ee34776b4d758536dc725ec4d48e2c11d0c5a16e4a2ce6c0e91604adb33a11127f50a46ea3cf5353d88a7a244c0f4337f449e68bf7c31feab02346d3c84c2335b8a06dc7df89dab05b6496fe428133c210c3bac68e18f026daa56662a41c36f9b55787fc1c5382d70b86e33be8555fd924606d2572c30a6ab6da71eccd4744ceb4e729519eef42ef4260db0e015832bfb0e742201fac36c711969a61243b08a77c372e44f76646fd1e9c9c06570447aa30527339baceb1d002e24e6ee3114f5a5daf0062bd372f824a60eebd74afc4fecffe74541933411b575295e27891abc71fc0e9597f65fc51be21962eea0aec96214b40a1a8ef32329df02a8b0ef038c48a1d5b2529ed01a820a6f262488de7791b07c5f941126be7893f7dadfb9639892264bc01af40402aa87a44df1754ce4e17226c41a8e3f05e4883d6ef4511e96378067f455f3a7275215622bfc71bb4db398b03b08e4bf6c54b2b6396c5b501fa26782fc36ad22044f5eb6a8f83efc8850d70ae4525d4e798f2aa1894621803394415f34cd4d002a2b3d393efa7d57f687b753830ff04798c240f05f581ce706f7d151417f09f17174cb87eff0e042c1860342b4ace069e1691e092e3"); + + let aad = hex!("5b187979e145d7b5beebbc0e689e759a027b5588059419b06b1afe4224f8f56ecccb2bfe2cef9ecf103eb382172320a17c19dce14a3e38030d3443697845b992ff1e871c02e788d7b40264f52ef0733791dc82dacdfa987685b33423bed0c05e0a65bce48ce1006d16628ea21b4390e75be72e043f299d6290289f90007474bf4e9ffb6c774d762afec8f3a01b2db545611772c32386fe6c7332125f0750c4987988d1e0e727c3c295bc743a34d3196d5e2d14f11bf2c884265ba901e77144a4b5a77864ad082e945727786f376bfcae99048ee7a994a2ea87584cd2e7e83ffd0310cf9cdb2cff5cf8c9cc09c94becb3f37fb9b071a76ee7ae115a49f0d95b1a9ec97e5b62bcae2c3cf47a3d2cb1b3d3dcd1729c33266ad7b0899654949a6f09086b74297cb48227e566e1f401109495ea05d636a5025104cd04c2a3c59f396b858f7f025825baf667b29b4f7f692f3a6c0c8956575a8dd183d1d03bd372c214e005d6e1090d89f2d950b8ac856465943568bc320602f52bf67d30f0d8ec7a9550dcdef99a43404a6d32d8f6b537b3eed568e32ab7ee63e16be63009702995d4d9300114638ba4c874f02039f3f67e2df64946030edef1930f30d4e6b9ca95887539d1af2036c8f5cf129c54d5734224e09b3daab5fb0e74c848af70a49c1499a5e56bc5eea90395df5bfd3e84a1c0a5be02dd3f2e2353e5522aeadaafdbf44444"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext= + hex!("b8eddddb8d0042bb42fdf675bae285e504b90e4d73e02f99f790b2ffe7815dba40fe4c7bc886ce44505f6ac53d3bba5d3c73efd98daf4b7a5af250a5d100ff5558c211cb03a28d9519502d7d0fc85a6d73e618feb6b503af12cb0330bb9c5743b19996174a84dbf5bac38d10d207067e4ab211a62ad0f85dd8245dfb077443017b7847996fe7ed547b9e02051f1cbe39128e21486b4f73399d0a50d9a1111bed11ebb0547454d0a922633c83f0bba784571f63f55dc33f92e09862471945312d99e40b4ed739556f102afd43055497739a4b22d107e867cc652a5d96974ff785976c82bc1ff89731c780e84a257bb885cd23e00a7bdc7a68e0a1668516fb972721a777429c76cfd4adb45afa554d44a8932d133af8c9254fd3fef2bd0bb65801f2ffbf752f14eaa783e53c2342f021863598e88b20232a0c44e963dd8943e9a54213ffbb174b90e38b55aa9b223e9596acb1517ff21b7458b7694488047797c521883c00762e7227f1e8a5e3f11a43962bdccde8dc4009aef7628a96efa8793d6080982f9b00a7b97d93fd5928702e78427f34eb434e2286de00216b405c36105dc2e8dae68c3342a23274b32a6d2d8ac85239a8fa2947126f505a517fb18847104b21b0326b7fd67efb54f5d0b12b311ef998ebaf14939b7cdb44b35435eedf1ba5b07eea99533f1857b8cc1538290a8dbd44ca696c6bc2f1105451032a650c"); + + let tag: [u8; 16] = hex!("e68a5de27beaeb6472611dfa9783602a"); + + let encrypted = DeoxysII128::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII128::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} diff --git a/deoxys/tests/deoxys_ii_256.rs b/deoxys/tests/deoxys_ii_256.rs new file mode 100644 index 00000000..44aa46aa --- /dev/null +++ b/deoxys/tests/deoxys_ii_256.rs @@ -0,0 +1,306 @@ +// Uses the official test vectors. +use deoxys::aead::generic_array::GenericArray; +use deoxys::aead::{Aead, NewAead, Payload}; +use deoxys::DeoxysII256; + +use hex_literal::hex; + +#[test] +fn test_deoxys_ii_256_1() { + let plaintext = Vec::new(); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("2b97bd77712f0cde975309959dfe1d7c"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_ii_256_2() { + let plaintext = Vec::new(); + + let aad = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("54708ae5565a71f147bdb94d7ba3aed7"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_ii_256_3() { + let plaintext = Vec::new(); + + let aad = hex!("f495c9c03d29989695d98ff5d430650125805c1e0576d06f26cbda42b1f82238b8"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: Vec = Vec::new(); + + let tag: [u8; 16] = hex!("3277689dc4208cc1ff59d15434a1baf1"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(plaintext, decrypted); +} + +#[test] +fn test_deoxys_ii_256_4() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext = hex!("9da20db1c2781f6669257d87e2a4d9be1970f7581bef2c995e1149331e5e8cc1"); + + let tag: [u8; 16] = hex!("92ce3aec3a4b72ff9eab71c2a93492fa"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_256_5() { + let plaintext = hex!("15cd77732f9d0c4c6e581ef400876ad9188c5b8850ebd38224da95d7cdc99f7acc"); + + let aad = Vec::new(); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext = hex!("e5ffd2abc5b459a73667756eda6443ede86c0883fc51dd75d22bb14992c684618c"); + + let tag: [u8; 16] = hex!("5fa78d57308f19d0252072ee39df5ecc"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_256_6() { + let plaintext = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: [u8; 32] = + hex!("109f8a168b36dfade02628a9e129d5257f03cc7912aefa79729b67b186a2b08f"); + + let tag: [u8; 16] = hex!("6549f9bf10acba0a451dbb2484a60d90"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_256_7() { + let plaintext = hex!("422857fb165af0a35c03199fb895604dca9cea6d788954962c419e0d5c225c0327"); + + let aad = hex!("000102030405060708090a0b0c0d0e0f10"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext: [u8; 33] = + hex!("7d772203fa38be296d8d20d805163130c69aba8cb16ed845c2296c61a8f34b394e"); + + let tag: [u8; 16] = hex!("0b3f10e3933c78190b24b33008bf80e9"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +} + +#[test] +fn test_deoxys_ii_256_8() { + let plaintext = + hex!("83dab23b1379e090755c99079cfe918cb737e989f2d720ccaff493a744927644fec3653211fa75306a83486e5c34ecfe63870c97251a73e4b9033ae374809711b211ed5d293a592e466a81170f1d85750b5ca025ccd4579947edbae9ec132bfb1a7233ad79fae30006a6699f143893861b975226ed9d3cfb8a240be232fbf4e83755d59d20bc2faa2ea5e5b0428427485cca5e76a89fe32bdd59ab4177ad7cb1899c101e3c4f7535129591390ebdf30140846078b13867bbb2efd6cf434afe356eb18d716b21fd664c26c908496534bf2cde6d6b897799016594fb6d9f830ae5f44ccec26d42ff0d1a21b80cdbe8c8c170a5f766fad884abcc781b5b8ebc0f559bfeaa4557b04d977d51411a7f47bf437d0280cf9f92bc4f9cd6226337a492320851955adae2cafea22a89c3132dd252e4728328eda05555dff3241404341b8aa502d45c456113af42a8e91a85e4b4e9555028982ec3d144722af0eb04a6d3b8127c3040629de53f5fd187048198e8f8e8cc857afcbae45c693fec12fc2149d5e7587d0121b1717d0147f6979f75e8f085293f705c3399a6cc8df7057bf481e6c374edf0a0af7479f858045357b7fe21021c3fabdaf012652bf2e5db257bd9490ce637a81477bd3f9814a2198fdb9afa9344321f2393798670e588c47a1924d592cda3eb5a96754dfd92d87ee1ffa9d4ee586c85d7518c5d2db57d0451c33de0"); + + let aad = hex!("3290bb8441279dc6083a43e9048c3dc08966ab30d7a6b35759e7a13339f124918f3b5ab1affa65e6c0e3680eb33a6ec82424ab1ce5a40b8654e13d845c29b13896a1466a75fc875acba4527ded37ed00c600a357c9a6e586c74cf3d85cd3258c813218f319d12b82480e5124ff19ec00bda1fbb8bd25eeb3de9fcbf3296deba250caf7e9f4ef0be1918e24221dd0be888c59c166ad761d7b58462a1b1d44b04265b45827172c133dd5b6c870b9af7b21368d12a88f4efa1751047543d584382d9ec22e7550d50ecddba27d1f65453f1f3398de54ee8c1f4ac8e16f5523d89641e99a632380af0f0b1e6b0e192ec29bf1d8714978ff9fbfb93604142393e9a82c3aaebbbe15e3b4e5cfd18bdfe309315c9f9f830deebe2edcdc24f8eca90fda49f6646e789c5041fb5be933fa843278e95f3a54f8eb41f14777ea949d5ea442b01249e64816151a325769e264ed4acd5c3f21700ca755d5bc0c2c5f9453419510bc74f2d71621dcecb9efc9c24791b4bb560fb70a8231521d6560af89d8d50144d9c080863f043781153bcd59030e60bd17a6d7aa083211b67b581fa4f74cce4d030d1e8f9429fd725c110040d41eb6989ffb1595c72cbe3c9b78a8ab80d71a6a5283da77b89cae295bb13c14fbe466b617f4da8ad60b085e2ea153f6713ae0046aa31e0ba44e43ef36a111bf05c073a4e3624cd35f63a546f9142b35aa81b8826d"); + + let payload = Payload { + msg: &plaintext, + aad: &aad, + }; + + let key = hex!("101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"); + let key = GenericArray::from_slice(&key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = GenericArray::from_slice(&nonce[..15]); + + let ciphertext = + hex!("88294fcef65a1bdfd7baaa472816c64ef5bef2622b88c1ec5a739396157ef4935f3aa76449e391c32da28ee2857f399ac3dd95aed30cfb26cc0063cd4cd8f7431108176fbf370123856662b000a8348e5925fbb97c9ec0c737758330a7983f06b51590c1d2f5e5faaf0eb58e34e19e5fc85cec03d3926dd46a79ba7026e83dec24e07484c9103dd0cdb0edb505500caca5e1d5dbc71348cf00648821488ebaab7f9d84bbbf91b3c521dbef30110e7bd94f8dad5ab8e0cc5411ca9682d210d5d80c0c4bdbba8181789a4273d6deb80899fdcd976ca6f3a9770b54305f586a04256cfbeb4c11254e88559f294db3b9a94b80ab9f9a02cb4c0748de0af7818685521691dba5738be546dba13a56016fb8635af9dff50f25d1b17ad21707db2640a76a741e65e559b2afaaec0f37e18436bf02008f84dbd7b2698687a22376b65dc7524fca8a28709eee3f3caee3b28ed1173d1e08ee849e2ca63d2c90d555755c8fbafd5d2f4b37f06a1dbd6852ee2ffcfe79d510152e98fc4f3094f740a4aede9ee378b606d34576776bf5f1269f5385a84b3928433bfca177550ccfcd22cd0331bbc595e38c2758b2662476fa66354c4e84c7b360405aa3f5b2a48621bdca1a90c69b21789c91b5b8c568e3c741d99e22f6d7e26f2abed045f1d578b782ab4a5cf2af636d842b3012e180e4b045d8d15b057b69c92398a517053daf9be7c2935e"); + + let tag: [u8; 16] = hex!("a616f0c218e18b526cf2a3f8c115e262"); + + let encrypted = DeoxysII256::new(key).encrypt(nonce, payload).unwrap(); + + let tag_begins = encrypted.len() - 16; + assert_eq!(ciphertext, encrypted[..tag_begins]); + assert_eq!(tag, encrypted[tag_begins..]); + + let payload = Payload { + msg: &encrypted, + aad: &aad, + }; + + let decrypted = DeoxysII256::new(key).decrypt(nonce, payload).unwrap(); + + assert_eq!(&plaintext[..], &decrypted[..]); +}