diff --git a/Cargo.lock b/Cargo.lock index 7b0ba102..1e09a9ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,41 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -206,6 +241,12 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -286,10 +327,21 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-targets", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.4.7" @@ -309,7 +361,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.10.0", ] [[package]] @@ -391,9 +443,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -444,6 +541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -458,6 +556,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "ecdsa" version = "0.16.8" @@ -695,6 +799,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.28.0" @@ -878,6 +992,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.4.0" @@ -896,6 +1016,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -906,6 +1027,16 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", ] [[package]] @@ -1152,6 +1283,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "p256" version = "0.13.2" @@ -1193,7 +1330,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b13fe415cdf3c8e44518e18a7c95a13431d9bdf6d15367d82b23c377fdd441a" dependencies = [ - "base64", + "base64 0.21.5", "serde", ] @@ -1203,7 +1340,7 @@ version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" dependencies = [ - "base64", + "base64 0.21.5", "serde", ] @@ -1285,6 +1422,18 @@ dependencies = [ "spki", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1422,9 +1571,10 @@ dependencies = [ name = "recert" version = "0.1.0" dependencies = [ + "aes-gcm", "anyhow", "async-trait", - "base64", + "base64 0.21.5", "bcder", "bytes", "chrono", @@ -1432,10 +1582,12 @@ dependencies = [ "clio", "data-url", "der", + "dyn-clone", "etcd-client", "fn-error-context", "futures-util", "glob", + "hex", "hmac", "itertools 0.12.1", "lazy-regex", @@ -1454,6 +1606,7 @@ dependencies = [ "rsa", "serde", "serde_json", + "serde_with", "serde_yaml", "serial_test", "sha1", @@ -1658,6 +1811,36 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.1.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_yaml" version = "0.9.27" @@ -1812,6 +1995,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.25.0" @@ -2007,7 +2196,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64", + "base64 0.21.5", "bytes", "h2", "http", @@ -2134,6 +2323,16 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsafe-libyaml" version = "0.2.9" diff --git a/Cargo.toml b/Cargo.toml index 2c53290c..2ff35d4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,10 @@ prost = "0.12.1" log = "0.4.20" itertools = "0.12.1" serial_test = "3.0.0" +aes-gcm = "0.10.3" +dyn-clone = "1.0.17" +hex = "0.4.3" +serde_with = { version = "3.11.0", features = ["base64"] } [build-dependencies] prost-build = "0.12.1" diff --git a/src/config.rs b/src/config.rs index 6f406a23..0647bb56 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,6 +2,7 @@ use self::{cli::Cli, path::ConfigPath}; use crate::{ cluster_crypto::REDACT_SECRETS, cnsanreplace::{CnSanReplace, CnSanReplaceRules}, + encrypt_config::EncryptionConfig, ocp_postprocess::{ additional_trust_bundle::params::{parse_additional_trust_bundle, ProxyAdditionalTrustBundle}, cluster_domain_rename::params::ClusterNamesRename, @@ -53,6 +54,13 @@ pub(crate) struct ClusterCustomizations { pub(crate) chrony_config: Option, } +#[derive(serde::Serialize)] +pub(crate) struct EncryptionCustomizations { + pub(crate) kube_encryption_config: Option, + pub(crate) openshift_encryption_config: Option, + pub(crate) oauth_encryption_config: Option, +} + /// All parsed CLI arguments, coalesced into a single struct for convenience #[derive(serde::Serialize)] pub(crate) struct RecertConfig { @@ -61,6 +69,7 @@ pub(crate) struct RecertConfig { pub(crate) etcd_endpoint: Option, pub(crate) crypto_customizations: CryptoCustomizations, pub(crate) cluster_customizations: ClusterCustomizations, + pub(crate) encryption_customizations: EncryptionCustomizations, pub(crate) threads: Option, pub(crate) regenerate_server_ssh_keys: Option, pub(crate) summary_file: Option, @@ -156,6 +165,11 @@ impl RecertConfig { proxy_trusted_ca_bundle: None, chrony_config: None, }, + encryption_customizations: EncryptionCustomizations { + kube_encryption_config: None, + openshift_encryption_config: None, + oauth_encryption_config: None, + }, threads: None, regenerate_server_ssh_keys: None, summary_file: None, @@ -269,6 +283,18 @@ impl RecertConfig { Some(value) => Some(value.as_str().context("etcd_endpoint must be a string")?.to_string()), None => None, }; + let kube_encryption_config = match value.remove("kube_encryption_config") { + Some(value) => parse_encryption_config(value)?, + None => None, + }; + let openshift_encryption_config = match value.remove("openshift_encryption_config") { + Some(value) => parse_encryption_config(value)?, + None => None, + }; + let oauth_encryption_config = match value.remove("oauth_encryption_config") { + Some(value) => parse_encryption_config(value)?, + None => None, + }; let threads = match value.remove("threads") { Some(value) => parse_threads(value)?, None => None, @@ -323,11 +349,18 @@ impl RecertConfig { chrony_config, }; + let encryption_customizations = EncryptionCustomizations { + kube_encryption_config, + openshift_encryption_config, + oauth_encryption_config, + }; + let recert_config = Self { dry_run, etcd_endpoint, crypto_customizations, cluster_customizations, + encryption_customizations, threads, regenerate_server_ssh_keys, summary_file, @@ -406,6 +439,11 @@ impl RecertConfig { machine_network_cidr: cli.machine_network_cidr, chrony_config: cli.chrony_config, }, + encryption_customizations: EncryptionCustomizations { + kube_encryption_config: cli.kube_encryption_config, + openshift_encryption_config: cli.openshift_encryption_config, + oauth_encryption_config: cli.oauth_encryption_config, + }, threads: cli.threads, regenerate_server_ssh_keys: cli.regenerate_server_ssh_keys.map(ConfigPath::from), summary_file: cli.summary_file.map(ConfigPath::from), @@ -475,6 +513,15 @@ fn parse_threads(value: Value) -> Result> { )) } +fn parse_encryption_config(value: Value) -> Result> { + Ok(Some( + EncryptionConfig::parse(value.as_str().context("encryption_config must be a string")?).context(format!( + "encryption_config {}", + value.as_str().context("encryption_config must be a string")? + ))?, + )) +} + fn parse_cert_rules(value: Value) -> Result { Ok(UseCertRules( value diff --git a/src/config/cli.rs b/src/config/cli.rs index 916dd02b..6c3750f6 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -1,5 +1,6 @@ use crate::{ cnsanreplace::CnSanReplace, + encrypt_config::EncryptionConfig, ocp_postprocess::{ additional_trust_bundle::params::ProxyAdditionalTrustBundle, cluster_domain_rename::params::ClusterNamesRename, proxy_rename::args::Proxy, @@ -18,6 +19,33 @@ pub(crate) struct Cli { #[clap(long)] pub(crate) etcd_endpoint: Option, + // OpenShift supports encryption at rest for: + // - Secrets, ConfigMaps encrypted by the kube-apiserver + // - Routes encrypted by the openshift-kube-apiserver + // - oauth {access,authorize} tokens encrypted by the openshift-oauth-apiserver + // To discover whether the seed image has etcd encryption enabled, recert checks the apiserver CR's `spec.encryption.type == aesgcm | aescbc`. + // When enabled, the secrets/openshift-kube-apiserver/encryption-config and the secrets/openshift-oauth-apiserver/encryption-config + // are encrypted by the kube-apiserver and recerts decrypts those first in order to decrypt Routes and oauth token resources. + // Thus recert uses the kube-apiserver encryption-config file (i.e. /etc/kubernetes/static-pod-resources/kube-apiserver-pod-/secrets/encryption-config/encryption-config) + // to fetch the encryption details for the kube-apiserver encrypted resources (i.e. Secrets and ConfigMaps) first. + /// Kubernetes API server EncryptionConfiguration resource in JSON formatted string or path to the respective file. + /// When specified, recert will use the encryption keys in this config to encrypt the specified Kubernetes resources + /// and then put this config in etcd and the filesystem. + #[clap(long, value_parser = EncryptionConfig::parse)] + pub(crate) kube_encryption_config: Option, + + /// OpenShift API server EncryptionConfiguration resource in JSON formatted string or path to the respective file. + /// When specified, recert will use these encryption keys in this config to encrypt the specified OpenShift resources + /// and then put this config in etcd. + #[clap(long, value_parser = EncryptionConfig::parse)] + pub(crate) openshift_encryption_config: Option, + + /// OAuth API server EncryptionConfiguration resource in JSON formatted string or path to the respective file. + /// When specified, recert will use the encryption keys in this config to encrypt the specified oauth resources + /// and then put this config in etcd. + #[clap(long, value_parser = EncryptionConfig::parse)] + pub(crate) oauth_encryption_config: Option, + // DEPRECATED: Use --crypto-dir and --cluster-customization-dir instead. This option will be // removed in a future release. Cannot be used with --crypto-dir or --cluster-customization-dir // or --additional-trust-bundle diff --git a/src/encrypt.rs b/src/encrypt.rs new file mode 100644 index 00000000..765411c1 --- /dev/null +++ b/src/encrypt.rs @@ -0,0 +1,229 @@ +use self::transformer::Transformer; +use anyhow::{bail, ensure, Context, Result}; +use serde::{Deserialize, Serialize}; +use serde_with::{base64::Base64, serde_as}; +use std::collections::HashMap; +use tokio::process::Command; + +pub(crate) mod aescbc; +pub(crate) mod aesgcm; +pub(crate) mod transformer; + +const API_VERSION: &str = "apiserver.config.k8s.io/v1"; +const KIND: &str = "EncryptionConfiguration"; + +const AES_KEY_SIZE: usize = 256; +const AES_KEY_SIZE_BYTES: usize = AES_KEY_SIZE / 8; + +#[allow(non_snake_case)] +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct EncryptionConfiguration { + pub(crate) kind: String, + pub(crate) apiVersion: String, + pub(crate) resources: Vec, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct Resource { + pub(crate) resources: Vec, + pub(crate) providers: Vec, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct Provider { + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) aesgcm: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) aescbc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub(crate) identity: Option, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct AesGcm { + pub(crate) keys: Vec, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct AesCbc { + pub(crate) keys: Vec, +} + +#[serde_as] +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct Key { + pub(crate) name: String, + #[serde_as(as = "Base64")] + pub(crate) secret: Vec, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub(crate) struct Identity {} + +#[derive(Clone)] +pub(crate) struct ResourceTransformers { + pub(crate) resource_to_prefix_transformers: HashMap>>, +} + +impl EncryptionConfiguration { + pub(crate) async fn new(resource_names: Vec, encryption_type: String) -> Result { + // use the same key for the resources of an EncryptionConfiguration object + let key = generate_key().await.context("could not generate key")?; + + let mut resources = Vec::::new(); + for res in resource_names { + let mut resource = Resource { + resources: vec![res.to_string()], + providers: vec![], + }; + let provider = match encryption_type.as_str() { + "aesgcm" => Provider { + aesgcm: Some(AesGcm { + keys: vec![Key { + name: "1".to_string(), + secret: key.clone(), + }], + }), + aescbc: None, + identity: None, + }, + "aescbc" => Provider { + aesgcm: None, + aescbc: Some(AesCbc { + keys: vec![Key { + name: "1".to_string(), + secret: key.clone(), + }], + }), + identity: None, + }, + "identity" => Provider { + aesgcm: None, + aescbc: None, + identity: Some(Identity {}), + }, + _ => { + bail!("unsupported encryption type"); + } + }; + resource.providers.push(provider); + // Always put identity in the providers + resource.providers.push(Provider { + aesgcm: None, + aescbc: None, + identity: Some(Identity {}), + }); + resources.push(resource); + } + + Ok(Self { + apiVersion: API_VERSION.to_string(), + kind: KIND.to_string(), + resources, + }) + } + + pub(crate) async fn new_kube_apiserver_config(encryption_type: String) -> Result { + Self::new(vec!["configmaps".to_string(), "secrets".to_string()], encryption_type).await + } + + pub(crate) async fn new_openshift_apiserver_config(encryption_type: String) -> Result { + Self::new(vec!["routes.route.openshift.io".to_string()], encryption_type).await + } + + pub(crate) async fn new_oauth_apiserver_config(encryption_type: String) -> Result { + Self::new( + vec![ + "oauthaccesstokens.oauth.openshift.io".to_string(), + "oauthauthorizetokens.oauth.openshift.io".to_string(), + ], + encryption_type, + ) + .await + } + + pub(crate) fn parse_from_file(config_bytes: Vec) -> Result { + let config: EncryptionConfiguration = serde_json::from_slice(&config_bytes)?; + + ensure!(config.kind == KIND, format!("kind should equal {}, found {}", KIND, config.kind)); + ensure!( + config.apiVersion == API_VERSION, + format!("apiVersion should equal {}, found {}", API_VERSION, config.apiVersion) + ); + + Ok(config) + } + + pub(crate) fn remove_redundant_providers(&mut self) { + for res in &mut self.resources { + if res.providers.len() > 1 { + res.providers = vec![res.providers[0].clone()] + } + } + } +} + +async fn generate_key() -> Result> { + let output = Command::new("openssl") + .arg("rand") + .arg(AES_KEY_SIZE_BYTES.to_string()) + .output() + .await + .context("failed to run openssl command")?; + + ensure!( + output.status.success(), + format!("openssl command failed with status: {}", output.status) + ); + + ensure!( + output.stdout.len() == AES_KEY_SIZE_BYTES, + format!("expected {} bytes, got {}", AES_KEY_SIZE_BYTES, output.stdout.len()) + ); + + Ok(output.stdout) +} + +impl ResourceTransformers { + pub(crate) fn parse_from_encryption_configuration(config: EncryptionConfiguration) -> Result { + let mut transformers: HashMap>> = HashMap::new(); + + for resources in config.resources { + let mut providers: Vec> = Vec::new(); + + for provider in resources.providers { + match (provider.aesgcm, provider.aescbc, provider.identity) { + (Some(aesgcm), None, None) => { + let prefix = "k8s:enc:aesgcm:v1:"; + for key in aesgcm.keys { + let prefix = format!("{}{}:", prefix, key.name); + providers.push(Box::new(aesgcm::AesGcm::new(prefix, key.secret))); + } + } + (None, Some(aescbc), None) => { + let prefix = "k8s:enc:aescbc:v1:"; + for key in aescbc.keys { + let prefix = format!("{}{}:", prefix, key.name); + providers.push(Box::new(aescbc::AesCbc::new(prefix, key.secret))); + } + } + (None, None, Some(_)) => { + // Nothing to implement + } + _ => { + bail!("unsupported provider"); + } + } + } + for resource in resources.resources { + if let Some(key) = resource.split('.').next() { + transformers.insert(key.to_string(), providers.clone()); + } + } + } + + Ok(Self { + resource_to_prefix_transformers: transformers, + }) + } +} diff --git a/src/encrypt/aescbc.rs b/src/encrypt/aescbc.rs new file mode 100644 index 00000000..74e9674e --- /dev/null +++ b/src/encrypt/aescbc.rs @@ -0,0 +1,154 @@ +use super::transformer::Transformer; +use anyhow::{ensure, Context, Result}; +use async_trait::async_trait; +use std::process::Stdio; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::process::Child; +use tokio::process::Command; + +const BLOCK_SIZE: usize = 16; + +#[derive(Clone)] +pub(crate) struct AesCbc { + prefix: String, + key: Vec, +} + +impl AesCbc { + pub(crate) fn new(prefix: String, key: Vec) -> Self { + Self { prefix, key } + } + + async fn generate_iv() -> Result> { + let output = Command::new("openssl") + .arg("rand") + .arg("16") + .output() + .await + .context("failed to run openssl command")?; + + ensure!( + output.status.success(), + format!("openssl command failed with status: {}", output.status) + ); + + Ok(output.stdout) + } + + async fn run_command_with_stdin(mut cmd: Child, stdin_data: Option<&[u8]>) -> Result> { + let stdin_future = async { + if let Some(mut stdin) = cmd.stdin.take() { + if let Some(data) = stdin_data { + stdin.write_all(data).await.context("failed to write to stdin")?; + } + } + Ok::<_, anyhow::Error>(()) + }; + + let mut stdout_buffer = Vec::new(); + let stdout_future = async { + if let Some(mut stdout) = cmd.stdout.take() { + stdout.read_to_end(&mut stdout_buffer).await.context("failed to read from stdout")?; + } + Ok::<_, anyhow::Error>(()) + }; + + let mut stderr_buffer = Vec::new(); + let stderr_future = async { + if let Some(mut stderr) = cmd.stderr.take() { + stderr.read_to_end(&mut stderr_buffer).await.context("failed to read from stderr")?; + } + Ok::<_, anyhow::Error>(()) + }; + + let (stdin_result, stdout_result, stderr_result) = tokio::join!(stdin_future, stdout_future, stderr_future); + + stdin_result?; + stdout_result?; + stderr_result?; + + let status = cmd.wait().await.context("failed to wait for command")?; + + ensure!( + status.success(), + format!("Command failed with stderr: {}", String::from_utf8_lossy(&stderr_buffer)) + ); + + Ok(stdout_buffer) + } +} + +#[async_trait] +impl Transformer for AesCbc { + fn get_prefix(&self) -> String { + self.prefix.to_string() + } + + async fn decrypt(&self, _etcd_key: String, ciphertext: Vec) -> Result> { + let (_, cipher_data) = ciphertext.split_at(self.prefix.len()); + ensure!(cipher_data.len() >= BLOCK_SIZE, "data is shorter than the required block size"); + + let (iv, data) = cipher_data.split_at(BLOCK_SIZE); + ensure!(data.len() % BLOCK_SIZE == 0, "invalid block size"); + + let cmd = Command::new("openssl") + .arg("enc") + .arg("-d") + .arg("-aes-256-cbc") + .arg("-K") + .arg(hex::encode(&self.key)) + .arg("-iv") + .arg(hex::encode(iv)) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("failed to spawn openssl")?; + + let plaintext = Self::run_command_with_stdin(cmd, Some(data)) + .await + .context("AES-CBC decryption error")?; + + Ok(plaintext) + } + + async fn encrypt(&self, _etcd_key: String, data: Vec) -> Result> { + let padding_size = BLOCK_SIZE - (data.len() % BLOCK_SIZE); + let total_size = data.len() + padding_size; + + let mut plaintext = vec![0u8; total_size]; + plaintext[..data.len()].copy_from_slice(&data); + + // add padding at the end + for i in 0..padding_size { + plaintext[data.len() + i] = padding_size as u8; + } + + let iv = Self::generate_iv().await.context("generating IV")?; + + let cmd = Command::new("openssl") + .arg("enc") + .arg("-e") + .arg("-aes-256-cbc") + .arg("-nopad") + .arg("-K") + .arg(hex::encode(&self.key)) + .arg("-iv") + .arg(hex::encode(&iv)) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .context("failed to spawn openssl")?; + + let ciphered_data = Self::run_command_with_stdin(cmd, Some(&plaintext)) + .await + .context("AES-CBC encryption error")?; + + let mut encrypted_data: Vec = self.prefix.as_bytes().to_vec(); + encrypted_data.extend_from_slice(&iv); + encrypted_data.extend_from_slice(&ciphered_data); + + Ok(encrypted_data) + } +} diff --git a/src/encrypt/aesgcm.rs b/src/encrypt/aesgcm.rs new file mode 100644 index 00000000..89d1c375 --- /dev/null +++ b/src/encrypt/aesgcm.rs @@ -0,0 +1,64 @@ +use super::transformer::Transformer; +use aes_gcm::{ + aead::{Aead, KeyInit, OsRng, Payload}, + AeadCore, Aes256Gcm, Key, Nonce, +}; +use anyhow::Result; +use async_trait::async_trait; + +#[derive(Clone)] +pub(crate) struct AesGcm { + prefix: String, + key: Vec, +} + +impl AesGcm { + pub(crate) fn new(prefix: String, key: Vec) -> Self { + Self { prefix, key } + } +} + +#[async_trait] +impl Transformer for AesGcm { + fn get_prefix(&self) -> String { + self.prefix.to_string() + } + + async fn decrypt(&self, etcd_key: String, ciphertext: Vec) -> Result> { + let nonce_size = 12; + + let key = Key::::from_slice(&self.key); + let cipher = Aes256Gcm::new(key); + + let (_, nonce_cipher_data) = ciphertext.split_at(self.prefix.len()); + let (nonce_arr, ciphered_data) = nonce_cipher_data.split_at(nonce_size); + let nonce = Nonce::from_slice(nonce_arr); + let aad = etcd_key.clone().into_bytes(); + + let ciphered = Payload { + msg: ciphered_data, + aad: &aad[..], + }; + let plaintext = cipher.decrypt(nonce, ciphered).map_err(anyhow::Error::msg)?; + + Ok(plaintext) + } + + async fn encrypt(&self, etcd_key: String, plaintext: Vec) -> Result> { + let key = Key::::from_slice(&self.key); + let cipher = Aes256Gcm::new(key); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + let aad = etcd_key.clone().into_bytes(); + let payload = Payload { + msg: &plaintext, + aad: &aad[..], + }; + + let ciphered_data = cipher.encrypt(&nonce, payload).map_err(anyhow::Error::msg)?; + let mut encrypted_data: Vec = self.prefix.as_bytes().to_vec(); + encrypted_data.extend_from_slice(&nonce); + encrypted_data.extend_from_slice(&ciphered_data); + + Ok(encrypted_data) + } +} diff --git a/src/encrypt/transformer.rs b/src/encrypt/transformer.rs new file mode 100644 index 00000000..15cc116d --- /dev/null +++ b/src/encrypt/transformer.rs @@ -0,0 +1,13 @@ +use anyhow::Result; +use async_trait::async_trait; +use dyn_clone::DynClone; + +#[async_trait] +pub(crate) trait Transformer: DynClone { + fn get_prefix(&self) -> String; + + async fn decrypt(&self, etcd_key: String, ciphertext: Vec) -> Result>; + async fn encrypt(&self, etcd_key: String, plaintext: Vec) -> Result>; +} + +dyn_clone::clone_trait_object!(Transformer); diff --git a/src/encrypt_config.rs b/src/encrypt_config.rs new file mode 100644 index 00000000..1356b6f7 --- /dev/null +++ b/src/encrypt_config.rs @@ -0,0 +1,46 @@ +use std::path::PathBuf; + +use anyhow::{ensure, Context, Result}; + +use crate::encrypt::EncryptionConfiguration; + +#[derive(Clone, serde::Serialize)] +pub(crate) struct EncryptionConfig { + pub(crate) config: EncryptionConfiguration, +} + +impl std::fmt::Display for EncryptionConfig { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Using encryption configuration {}", self.config.apiVersion) + } +} + +impl EncryptionConfig { + pub(crate) fn new(config: EncryptionConfiguration) -> Self { + Self { config } + } + + pub(crate) fn parse(config_path_or_string: &str) -> Result { + // using '{' as it's a JSON formatted string + let config = EncryptionConfiguration::parse_from_file(if config_path_or_string.contains('{') { + config_path_or_string.as_bytes().to_vec() + } else { + let path = PathBuf::from(config_path_or_string); + ensure!( + path.exists(), + "encryption configuration file {} does not exist", + config_path_or_string + ); + ensure!( + path.is_file(), + "encryption configuration file {} is not a file", + config_path_or_string + ); + + std::fs::read(config_path_or_string).context("reading encryption config file")? + }) + .context("parsing encryption configuration")?; + + Ok(Self { config }) + } +} diff --git a/src/k8s_etcd.rs b/src/k8s_etcd.rs index ddac5b24..57549844 100644 --- a/src/k8s_etcd.rs +++ b/src/k8s_etcd.rs @@ -1,4 +1,5 @@ use crate::cluster_crypto::locations::K8sResourceLocation; +use crate::encrypt::ResourceTransformers; use crate::etcd_encoding; use anyhow::{bail, ensure, Context, Result}; use etcd_client::{Client as EtcdClient, GetOptions}; @@ -24,16 +25,24 @@ pub(crate) struct InMemoryK8sEtcd { etcd_keyvalue_hashmap: Mutex>>, edited: Mutex>>, deleted_keys: Mutex>, + decrypt_resource_transformers: Option, + encrypt_resource_transformers: Option, } impl InMemoryK8sEtcd { /// Pass a None etcd_client to disable actual etcd access (dummy mode, empty key list). - pub(crate) fn new(etcd_client: Option) -> Self { + pub(crate) fn new( + etcd_client: Option, + decrypt_resource_transformers: Option, + encrypt_resource_transformers: Option, + ) -> Self { Self { etcd_client: etcd_client.map(Arc::new), etcd_keyvalue_hashmap: Mutex::new(HashMap::new()), deleted_keys: Mutex::new(HashSet::new()), edited: Mutex::new(HashMap::new()), + decrypt_resource_transformers, + encrypt_resource_transformers, } } @@ -98,7 +107,21 @@ impl InMemoryK8sEtcd { let key = key.clone(); let value = value.clone(); let etcd_client = Arc::clone(etcd_client); - let value = etcd_encoding::encode(value.as_slice()).await.context("encoding value")?; + + let mut value = etcd_encoding::encode(value.as_slice()).await.context("encoding value")?; + + if let Some(resource_transformers) = &self.encrypt_resource_transformers { + // https://github.com/kubernetes/apiserver/blob/3423727e46efe7dfa40dcdb1a9c5c5027b07303d/pkg/storage/value/transformer.go#L172 + if let Some(transformers) = resource_transformers + .resource_to_prefix_transformers + .get(&resource_from_key(key.to_string())) + { + value = transformers[0] + .encrypt(key.to_string(), value) + .await + .context("encrypting etcd value")?; + } + } etcd_client .kv_client() @@ -110,6 +133,40 @@ impl InMemoryK8sEtcd { Ok(()) } + pub(crate) async fn reencrypt_resources(&self) -> Result<()> { + if let Some(resource_transformers) = &self.encrypt_resource_transformers { + for resource in resource_transformers.resource_to_prefix_transformers.keys() { + join_all(self.list_keys(resource).await?.into_iter().map(|key| async move { + if !self.deleted_keys.lock().await.contains(&key) { + let etcd_result = self + .get(key.clone()) + .await + .with_context(|| format!("getting key {:?}", key))? + .context("key disappeared")?; + + let value: serde_json::Value = serde_json::from_slice(etcd_result.value.as_slice()) + .with_context(|| format!("deserializing value of key {:?}", key,))?; + + let k8s_resource_location = K8sResourceLocation::try_from(&value)?; + + let workload = get_etcd_json(self, &k8s_resource_location) + .await? + .context(format!("no workload for {:?}", k8s_resource_location.as_etcd_key()))?; + + put_etcd_yaml(self, &k8s_resource_location, workload).await?; + } + + Ok(()) + })) + .await + .into_iter() + .collect::>>()?; + } + } + + Ok(()) + } + pub(crate) async fn get(&self, key: String) -> Result> { let etcd_client = match &self.etcd_client { Some(etcd_client) => etcd_client, @@ -134,7 +191,27 @@ impl InMemoryK8sEtcd { if let Some(value) = get_result.kvs().first() { let raw_etcd_value = value.value(); - let decoded_value = etcd_encoding::decode(raw_etcd_value).await.context("decoding value")?; + let mut decoded_value = etcd_encoding::decode(raw_etcd_value).await.context("decoding value")?; + + if let Some(resource_transformers) = &self.decrypt_resource_transformers { + // https://github.com/kubernetes/apiserver/blob/3423727e46efe7dfa40dcdb1a9c5c5027b07303d/pkg/storage/value/transformer.go#L110 + if let Some(transformers) = resource_transformers + .resource_to_prefix_transformers + .get(&resource_from_key(key.to_string())) + { + for transformer in transformers { + if raw_etcd_value.to_vec().starts_with(transformer.get_prefix().as_bytes()) { + let plaintext_value = transformer + .decrypt(key.to_string(), raw_etcd_value.to_vec()) + .await + .context("decrypting etcd value")?; + decoded_value = etcd_encoding::decode(&plaintext_value).await.context("decoding value")?; + break; + } + } + } + } + self.etcd_keyvalue_hashmap .lock() .await @@ -159,10 +236,18 @@ impl InMemoryK8sEtcd { None => return Ok(vec![]), }; + let kubernetes_keys = self.get_keys_with_prefix(etcd_client, "/kubernetes.io", resource_kind).await?; + let openshift_keys = self.get_keys_with_prefix(etcd_client, "/openshift.io", resource_kind).await?; + let keys: Vec<_> = kubernetes_keys.into_iter().chain(openshift_keys.into_iter()).collect(); + + Ok(keys) + } + + async fn get_keys_with_prefix(&self, etcd_client: &Arc, prefix: &str, resource_kind: &str) -> Result> { let etcd_get_options = GetOptions::new().with_prefix().with_limit(0).with_keys_only(); let keys = etcd_client .kv_client() - .get(format!("/kubernetes.io/{}", resource_kind), Some(etcd_get_options.clone())) + .get(format!("{}/{}", prefix, resource_kind), Some(etcd_get_options.clone())) .await?; keys.kvs() @@ -214,6 +299,10 @@ impl InMemoryK8sEtcd { } } +fn resource_from_key(key: String) -> String { + key.split('/').collect::>()[2].to_string() +} + fn is_too_many_requests_error(delete_response: &std::prelude::v1::Result) -> bool { match delete_response { Ok(_) => false, diff --git a/src/main.rs b/src/main.rs index efa35765..f49ae5f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,8 @@ use std::sync::atomic::Ordering::Relaxed; mod cluster_crypto; mod cnsanreplace; mod config; +mod encrypt; +mod encrypt_config; mod etcd_encoding; mod file_utils; mod json_tools; diff --git a/src/ocp_postprocess.rs b/src/ocp_postprocess.rs index 5b47c302..a039df85 100644 --- a/src/ocp_postprocess.rs +++ b/src/ocp_postprocess.rs @@ -25,6 +25,7 @@ pub(crate) mod additional_trust_bundle; mod arguments; pub(crate) mod chrony_config; pub(crate) mod cluster_domain_rename; +pub(crate) mod encryption_config; mod fnv; mod go_base32; pub(crate) mod hostname_rename; diff --git a/src/ocp_postprocess/cluster_domain_rename.rs b/src/ocp_postprocess/cluster_domain_rename.rs index e954b587..c3bbdd5d 100644 --- a/src/ocp_postprocess/cluster_domain_rename.rs +++ b/src/ocp_postprocess/cluster_domain_rename.rs @@ -217,7 +217,7 @@ async fn fix_etcd_resources( .context("fixing routes")?; etcd_rename::fix_controller_config(etcd_client, &generated_infra_id, cluster_domain) .await - .context("fixing routes")?; + .context("fixing controller config")?; etcd_rename::delete_resources(etcd_client).await.context("fixing kcm pods")?; etcd_rename::fix_oauth_client( etcd_client, diff --git a/src/ocp_postprocess/encryption_config.rs b/src/ocp_postprocess/encryption_config.rs new file mode 100644 index 00000000..7378e241 --- /dev/null +++ b/src/ocp_postprocess/encryption_config.rs @@ -0,0 +1,79 @@ +use crate::config::EncryptionCustomizations; +use crate::{config::path::ConfigPath, k8s_etcd::InMemoryK8sEtcd}; +use anyhow::{Context, Result}; +use std::{path::Path, sync::Arc}; + +mod etcd_rename; +mod filesystem_rename; + +pub(crate) async fn rename_all( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, + dirs: &[ConfigPath], + files: &[ConfigPath], +) -> Result<()> { + fix_etcd_resources(etcd_client, encryption_customizations) + .await + .context("renaming etcd resources")?; + + fix_filesystem_resources(encryption_customizations, dirs, files) + .await + .context("renaming filesystem resources")?; + + Ok(()) +} + +async fn fix_filesystem_resources( + encryption_customizations: &EncryptionCustomizations, + dirs: &[ConfigPath], + files: &[ConfigPath], +) -> Result<()> { + for dir in dirs { + fix_dir_resources(encryption_customizations, dir).await?; + } + + for file in files { + fix_file_resources(encryption_customizations, file).await?; + } + + Ok(()) +} + +async fn fix_dir_resources(encryption_customizations: &EncryptionCustomizations, dir: &Path) -> Result<()> { + filesystem_rename::fix_filesystem_kas_pods(encryption_customizations, dir) + .await + .context(format!("fix filesystem kube-apiserver encryption-config in {:?}", dir))?; + Ok(()) +} + +async fn fix_file_resources(_encryption_customizations: &EncryptionCustomizations, _file: &Path) -> Result<()> { + Ok(()) +} + +async fn fix_etcd_resources(etcd_client: &Arc, encryption_customizations: &EncryptionCustomizations) -> Result<()> { + etcd_rename::update_kube_apiserver_encryption_config(etcd_client, encryption_customizations) + .await + .context("updating kube-apiserver encryption-config")?; + + etcd_rename::update_openshift_apiserver_encryption_config(etcd_client, encryption_customizations) + .await + .context("updating openshift-apiserver encryption-config")?; + + etcd_rename::update_oauth_apiserver_encryption_config(etcd_client, encryption_customizations) + .await + .context("updating oauth-apiserver encryption-config")?; + + etcd_rename::update_kube_apiserver_encryption_key(etcd_client, encryption_customizations) + .await + .context("updating secrets/openshift-config-managed/encryption-key-openshift-kube-apiserver")?; + + etcd_rename::update_openshift_apiserver_encryption_key(etcd_client, encryption_customizations) + .await + .context("updating secrets/openshift-config-managed/encryption-key-openshift-apiserver")?; + + etcd_rename::update_oauth_apiserver_encryption_key(etcd_client, encryption_customizations) + .await + .context("updating secrets/openshift-config-managed/ncryption-key-openshift-oauth-apiserver")?; + + Ok(()) +} diff --git a/src/ocp_postprocess/encryption_config/etcd_rename.rs b/src/ocp_postprocess/encryption_config/etcd_rename.rs new file mode 100644 index 00000000..e8d6c60e --- /dev/null +++ b/src/ocp_postprocess/encryption_config/etcd_rename.rs @@ -0,0 +1,226 @@ +use crate::{ + cluster_crypto::locations::K8sResourceLocation, + config::EncryptionCustomizations, + encrypt::{EncryptionConfiguration, Provider}, + k8s_etcd::{get_etcd_json, put_etcd_yaml, InMemoryK8sEtcd}, +}; +use anyhow::{bail, Context, Result}; +use base64::{engine::general_purpose::STANDARD as base64_standard, Engine as _}; +use futures_util::future::join_all; +use std::sync::Arc; + +const ENCRYPTION_KEY_NAME: &str = "encryption.apiserver.operator.openshift.io-key"; + +async fn update_encryption_config(namespace: &str, etcd_client: &Arc, config: &EncryptionConfiguration) -> Result<()> { + join_all( + etcd_client + .list_keys(&format!("secrets/{}/encryption-config", namespace).to_string()) + .await? + .into_iter() + .chain( + etcd_client + .list_keys(&format!("secrets/openshift-config-managed/encryption-config-{}", namespace).to_string()) + .await? + .into_iter(), + ) + .map(|key| async move { + let etcd_result = etcd_client + .get(key.clone()) + .await + .with_context(|| format!("getting key {:?}", key))? + .context("key disappeared")?; + let value: serde_json::Value = serde_yaml::from_slice(etcd_result.value.as_slice()) + .with_context(|| format!("deserializing value of key {:?}", key,))?; + let k8s_resource_location = K8sResourceLocation::try_from(&value)?; + + let mut secret = get_etcd_json(etcd_client, &k8s_resource_location) + .await? + .context("getting secret")?; + + let data = &mut secret + .pointer_mut("/data") + .context("no /data")? + .as_object_mut() + .context("data not an object")?; + + data.insert( + "encryption-config".to_string(), + serde_json::Value::Array( + format!("{}\n", serde_json::to_string(&config).context("serializing encryption-config")?) + .as_bytes() + .iter() + .map(|byte| serde_json::Value::Number(serde_json::Number::from(*byte))) + .collect(), + ), + ) + .context("could not find original encryption-config")?; + + put_etcd_yaml(etcd_client, &k8s_resource_location, secret).await?; + + Ok(()) + }), + ) + .await + .into_iter() + .collect::>>()?; + + Ok(()) +} + +pub(crate) async fn update_kube_apiserver_encryption_config( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, +) -> Result<()> { + if let Some(kube_encryption_config) = &encryption_customizations.kube_encryption_config { + update_encryption_config("openshift-kube-apiserver", etcd_client, &kube_encryption_config.config).await? + } + + Ok(()) +} + +pub(crate) async fn update_openshift_apiserver_encryption_config( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, +) -> Result<()> { + if let Some(openshift_encryption_config) = &encryption_customizations.openshift_encryption_config { + update_encryption_config("openshift-apiserver", etcd_client, &openshift_encryption_config.config).await? + } + + Ok(()) +} + +pub(crate) async fn update_oauth_apiserver_encryption_config( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, +) -> Result<()> { + if let Some(oauth_encryption_config) = &encryption_customizations.oauth_encryption_config { + update_encryption_config("openshift-oauth-apiserver", etcd_client, &oauth_encryption_config.config).await? + } + + Ok(()) +} + +async fn update_encryption_key(component: &str, etcd_client: &Arc, config: &EncryptionConfiguration) -> Result<()> { + join_all( + etcd_client + .list_keys(&format!("secrets/openshift-config-managed/encryption-key-{}", component).to_string()) + .await? + .into_iter() + .map(|key| async move { + let etcd_result = etcd_client + .get(key.clone()) + .await + .with_context(|| format!("getting key {:?}", key))? + .context("key disappeared")?; + let value: serde_json::Value = serde_yaml::from_slice(etcd_result.value.as_slice()) + .with_context(|| format!("deserializing value of key {:?}", key,))?; + let k8s_resource_location = K8sResourceLocation::try_from(&value)?; + + let mut secret = get_etcd_json(etcd_client, &k8s_resource_location) + .await? + .context("getting secret")?; + + let data = &mut secret + .pointer_mut("/data") + .context("no /data")? + .as_object_mut() + .context("data not an object")?; + + let (encryption_key, key_name) = match &config.resources[0].providers[0] { + Provider { + aesgcm: Some(aesgcm), + aescbc: None, + identity: _, + } => (aesgcm.keys[0].secret.clone(), aesgcm.keys[0].name.clone()), + Provider { + aesgcm: None, + aescbc: Some(aescbc), + identity: _, + } => (aescbc.keys[0].secret.clone(), aescbc.keys[0].name.clone()), + _ => bail!("unsupported provider"), + }; + + let encryption_key_base64 = base64_standard.encode(encryption_key.clone()); + + if *data.get(ENCRYPTION_KEY_NAME).context("cound not find encryption-key")?.to_string() != encryption_key_base64 { + data.insert( + ENCRYPTION_KEY_NAME.to_string(), + serde_json::Value::Array( + encryption_key + .iter() + .map(|byte| serde_json::Value::Number(serde_json::Number::from(*byte))) + .collect(), + ), + ) + .context("could not find original encryption-key")?; + + if key_name == key.rsplit('-').next().context("cound not rsplit key")? { + put_etcd_yaml(etcd_client, &k8s_resource_location, secret).await?; + } else { + let metadata = &mut secret + .pointer_mut("/metadata") + .context("no /metadata")? + .as_object_mut() + .context("metadata not an object")?; + metadata + .insert( + "name".to_string(), + serde_json::Value::String(format!("encryption-key-{}-{}", component, key_name)), + ) + .context("could not find original name")?; + + etcd_client + .put( + &(format!( + "/kubernetes.io/secrets/openshift-config-managed/encryption-key-{}-{}", + component, key_name + )), + serde_json::to_string(&secret).context("serializing value")?.as_bytes().to_vec(), + ) + .await; + etcd_client.delete(&key).await.context(format!("deleting {}", key))?; + } + } + + Ok(()) + }), + ) + .await + .into_iter() + .collect::>>()?; + + Ok(()) +} + +pub(crate) async fn update_kube_apiserver_encryption_key( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, +) -> Result<()> { + if let Some(kube_encryption_config) = &encryption_customizations.kube_encryption_config { + update_encryption_key("openshift-kube-apiserver", etcd_client, &kube_encryption_config.config).await? + } + + Ok(()) +} + +pub(crate) async fn update_openshift_apiserver_encryption_key( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, +) -> Result<()> { + if let Some(openshift_encryption_config) = &encryption_customizations.openshift_encryption_config { + update_encryption_key("openshift-apiserver", etcd_client, &openshift_encryption_config.config).await? + } + + Ok(()) +} + +pub(crate) async fn update_oauth_apiserver_encryption_key( + etcd_client: &Arc, + encryption_customizations: &EncryptionCustomizations, +) -> Result<()> { + if let Some(oauth_encryption_config) = &encryption_customizations.oauth_encryption_config { + update_encryption_key("openshift-oauth-apiserver", etcd_client, &oauth_encryption_config.config).await? + } + + Ok(()) +} diff --git a/src/ocp_postprocess/encryption_config/filesystem_rename.rs b/src/ocp_postprocess/encryption_config/filesystem_rename.rs new file mode 100644 index 00000000..8c0627bb --- /dev/null +++ b/src/ocp_postprocess/encryption_config/filesystem_rename.rs @@ -0,0 +1,37 @@ +use crate::config::EncryptionCustomizations; +use crate::file_utils::{self, commit_file}; +use anyhow::{self, Context, Result}; +use futures_util::future::join_all; +use std::path::Path; + +pub(crate) async fn fix_filesystem_kas_pods(encryption_customizations: &EncryptionCustomizations, dir: &Path) -> Result<()> { + if let Some(kube_encryption_config) = &encryption_customizations.kube_encryption_config { + join_all( + file_utils::globvec(dir, "**/kube-apiserver-pod-*/secrets/encryption-config/encryption-config")? + .into_iter() + .map(|file_path| { + let path = file_path.clone(); + let kube_encryption_config = kube_encryption_config.clone(); + tokio::spawn(async move { + let cloned_path = file_path.clone(); + async move { + commit_file(file_path, format!("{}\n", serde_json::to_string(&kube_encryption_config.config)?)) + .await + .context(format!("writing {:?}", cloned_path))?; + + anyhow::Ok(()) + } + .await + .context(format!("fixing {:?}", path)) + }) + }), + ) + .await + .into_iter() + .collect::, _>>()? + .into_iter() + .collect::, _>>()?; + } + + Ok(()) +} diff --git a/src/recert.rs b/src/recert.rs index 3f17c509..792a9df9 100644 --- a/src/recert.rs +++ b/src/recert.rs @@ -1,8 +1,13 @@ use crate::{ cluster_crypto::{crypto_utils::ensure_openssl_version, scanning, ClusterCryptoObjects}, - config::{ClusterCustomizations, CryptoCustomizations, RecertConfig}, + config::{ClusterCustomizations, CryptoCustomizations, EncryptionCustomizations, RecertConfig}, + encrypt::ResourceTransformers, k8s_etcd::InMemoryK8sEtcd, - ocp_postprocess::ocp_postprocess, + ocp_postprocess::{encryption_config, ocp_postprocess}, + recert::encrypt_utils::{ + build_decryption_transformers, build_encryption_customizations, build_encryption_transformers, get_apiserver_encryption_type, + is_encryption_enabled, + }, rsa_key_pool, server_ssh_keys, }; use anyhow::{Context, Result}; @@ -13,10 +18,12 @@ use self::timing::{combine_timings, FinalizeTiming, RecertifyTiming, RunTime, Ru pub(crate) mod timing; +mod encrypt_utils; + pub(crate) async fn run(recert_config: &RecertConfig, cluster_crypto: &mut ClusterCryptoObjects) -> Result { ensure_openssl_version().context("checking openssl version compatibility")?; - let in_memory_etcd_client = get_etcd_endpoint(recert_config).await?; + let (in_memory_etcd_client, encryption_customizations) = setup_etcd_client(recert_config).await?; let recertify_timing = if !recert_config.postprocess_only { recertify( @@ -34,6 +41,7 @@ pub(crate) async fn run(recert_config: &RecertConfig, cluster_crypto: &mut Clust Arc::clone(&in_memory_etcd_client), cluster_crypto, &recert_config.cluster_customizations, + encryption_customizations, recert_config.regenerate_server_ssh_keys.as_deref(), recert_config.dry_run, recert_config.etcd_defrag, @@ -44,18 +52,53 @@ pub(crate) async fn run(recert_config: &RecertConfig, cluster_crypto: &mut Clust Ok(combine_timings(recertify_timing, finalize_timing)) } -async fn get_etcd_endpoint(recert_config: &RecertConfig) -> Result> { - let in_memory_etcd_client = Arc::new(InMemoryK8sEtcd::new(match &recert_config.etcd_endpoint { - Some(etcd_endpoint) => Some( - EtcdClient::connect([etcd_endpoint.as_str()], None) - .await - .context("connecting to etcd")?, - ), - None => None, - })); +async fn setup_etcd_client(recert_config: &RecertConfig) -> Result<(Arc, Option)> { + let mut in_memory_etcd_client = get_etcd_endpoint(recert_config, None, None).await?; + + let mut encryption_customizations: Option = None; + + if is_encryption_enabled(&in_memory_etcd_client).await? { + let decrypt_resource_transformers = build_decryption_transformers(recert_config, &mut in_memory_etcd_client).await?; + + let encryption_type = get_apiserver_encryption_type(&in_memory_etcd_client).await?; + + log::info!("OpenShift etcd encryption type {} detected", encryption_type); + + let customizations = build_encryption_customizations(recert_config, encryption_type).await?; + let encrypt_resource_transformers = build_encryption_transformers(&customizations).await?; + + encryption_customizations = Some(customizations); + in_memory_etcd_client = get_etcd_endpoint( + recert_config, + Some(decrypt_resource_transformers.clone()), + Some(encrypt_resource_transformers.clone()), + ) + .await?; + } log::info!("Connected to etcd"); + Ok((in_memory_etcd_client, encryption_customizations)) +} + +async fn get_etcd_endpoint( + recert_config: &RecertConfig, + decrypt_resource_transformers: Option, + encrypt_resource_transformers: Option, +) -> Result> { + let in_memory_etcd_client = Arc::new(InMemoryK8sEtcd::new( + match &recert_config.etcd_endpoint { + Some(etcd_endpoint) => Some( + EtcdClient::connect([etcd_endpoint.as_str()], None) + .await + .context("connecting to etcd")?, + ), + None => None, + }, + decrypt_resource_transformers, + encrypt_resource_transformers, + )); + Ok(in_memory_etcd_client) } @@ -114,6 +157,7 @@ async fn finalize( in_memory_etcd_client: Arc, cluster_crypto: &mut ClusterCryptoObjects, cluster_customizations: &ClusterCustomizations, + encryption_customizations: Option, regenerate_server_ssh_keys: Option<&Path>, dry_run: bool, etcd_defrag: bool, @@ -134,6 +178,22 @@ async fn finalize( ocp_postprocess(&in_memory_etcd_client, cluster_customizations) .await .context("performing ocp specific post-processing")?; + + if let Some(encryption_customizations) = encryption_customizations { + encryption_config::rename_all( + &in_memory_etcd_client, + &encryption_customizations, + &cluster_customizations.dirs, + &cluster_customizations.files, + ) + .await + .context("renaming all")?; + + in_memory_etcd_client + .reencrypt_resources() + .await + .context("re-encrypting resources")?; + } } let ocp_postprocessing_run_time = RunTime::since_start(start); diff --git a/src/recert/encrypt_utils.rs b/src/recert/encrypt_utils.rs new file mode 100644 index 00000000..3a71f4bf --- /dev/null +++ b/src/recert/encrypt_utils.rs @@ -0,0 +1,270 @@ +use crate::cluster_crypto::locations::K8sResourceLocation; +use crate::config::{EncryptionCustomizations, RecertConfig}; +use crate::encrypt::{EncryptionConfiguration, ResourceTransformers}; +use crate::encrypt_config::EncryptionConfig; +use crate::file_utils::{self, read_file_to_string}; +use crate::k8s_etcd::get_etcd_json; +use crate::k8s_etcd::InMemoryK8sEtcd; +use anyhow::{ensure, Context, Result}; +use futures_util::Future; +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +use super::get_etcd_endpoint; + +pub(crate) async fn is_encryption_enabled(in_memory_etcd_client: &Arc) -> Result { + let k8s_location = K8sResourceLocation::new(None, "APIServer", "cluster", "config.openshift.io/v1"); + + let cluster = get_etcd_json(in_memory_etcd_client, &k8s_location) + .await? + .context(format!("could not get {}", k8s_location))?; + + if let Some(encryption_type) = cluster.pointer("/spec/encryption/type") { + let encryption_type = encryption_type.as_str().context("spec.encryption.type not a string")?; + + ensure!( + encryption_type == "aescbc" || encryption_type == "aesgcm", + format!( + "Unsupported encryption type {}, the supported encryption types are 'aescbc' and 'aesgcm'.", + encryption_type + ) + ); + + Ok(true) + } else { + Ok(false) + } +} + +async fn get_latest_encryption_config(recert_config: &RecertConfig) -> Result { + let all_encryption_config_files = &recert_config + .cluster_customizations + .dirs + .iter() + .map(|dir| file_utils::globvec(dir, "**/encryption-config/encryption-config")) + .collect::>>()? + .into_iter() + .flatten() + .collect::>(); + + // Get latest revision from kube-apiserver-pod-(\d+) in the file path + let regex = regex::Regex::new(r"kube-apiserver-pod-(\d+)").context("compiling regex")?; + let captures = &all_encryption_config_files + .iter() + .filter_map(|file_pathbuf| { + let file_path = file_pathbuf.to_str()?; + Some((regex.captures(file_path)?[1].parse::().ok()?, file_pathbuf)) + }) + .collect::>(); + let (_, latest_encryption_config) = captures + .iter() + .max_by_key(|(revision, _pathbuf)| revision) + .context("no kube-apiserver-pod-* found")?; + + let latest_encryption_config_contents = &read_file_to_string(latest_encryption_config) + .await + .context("reading latest encryption-config")?; + + Ok(latest_encryption_config_contents.to_string()) +} + +pub(crate) async fn get_apiserver_encryption_type(in_memory_etcd_client: &Arc) -> Result { + let k8s_location = K8sResourceLocation::new(None, "APIServer", "cluster", "config.openshift.io/v1"); + + let apiserver = get_etcd_json(in_memory_etcd_client, &k8s_location) + .await? + .context(format!("could not get {}", k8s_location))?; + + let encryption_type = apiserver + .pointer("/spec/encryption/type") + .context("no /spec/encryption/type")? + .as_str() + .context("spec.encryption.type not a string")?; + + Ok(encryption_type.to_string()) +} + +pub(crate) async fn build_decryption_transformers( + recert_config: &RecertConfig, + in_memory_etcd_client: &mut Arc, +) -> Result { + // Auto-discover seed encryption configs + let contents = get_latest_encryption_config(recert_config).await?; + let encryption_config = EncryptionConfiguration::parse_from_file(contents.into()).context("could not parse encryption-config")?; + + let mut decrypt_resource_transformers = + ResourceTransformers::parse_from_encryption_configuration(encryption_config.clone()).context("parsing encryption configuration")?; + + // Use kube-apiserver encryption-config to decrypt the OpenShift Secrets + *in_memory_etcd_client = get_etcd_endpoint(recert_config, Some(decrypt_resource_transformers.clone()), None).await?; + + // Add OpenShift resources to kube-apiserver resource transformers + decrypt_resource_transformers = add_openshift_resource_transformers(in_memory_etcd_client, decrypt_resource_transformers).await?; + + Ok(decrypt_resource_transformers) +} + +async fn get_encryption_config( + config_option: &Option, + default_fn: F, + encryption_type: String, +) -> anyhow::Result +where + F: Fn(String) -> Fut, + Fut: Future>, +{ + if let Some(config) = config_option { + let mut encryption_config = config.config.clone(); + encryption_config.remove_redundant_providers(); + Ok(encryption_config) + } else { + default_fn(encryption_type).await + } +} + +pub(crate) async fn build_encryption_customizations( + recert_config: &RecertConfig, + encryption_type: String, +) -> Result { + let kube_encryption_config = get_encryption_config( + &recert_config.encryption_customizations.kube_encryption_config, + EncryptionConfiguration::new_kube_apiserver_config, + encryption_type.clone(), + ) + .await?; + + let openshift_encryption_config = get_encryption_config( + &recert_config.encryption_customizations.openshift_encryption_config, + EncryptionConfiguration::new_openshift_apiserver_config, + encryption_type.clone(), + ) + .await?; + + let oauth_encryption_config = get_encryption_config( + &recert_config.encryption_customizations.oauth_encryption_config, + EncryptionConfiguration::new_oauth_apiserver_config, + encryption_type.clone(), + ) + .await?; + + Ok(EncryptionCustomizations { + kube_encryption_config: Some(EncryptionConfig::new(kube_encryption_config)), + openshift_encryption_config: Some(EncryptionConfig::new(openshift_encryption_config)), + oauth_encryption_config: Some(EncryptionConfig::new(oauth_encryption_config)), + }) +} + +pub(crate) async fn build_encryption_transformers(encryption_customizations: &EncryptionCustomizations) -> Result { + let kube_encryption_config = match &encryption_customizations.kube_encryption_config { + Some(config) => &config.config, + None => return Err(anyhow::anyhow!("Missing kube encryption config")), + }; + + let openshift_encryption_config = match &encryption_customizations.openshift_encryption_config { + Some(config) => &config.config, + None => return Err(anyhow::anyhow!("Missing openshift encryption config")), + }; + + let oauth_encryption_config = match &encryption_customizations.oauth_encryption_config { + Some(config) => &config.config, + None => return Err(anyhow::anyhow!("Missing oauth encryption config")), + }; + + let mut encrypt_resource_transformers = ResourceTransformers::parse_from_encryption_configuration(kube_encryption_config.clone()) + .context("parsing kube encryption configuration")?; + + let openshift_resource_transformers = ResourceTransformers::parse_from_encryption_configuration(openshift_encryption_config.clone()) + .context("parsing openshift encryption configuration")?; + + let oauth_resource_transformers = ResourceTransformers::parse_from_encryption_configuration(oauth_encryption_config.clone()) + .context("parsing oauth encryption configuration")?; + + let size_before = encrypt_resource_transformers.resource_to_prefix_transformers.len() + + openshift_resource_transformers.resource_to_prefix_transformers.len() + + oauth_resource_transformers.resource_to_prefix_transformers.len(); + + encrypt_resource_transformers.resource_to_prefix_transformers.extend( + openshift_resource_transformers + .resource_to_prefix_transformers + .into_iter() + .chain(oauth_resource_transformers.resource_to_prefix_transformers), + ); + + let size_after = encrypt_resource_transformers.resource_to_prefix_transformers.len(); + + ensure!(size_before == size_after, "encryption configurations contain overlapping resources"); + + Ok(encrypt_resource_transformers) +} + +async fn add_openshift_resource_transformers( + in_memory_etcd_client: &Arc, + resource_transformers: ResourceTransformers, +) -> Result { + let resource_to_prefix_transformers: HashMap<_, _> = resource_transformers.resource_to_prefix_transformers; + + let apiserver_location = K8sResourceLocation::new(Some("openshift-apiserver"), "Secret", "encryption-config", "v1"); + let resource_to_prefix_transformers = if let Some(apiserver_resource_transformers) = + get_openshift_resource_transformers(in_memory_etcd_client, &apiserver_location).await? + { + resource_to_prefix_transformers + .clone() + .into_iter() + .chain(apiserver_resource_transformers.resource_to_prefix_transformers) + .collect() + } else { + resource_to_prefix_transformers + }; + + let oauth_apiserver_location = K8sResourceLocation::new(Some("openshift-oauth-apiserver"), "Secret", "encryption-config", "v1"); + let resource_to_prefix_transformers = if let Some(oauth_apiserver_resource_transformers) = + get_openshift_resource_transformers(in_memory_etcd_client, &oauth_apiserver_location).await? + { + resource_to_prefix_transformers + .clone() + .into_iter() + .chain(oauth_apiserver_resource_transformers.resource_to_prefix_transformers) + .collect() + } else { + resource_to_prefix_transformers + }; + + Ok(ResourceTransformers { + resource_to_prefix_transformers, + }) +} + +async fn get_openshift_resource_transformers( + in_memory_etcd_client: &Arc, + k8s_location: &K8sResourceLocation, +) -> Result> { + let secret = get_etcd_json(in_memory_etcd_client, k8s_location) + .await? + .context(format!("could not get {}", k8s_location))?; + let data = secret + .pointer("/data") + .context("no /data")? + .as_object() + .context("data not an object")?; + + if let Some(config) = data.get("encryption-config") { + let config = String::from_utf8( + config + .as_array() + .context("not an array")? + .iter() + .filter_map(|v| v.as_u64().map(|b| b as u8)) + .collect(), + )?; + + let encryption_config = + EncryptionConfiguration::parse_from_file(config.as_bytes().to_vec()).context(format!("could not parse {}", k8s_location))?; + + return Ok(Some( + ResourceTransformers::parse_from_encryption_configuration(encryption_config) + .context(format!("could not parse transformers from {}", k8s_location))?, + )); + } + + Ok(None) +} diff --git a/src/rules.rs b/src/rules.rs index b123a9c1..0d3ce70b 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -19,6 +19,7 @@ lazy_static! { "alertmanager.yaml.gz", "entitlement.pem", "entitlement-key.pem", + "encryption.apiserver.operator.openshift.io-key", ] .into_iter() .map(str::to_string) diff --git a/vendor/aead/.cargo-checksum.json b/vendor/aead/.cargo-checksum.json new file mode 100644 index 00000000..ce583216 --- /dev/null +++ b/vendor/aead/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8870cb71cd8b46213591c7a4ee7ad80985600bd00c9f88331f825407498a00a7","Cargo.toml":"bf935971de51d6c168946e1822e1e4c3267aad0e1ae6e036b4e5baeb6d81a4be","LICENSE-APACHE":"b1cf9a3333ca78152b859012cd4a804156e5243e9ca20ad1df7327ba5ea7405c","LICENSE-MIT":"949ab7b3e7140fee216f06fe3a2bd67d68dd511f8ea73c1e01c98cb348e9c8ae","README.md":"8e195a2c3d0437b035de4640adabc6fb29ed91d814ec5073e7c2ae1a4d988748","src/dev.rs":"8a615fadb1236158cea9fde4ea96e8bb2ced4757c43b829c23eb143fc816d894","src/lib.rs":"477a851e2666a29dc3a724a75b7558d32d9ed7584364e1567dc6746c32a74fc5","src/stream.rs":"0b89b1e648972b2434cfed6556302f28ad2d8bdc11434f6905354167bf8a38e7"},"package":"d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"} \ No newline at end of file diff --git a/vendor/aead/CHANGELOG.md b/vendor/aead/CHANGELOG.md new file mode 100644 index 00000000..d5413f8e --- /dev/null +++ b/vendor/aead/CHANGELOG.md @@ -0,0 +1,106 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.5.2 (2023-04-02) +### Added +- `arrayvec` feature ([#1219]) + +[#1219]: https://github.com/RustCrypto/traits/pull/1219 + +## 0.5.1 (2022-08-09) +### Added +- `AeadCore::generate_nonce` ([#1073]) + +[#1073]: https://github.com/RustCrypto/traits/pull/1073 + +## 0.5.0 (2022-07-23) +### Added +- Optional support for `BytesMut` as a `Buffer` ([#956]) +- `getrandom` feature ([#1042]) + +### Changed +- Replace `NewAead` trait with `KeyInit` trait from `crypto-common` ([#1033]) +- Rust 2021 edition upgrade; MSRV 1.56+ ([#1044]) + +[#956]: https://github.com/RustCrypto/traits/pull/956 +[#1033]: https://github.com/RustCrypto/traits/pull/1033 +[#1042]: https://github.com/RustCrypto/traits/pull/1042 +[#1044]: https://github.com/RustCrypto/traits/pull/1044 + +## 0.4.3 (2021-08-29) +### Added +- `Result` type alias ([#725]) + +[#725]: https://github.com/RustCrypto/traits/pull/725 + +## 0.4.2 (2021-07-12) +### Added +- Re-export `rand_core` ([#682]) + +[#682]: https://github.com/RustCrypto/traits/pull/682 + +## 0.4.1 (2021-05-03) +### Changed +- Bump `heapless` dependency to v0.7 ([#628]) + +[#628]: https://github.com/RustCrypto/traits/pull/628 + +## 0.4.0 (2021-02-05) [YANKED] +### Added +- `stream` module ([#436], [#445], [#447]) +- `NewAead::generate_key` method gated under `rand_core` feature ([#513]) + +### Changed +- Extract `AeadCore` trait ([#508]) +- Rename `NewAead::new_var` to `::new_from_slice` ([#512]) +- Disable alloc by default ([#514]) +- Bump `heapless` dependency to v0.6 ([#522]) + +[#436]: https://github.com/RustCrypto/traits/pull/436 +[#445]: https://github.com/RustCrypto/traits/pull/445 +[#447]: https://github.com/RustCrypto/traits/pull/447 +[#508]: https://github.com/RustCrypto/traits/pull/508 +[#512]: https://github.com/RustCrypto/traits/pull/512 +[#513]: https://github.com/RustCrypto/traits/pull/513 +[#514]: https://github.com/RustCrypto/traits/pull/514 +[#522]: https://github.com/RustCrypto/traits/pull/522 + +## 0.3.2 (2020-07-01) +### Added +- `dev` module ([#194]) + +[#194]: https://github.com/RustCrypto/traits/pull/194 + +## 0.3.1 (2020-06-12) +### Added +- `NewAead::new_varkey` method ([#191]) + +[#191]: https://github.com/RustCrypto/traits/pull/191 + +## 0.3.0 (2020-06-04) +### Added +- Type aliases for `Key`, `Nonce`, and `Tag` ([#125]) +- Optional `std` feature ([#63]) + +### Changed +- `NewAead` now borrows the key ([#124]) +- Split `Aead`/`AeadMut` into `AeadInPlace`/`AeadMutInPlace` ([#120]) +- Bump `generic-array` dependency to v0.14 ([#95]) + +[#125]: https://github.com/RustCrypto/traits/pull/125 +[#124]: https://github.com/RustCrypto/traits/pull/124 +[#120]: https://github.com/RustCrypto/traits/pull/120 +[#95]: https://github.com/RustCrypto/traits/pull/95 +[#63]: https://github.com/RustCrypto/traits/pull/63 + +## 0.2.0 (2019-11-17) + +## 0.1.2 (2019-11-17) [YANKED] + +## 0.1.1 (2019-08-30) + +## 0.1.0 (2019-08-29) diff --git a/vendor/aead/Cargo.toml b/vendor/aead/Cargo.toml new file mode 100644 index 00000000..91276744 --- /dev/null +++ b/vendor/aead/Cargo.toml @@ -0,0 +1,81 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "aead" +version = "0.5.2" +authors = ["RustCrypto Developers"] +description = """ +Traits for Authenticated Encryption with Associated Data (AEAD) algorithms, +such as AES-GCM as ChaCha20Poly1305, which provide a high-level API +""" +documentation = "https://docs.rs/aead" +readme = "README.md" +keywords = [ + "crypto", + "encryption", +] +categories = [ + "cryptography", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/traits" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.arrayvec] +version = "0.7" +optional = true +default-features = false + +[dependencies.blobby] +version = "0.3" +optional = true + +[dependencies.bytes] +version = "1" +optional = true +default-features = false + +[dependencies.crypto-common] +version = "0.1.4" + +[dependencies.generic-array] +version = "0.14" +default-features = false + +[dependencies.heapless] +version = "0.7" +optional = true +default-features = false + +[features] +alloc = [] +default = ["rand_core"] +dev = ["blobby"] +getrandom = [ + "crypto-common/getrandom", + "rand_core", +] +rand_core = ["crypto-common/rand_core"] +std = [ + "alloc", + "crypto-common/std", +] +stream = [] diff --git a/vendor/aead/LICENSE-APACHE b/vendor/aead/LICENSE-APACHE new file mode 100644 index 00000000..7650239c --- /dev/null +++ b/vendor/aead/LICENSE-APACHE @@ -0,0 +1,202 @@ + 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 [yyyy] [name of copyright owner] + +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/vendor/aead/LICENSE-MIT b/vendor/aead/LICENSE-MIT new file mode 100644 index 00000000..88e64ca7 --- /dev/null +++ b/vendor/aead/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2019 The RustCrypto Project Developers +Copyright (c) 2019 MobileCoin, LLC + +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/vendor/aead/README.md b/vendor/aead/README.md new file mode 100644 index 00000000..ff1a580a --- /dev/null +++ b/vendor/aead/README.md @@ -0,0 +1,65 @@ +# RustCrypto: Authenticated Encryption with Additional Data Traits + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] +[![Build Status][build-image]][build-link] + +This crate provides an abstract interface for [AEAD] ciphers, which guarantee +both confidentiality and integrity, even from a powerful attacker who is +able to execute [chosen-ciphertext attacks]. The resulting security property, +[ciphertext indistinguishability], is considered a basic requirement for +modern cryptographic implementations. + +See [RustCrypto/AEADs] for cipher implementations which use this trait. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +Rust **1.56** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/aead.svg +[crate-link]: https://crates.io/crates/aead +[docs-image]: https://docs.rs/aead/badge.svg +[docs-link]: https://docs.rs/aead/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260038-AEADs +[build-image]: https://github.com/RustCrypto/traits/workflows/aead/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/traits/actions?query=workflow%3Aaead + +[//]: # (general links) + +[AEAD]: https://en.wikipedia.org/wiki/Authenticated_encryption +[chosen-ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack +[ciphertext indistinguishability]: https://en.wikipedia.org/wiki/Ciphertext_indistinguishability +[RustCrypto/AEADs]: https://github.com/RustCrypto/AEADs diff --git a/vendor/aead/src/dev.rs b/vendor/aead/src/dev.rs new file mode 100644 index 00000000..a0fc7db2 --- /dev/null +++ b/vendor/aead/src/dev.rs @@ -0,0 +1,78 @@ +//! Development-related functionality +pub use blobby; + +/// Define AEAD test +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! new_test { + ($name:ident, $test_name:expr, $cipher:ty $(,)?) => { + #[test] + fn $name() { + use aead::{ + dev::blobby::Blob6Iterator, + generic_array::{typenum::Unsigned, GenericArray}, + Aead, KeyInit, Payload, + }; + + fn run_test( + key: &[u8], + nonce: &[u8], + aad: &[u8], + pt: &[u8], + ct: &[u8], + pass: bool, + ) -> Result<(), &'static str> { + let key = key.try_into().map_err(|_| "wrong key size")?; + let cipher = <$cipher>::new(key); + let nonce = nonce.try_into().map_err(|_| "wrong nonce size")?; + + if !pass { + let res = cipher.decrypt(nonce, Payload { aad: aad, msg: ct }); + if res.is_ok() { + return Err("decryption must return error"); + } + return Ok(()); + } + + let res = cipher + .encrypt(nonce, Payload { aad: aad, msg: pt }) + .map_err(|_| "encryption failure")?; + if res != ct { + return Err("encrypted data is different from target ciphertext"); + } + let res = cipher + .decrypt(nonce, Payload { aad: aad, msg: ct }) + .map_err(|_| "decryption failure")?; + if res != pt { + return Err("decrypted data is different from target plaintext"); + } + Ok(()) + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + for (i, row) in Blob6Iterator::new(data).unwrap().enumerate() { + let [key, nonce, aad, pt, ct, status] = row.unwrap(); + let pass = match status[0] { + 0 => false, + 1 => true, + _ => panic!("invalid value for pass flag"), + }; + if let Err(reason) = run_test(key, nonce, aad, pt, ct, pass) { + panic!( + "\n\ + Failed test №{}\n\ + reason: \t{:?}\n\ + key:\t{:?}\n\ + nonce:\t{:?}\n\ + aad:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n\ + pass:\t{}\n\ + ", + i, reason, key, nonce, aad, pt, ct, pass, + ); + } + } + } + }; +} diff --git a/vendor/aead/src/lib.rs b/vendor/aead/src/lib.rs new file mode 100644 index 00000000..c5856a07 --- /dev/null +++ b/vendor/aead/src/lib.rs @@ -0,0 +1,591 @@ +//! [Authenticated Encryption with Associated Data] (AEAD) traits +//! +//! This crate provides an abstract interface for AEAD ciphers, which guarantee +//! both confidentiality and integrity, even from a powerful attacker who is +//! able to execute [chosen-ciphertext attacks]. The resulting security property, +//! [ciphertext indistinguishability], is considered a basic requirement for +//! modern cryptographic implementations. +//! +//! See [RustCrypto/AEADs] for cipher implementations which use this trait. +//! +//! [Authenticated Encryption with Associated Data]: https://en.wikipedia.org/wiki/Authenticated_encryption +//! [chosen-ciphertext attacks]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack +//! [ciphertext indistinguishability]: https://en.wikipedia.org/wiki/Ciphertext_indistinguishability +//! [RustCrypto/AEADs]: https://github.com/RustCrypto/AEADs + +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn(clippy::unwrap_used, missing_docs, rust_2018_idioms)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "dev")] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +pub mod dev; + +#[cfg(feature = "stream")] +#[cfg_attr(docsrs, doc(cfg(feature = "stream")))] +pub mod stream; + +pub use crypto_common::{Key, KeyInit, KeySizeUser}; +pub use generic_array::{self, typenum::consts}; + +#[cfg(feature = "arrayvec")] +#[cfg_attr(docsrs, doc(cfg(feature = "arrayvec")))] +pub use arrayvec; + +#[cfg(feature = "bytes")] +#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))] +pub use bytes; + +#[cfg(feature = "getrandom")] +#[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))] +pub use crypto_common::rand_core::OsRng; + +#[cfg(feature = "heapless")] +#[cfg_attr(docsrs, doc(cfg(feature = "heapless")))] +pub use heapless; + +#[cfg(feature = "rand_core")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] +pub use crypto_common::rand_core; + +use core::fmt; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +#[cfg(feature = "bytes")] +use bytes::BytesMut; + +#[cfg(feature = "rand_core")] +use rand_core::{CryptoRng, RngCore}; + +/// Error type. +/// +/// This type is deliberately opaque as to avoid potential side-channel +/// leakage (e.g. padding oracle). +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Error; + +/// Result type alias with [`Error`]. +pub type Result = core::result::Result; + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aead::Error") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +/// Nonce: single-use value for ensuring ciphertexts are unique +pub type Nonce = GenericArray::NonceSize>; + +/// Tag: authentication code which ensures ciphertexts are authentic +pub type Tag = GenericArray::TagSize>; + +/// Authenticated Encryption with Associated Data (AEAD) algorithm core trait. +/// +/// Defines nonce, tag, and overhead sizes that are consumed by various other +/// `Aead*` traits. +pub trait AeadCore { + /// The length of a nonce. + type NonceSize: ArrayLength; + + /// The maximum length of the nonce. + type TagSize: ArrayLength; + + /// The upper bound amount of additional space required to support a + /// ciphertext vs. a plaintext. + type CiphertextOverhead: ArrayLength + Unsigned; + + /// Generate a random nonce for this AEAD algorithm. + /// + /// AEAD algorithms accept a parameter to encryption/decryption called + /// a "nonce" which must be unique every time encryption is performed and + /// never repeated for the same key. The nonce is often prepended to the + /// ciphertext. The nonce used to produce a given ciphertext must be passed + /// to the decryption function in order for it to decrypt correctly. + /// + /// Nonces don't necessarily have to be random, but it is one strategy + /// which is implemented by this function. + /// + /// # ⚠️Security Warning + /// + /// AEAD algorithms often fail catastrophically if nonces are ever repeated + /// (with SIV modes being an exception). + /// + /// Using random nonces runs the risk of repeating them unless the nonce + /// size is particularly large (e.g. 192-bit extended nonces used by the + /// `XChaCha20Poly1305` and `XSalsa20Poly1305` constructions. + /// + /// [NIST SP 800-38D] recommends the following: + /// + /// > The total number of invocations of the authenticated encryption + /// > function shall not exceed 2^32, including all IV lengths and all + /// > instances of the authenticated encryption function with the given key. + /// + /// Following this guideline, only 4,294,967,296 messages with random + /// nonces can be encrypted under a given key. While this bound is high, + /// it's possible to encounter in practice, and systems which might + /// reach it should consider alternatives to purely random nonces, like + /// a counter or a combination of a random nonce + counter. + /// + /// See the [`stream`] module for a ready-made implementation of the latter. + /// + /// [NIST SP 800-38D]: https://csrc.nist.gov/publications/detail/sp/800-38d/final + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + fn generate_nonce(mut rng: impl CryptoRng + RngCore) -> Nonce + where + Nonce: Default, + { + let mut nonce = Nonce::::default(); + rng.fill_bytes(&mut nonce); + nonce + } +} + +/// Authenticated Encryption with Associated Data (AEAD) algorithm. +/// +/// This trait is intended for use with stateless AEAD algorithms. The +/// [`AeadMut`] trait provides a stateful interface. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub trait Aead: AeadCore { + /// Encrypt the given plaintext payload, and return the resulting + /// ciphertext as a vector of bytes. + /// + /// The [`Payload`] type can be used to provide Additional Associated Data + /// (AAD) along with the message: this is an optional bytestring which is + /// not encrypted, but *is* authenticated along with the message. Failure + /// to pass the same AAD that was used during encryption will cause + /// decryption to fail, which is useful if you would like to "bind" the + /// ciphertext to some other identifier, like a digital signature key + /// or other identifier. + /// + /// If you don't care about AAD and just want to encrypt a plaintext + /// message, `&[u8]` will automatically be coerced into a `Payload`: + /// + /// ```nobuild + /// let plaintext = b"Top secret message, handle with care"; + /// let ciphertext = cipher.encrypt(nonce, plaintext); + /// ``` + /// + /// The default implementation assumes a postfix tag (ala AES-GCM, + /// AES-GCM-SIV, ChaCha20Poly1305). [`Aead`] implementations which do not + /// use a postfix tag will need to override this to correctly assemble the + /// ciphertext message. + fn encrypt<'msg, 'aad>( + &self, + nonce: &Nonce, + plaintext: impl Into>, + ) -> Result>; + + /// Decrypt the given ciphertext slice, and return the resulting plaintext + /// as a vector of bytes. + /// + /// See notes on [`Aead::encrypt()`] about allowable message payloads and + /// Associated Additional Data (AAD). + /// + /// If you have no AAD, you can call this as follows: + /// + /// ```nobuild + /// let ciphertext = b"..."; + /// let plaintext = cipher.decrypt(nonce, ciphertext)?; + /// ``` + /// + /// The default implementation assumes a postfix tag (ala AES-GCM, + /// AES-GCM-SIV, ChaCha20Poly1305). [`Aead`] implementations which do not + /// use a postfix tag will need to override this to correctly parse the + /// ciphertext message. + fn decrypt<'msg, 'aad>( + &self, + nonce: &Nonce, + ciphertext: impl Into>, + ) -> Result>; +} + +/// Stateful Authenticated Encryption with Associated Data algorithm. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub trait AeadMut: AeadCore { + /// Encrypt the given plaintext slice, and return the resulting ciphertext + /// as a vector of bytes. + /// + /// See notes on [`Aead::encrypt()`] about allowable message payloads and + /// Associated Additional Data (AAD). + fn encrypt<'msg, 'aad>( + &mut self, + nonce: &Nonce, + plaintext: impl Into>, + ) -> Result>; + + /// Decrypt the given ciphertext slice, and return the resulting plaintext + /// as a vector of bytes. + /// + /// See notes on [`Aead::encrypt()`] and [`Aead::decrypt()`] about allowable + /// message payloads and Associated Additional Data (AAD). + fn decrypt<'msg, 'aad>( + &mut self, + nonce: &Nonce, + ciphertext: impl Into>, + ) -> Result>; +} + +/// Implement the `decrypt_in_place` method on [`AeadInPlace`] and +/// [`AeadMutInPlace]`, using a macro to gloss over the `&self` vs `&mut self`. +/// +/// Assumes a postfix authentication tag. AEAD ciphers which do not use a +/// postfix authentication tag will need to define their own implementation. +macro_rules! impl_decrypt_in_place { + ($aead:expr, $nonce:expr, $aad:expr, $buffer:expr) => {{ + if $buffer.len() < Self::TagSize::to_usize() { + return Err(Error); + } + + let tag_pos = $buffer.len() - Self::TagSize::to_usize(); + let (msg, tag) = $buffer.as_mut().split_at_mut(tag_pos); + $aead.decrypt_in_place_detached($nonce, $aad, msg, Tag::::from_slice(tag))?; + $buffer.truncate(tag_pos); + Ok(()) + }}; +} + +/// In-place stateless AEAD trait. +/// +/// This trait is both object safe and has no dependencies on `alloc` or `std`. +pub trait AeadInPlace: AeadCore { + /// Encrypt the given buffer containing a plaintext message in-place. + /// + /// The buffer must have sufficient capacity to store the ciphertext + /// message, which will always be larger than the original plaintext. + /// The exact size needed is cipher-dependent, but generally includes + /// the size of an authentication tag. + /// + /// Returns an error if the buffer has insufficient capacity to store the + /// resulting ciphertext message. + fn encrypt_in_place( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?; + buffer.extend_from_slice(tag.as_slice())?; + Ok(()) + } + + /// Encrypt the data in-place, returning the authentication tag + fn encrypt_in_place_detached( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + ) -> Result>; + + /// Decrypt the message in-place, returning an error in the event the + /// provided authentication tag does not match the given ciphertext. + /// + /// The buffer will be truncated to the length of the original plaintext + /// message upon success. + fn decrypt_in_place( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + impl_decrypt_in_place!(self, nonce, associated_data, buffer) + } + + /// Decrypt the message in-place, returning an error in the event the provided + /// authentication tag does not match the given ciphertext (i.e. ciphertext + /// is modified/unauthentic) + fn decrypt_in_place_detached( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + tag: &Tag, + ) -> Result<()>; +} + +/// In-place stateful AEAD trait. +/// +/// This trait is both object safe and has no dependencies on `alloc` or `std`. +pub trait AeadMutInPlace: AeadCore { + /// Encrypt the given buffer containing a plaintext message in-place. + /// + /// The buffer must have sufficient capacity to store the ciphertext + /// message, which will always be larger than the original plaintext. + /// The exact size needed is cipher-dependent, but generally includes + /// the size of an authentication tag. + /// + /// Returns an error if the buffer has insufficient capacity to store the + /// resulting ciphertext message. + fn encrypt_in_place( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut impl Buffer, + ) -> Result<()> { + let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?; + buffer.extend_from_slice(tag.as_slice())?; + Ok(()) + } + + /// Encrypt the data in-place, returning the authentication tag + fn encrypt_in_place_detached( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + ) -> Result>; + + /// Decrypt the message in-place, returning an error in the event the + /// provided authentication tag does not match the given ciphertext. + /// + /// The buffer will be truncated to the length of the original plaintext + /// message upon success. + fn decrypt_in_place( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut impl Buffer, + ) -> Result<()> { + impl_decrypt_in_place!(self, nonce, associated_data, buffer) + } + + /// Decrypt the data in-place, returning an error in the event the provided + /// authentication tag does not match the given ciphertext (i.e. ciphertext + /// is modified/unauthentic) + fn decrypt_in_place_detached( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + tag: &Tag, + ) -> Result<()>; +} + +#[cfg(feature = "alloc")] +impl Aead for Alg { + fn encrypt<'msg, 'aad>( + &self, + nonce: &Nonce, + plaintext: impl Into>, + ) -> Result> { + let payload = plaintext.into(); + let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize()); + buffer.extend_from_slice(payload.msg); + self.encrypt_in_place(nonce, payload.aad, &mut buffer)?; + Ok(buffer) + } + + fn decrypt<'msg, 'aad>( + &self, + nonce: &Nonce, + ciphertext: impl Into>, + ) -> Result> { + let payload = ciphertext.into(); + let mut buffer = Vec::from(payload.msg); + self.decrypt_in_place(nonce, payload.aad, &mut buffer)?; + Ok(buffer) + } +} + +#[cfg(feature = "alloc")] +impl AeadMut for Alg { + fn encrypt<'msg, 'aad>( + &mut self, + nonce: &Nonce, + plaintext: impl Into>, + ) -> Result> { + let payload = plaintext.into(); + let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize()); + buffer.extend_from_slice(payload.msg); + self.encrypt_in_place(nonce, payload.aad, &mut buffer)?; + Ok(buffer) + } + + fn decrypt<'msg, 'aad>( + &mut self, + nonce: &Nonce, + ciphertext: impl Into>, + ) -> Result> { + let payload = ciphertext.into(); + let mut buffer = Vec::from(payload.msg); + self.decrypt_in_place(nonce, payload.aad, &mut buffer)?; + Ok(buffer) + } +} + +impl AeadMutInPlace for Alg { + fn encrypt_in_place( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut impl Buffer, + ) -> Result<()> { + ::encrypt_in_place(self, nonce, associated_data, buffer) + } + + fn encrypt_in_place_detached( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + ) -> Result> { + ::encrypt_in_place_detached(self, nonce, associated_data, buffer) + } + + fn decrypt_in_place( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut impl Buffer, + ) -> Result<()> { + ::decrypt_in_place(self, nonce, associated_data, buffer) + } + + fn decrypt_in_place_detached( + &mut self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + tag: &Tag, + ) -> Result<()> { + ::decrypt_in_place_detached(self, nonce, associated_data, buffer, tag) + } +} + +/// AEAD payloads (message + AAD). +/// +/// Combination of a message (plaintext or ciphertext) and +/// "additional associated data" (AAD) to be authenticated (in cleartext) +/// along with the message. +/// +/// If you don't care about AAD, you can pass a `&[u8]` as the payload to +/// `encrypt`/`decrypt` and it will automatically be coerced to this type. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub struct Payload<'msg, 'aad> { + /// Message to be encrypted/decrypted + pub msg: &'msg [u8], + + /// Optional "additional associated data" to authenticate along with + /// this message. If AAD is provided at the time the message is encrypted, + /// the same AAD *MUST* be provided at the time the message is decrypted, + /// or decryption will fail. + pub aad: &'aad [u8], +} + +#[cfg(feature = "alloc")] +impl<'msg, 'aad> From<&'msg [u8]> for Payload<'msg, 'aad> { + fn from(msg: &'msg [u8]) -> Self { + Self { msg, aad: b"" } + } +} + +/// In-place encryption/decryption byte buffers. +/// +/// This trait defines the set of methods needed to support in-place operations +/// on a `Vec`-like data type. +pub trait Buffer: AsRef<[u8]> + AsMut<[u8]> { + /// Get the length of the buffer + fn len(&self) -> usize { + self.as_ref().len() + } + + /// Is the buffer empty? + fn is_empty(&self) -> bool { + self.as_ref().is_empty() + } + + /// Extend this buffer from the given slice + fn extend_from_slice(&mut self, other: &[u8]) -> Result<()>; + + /// Truncate this buffer to the given size + fn truncate(&mut self, len: usize); +} + +#[cfg(feature = "alloc")] +impl Buffer for Vec { + fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> { + Vec::extend_from_slice(self, other); + Ok(()) + } + + fn truncate(&mut self, len: usize) { + Vec::truncate(self, len); + } +} + +#[cfg(feature = "bytes")] +impl Buffer for BytesMut { + fn len(&self) -> usize { + BytesMut::len(self) + } + + fn is_empty(&self) -> bool { + BytesMut::is_empty(self) + } + + fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> { + BytesMut::extend_from_slice(self, other); + Ok(()) + } + + fn truncate(&mut self, len: usize) { + BytesMut::truncate(self, len); + } +} + +#[cfg(feature = "arrayvec")] +impl Buffer for arrayvec::ArrayVec { + fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> { + arrayvec::ArrayVec::try_extend_from_slice(self, other).map_err(|_| Error) + } + + fn truncate(&mut self, len: usize) { + arrayvec::ArrayVec::truncate(self, len); + } +} + +#[cfg(feature = "heapless")] +impl Buffer for heapless::Vec { + fn extend_from_slice(&mut self, other: &[u8]) -> Result<()> { + heapless::Vec::extend_from_slice(self, other).map_err(|_| Error) + } + + fn truncate(&mut self, len: usize) { + heapless::Vec::truncate(self, len); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Ensure that `AeadInPlace` is object-safe + #[allow(dead_code)] + type DynAeadInPlace = + dyn AeadInPlace; + + /// Ensure that `AeadMutInPlace` is object-safe + #[allow(dead_code)] + type DynAeadMutInPlace = + dyn AeadMutInPlace; +} diff --git a/vendor/aead/src/stream.rs b/vendor/aead/src/stream.rs new file mode 100644 index 00000000..6b38d43f --- /dev/null +++ b/vendor/aead/src/stream.rs @@ -0,0 +1,542 @@ +//! Streaming AEAD support. +//! +//! Implementation of the STREAM online authenticated encryption construction +//! as described in the paper +//! [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]. +//! +//! ## About +//! +//! The STREAM construction supports encrypting/decrypting sequences of AEAD +//! message segments, which is useful in cases where the overall message is too +//! large to fit in a single buffer and needs to be processed incrementally. +//! +//! STREAM defends against reordering and truncation attacks which are common +//! in naive schemes which attempt to provide these properties, and is proven +//! to meet the security definition of "nonce-based online authenticated +//! encryption" (nOAE) as given in the aforementioned paper. +//! +//! ## Diagram +//! +//! ![STREAM Diagram](https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/img/AEADs/rogaway-stream.svg) +//! +//! Legend: +//! +//! - 𝐄k: AEAD encryption under key `k` +//! - 𝐌: message +//! - 𝐍: nonce +//! - 𝐀: additional associated data +//! - 𝐂: ciphertext +//! - 𝜏: MAC tag +//! +//! [1]: https://eprint.iacr.org/2015/189.pdf + +#![allow(clippy::upper_case_acronyms)] + +use crate::{AeadCore, AeadInPlace, Buffer, Error, Key, KeyInit, Result}; +use core::ops::{AddAssign, Sub}; +use generic_array::{ + typenum::{Unsigned, U4, U5}, + ArrayLength, GenericArray, +}; + +#[cfg(feature = "alloc")] +use {crate::Payload, alloc::vec::Vec}; + +/// Nonce as used by a given AEAD construction and STREAM primitive. +pub type Nonce = GenericArray>; + +/// Size of a nonce as used by a STREAM construction, sans the overhead of +/// the STREAM protocol itself. +pub type NonceSize = + <::NonceSize as Sub<>::NonceOverhead>>::Output; + +/// STREAM encryptor instantiated with [`StreamBE32`] as the underlying +/// STREAM primitive. +pub type EncryptorBE32 = Encryptor>; + +/// STREAM decryptor instantiated with [`StreamBE32`] as the underlying +/// STREAM primitive. +pub type DecryptorBE32 = Decryptor>; + +/// STREAM encryptor instantiated with [`StreamLE31`] as the underlying +/// STREAM primitive. +pub type EncryptorLE31 = Encryptor>; + +/// STREAM decryptor instantiated with [`StreamLE31`] as the underlying +/// STREAM primitive. +pub type DecryptorLE31 = Decryptor>; + +/// Create a new STREAM from the provided AEAD. +pub trait NewStream: StreamPrimitive +where + A: AeadInPlace, + A::NonceSize: Sub, + NonceSize: ArrayLength, +{ + /// Create a new STREAM with the given key and nonce. + fn new(key: &Key, nonce: &Nonce) -> Self + where + A: KeyInit, + Self: Sized, + { + Self::from_aead(A::new(key), nonce) + } + + /// Create a new STREAM from the given AEAD cipher. + fn from_aead(aead: A, nonce: &Nonce) -> Self; +} + +/// Low-level STREAM implementation. +/// +/// This trait provides a particular "flavor" of STREAM, as there are +/// different ways the specifics of the construction can be implemented. +/// +/// Deliberately immutable and stateless to permit parallel operation. +pub trait StreamPrimitive +where + A: AeadInPlace, + A::NonceSize: Sub, + NonceSize: ArrayLength, +{ + /// Number of bytes this STREAM primitive requires from the nonce. + type NonceOverhead: ArrayLength; + + /// Type used as the STREAM counter. + type Counter: AddAssign + Copy + Default + Eq; + + /// Value to use when incrementing the STREAM counter (i.e. one) + const COUNTER_INCR: Self::Counter; + + /// Maximum value of the STREAM counter. + const COUNTER_MAX: Self::Counter; + + /// Encrypt an AEAD message in-place at the given position in the STREAM. + fn encrypt_in_place( + &self, + position: Self::Counter, + last_block: bool, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()>; + + /// Decrypt an AEAD message in-place at the given position in the STREAM. + fn decrypt_in_place( + &self, + position: Self::Counter, + last_block: bool, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()>; + + /// Encrypt the given plaintext payload, and return the resulting + /// ciphertext as a vector of bytes. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn encrypt<'msg, 'aad>( + &self, + position: Self::Counter, + last_block: bool, + plaintext: impl Into>, + ) -> Result> { + let payload = plaintext.into(); + let mut buffer = Vec::with_capacity(payload.msg.len() + A::TagSize::to_usize()); + buffer.extend_from_slice(payload.msg); + self.encrypt_in_place(position, last_block, payload.aad, &mut buffer)?; + Ok(buffer) + } + + /// Decrypt the given ciphertext slice, and return the resulting plaintext + /// as a vector of bytes. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn decrypt<'msg, 'aad>( + &self, + position: Self::Counter, + last_block: bool, + ciphertext: impl Into>, + ) -> Result> { + let payload = ciphertext.into(); + let mut buffer = Vec::from(payload.msg); + self.decrypt_in_place(position, last_block, payload.aad, &mut buffer)?; + Ok(buffer) + } + + /// Obtain [`Encryptor`] for this [`StreamPrimitive`]. + fn encryptor(self) -> Encryptor + where + Self: Sized, + { + Encryptor::from_stream_primitive(self) + } + + /// Obtain [`Decryptor`] for this [`StreamPrimitive`]. + fn decryptor(self) -> Decryptor + where + Self: Sized, + { + Decryptor::from_stream_primitive(self) + } +} + +/// Implement a stateful STREAM object (i.e. encryptor or decryptor) +macro_rules! impl_stream_object { + ( + $name:ident, + $next_method:tt, + $next_in_place_method:tt, + $last_method:tt, + $last_in_place_method:tt, + $op:tt, + $in_place_op:tt, + $op_desc:expr, + $obj_desc:expr + ) => { + #[doc = "Stateful STREAM object which can"] + #[doc = $op_desc] + #[doc = "AEAD messages one-at-a-time."] + #[doc = ""] + #[doc = "This corresponds to the "] + #[doc = $obj_desc] + #[doc = "object as defined in the paper"] + #[doc = "[Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]."] + #[doc = ""] + #[doc = "[1]: https://eprint.iacr.org/2015/189.pdf"] + pub struct $name + where + A: AeadInPlace, + S: StreamPrimitive, + A::NonceSize: Sub<>::NonceOverhead>, + NonceSize: ArrayLength, + { + /// Underlying STREAM primitive. + stream: S, + + /// Current position in the STREAM. + position: S::Counter, + } + + impl $name + where + A: AeadInPlace, + S: StreamPrimitive, + A::NonceSize: Sub<>::NonceOverhead>, + NonceSize: ArrayLength, + { + #[doc = "Create a"] + #[doc = $obj_desc] + #[doc = "object from the given AEAD key and nonce."] + pub fn new(key: &Key, nonce: &Nonce) -> Self + where + A: KeyInit, + S: NewStream, + { + Self::from_stream_primitive(S::new(key, nonce)) + } + + #[doc = "Create a"] + #[doc = $obj_desc] + #[doc = "object from the given AEAD primitive."] + pub fn from_aead(aead: A, nonce: &Nonce) -> Self + where + A: KeyInit, + S: NewStream, + { + Self::from_stream_primitive(S::from_aead(aead, nonce)) + } + + #[doc = "Create a"] + #[doc = $obj_desc] + #[doc = "object from the given STREAM primitive."] + pub fn from_stream_primitive(stream: S) -> Self { + Self { + stream, + position: Default::default(), + } + } + + #[doc = "Use the underlying AEAD to"] + #[doc = $op_desc] + #[doc = "the next AEAD message in this STREAM, returning the"] + #[doc = "result as a [`Vec`]."] + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + pub fn $next_method<'msg, 'aad>( + &mut self, + payload: impl Into>, + ) -> Result> { + if self.position == S::COUNTER_MAX { + // Counter overflow. Note that the maximum counter value is + // deliberately disallowed, as it would preclude being able + // to encrypt a last block (i.e. with `$last_in_place_method`) + return Err(Error); + } + + let result = self.stream.$op(self.position, false, payload)?; + + // Note: overflow checked above + self.position += S::COUNTER_INCR; + Ok(result) + } + + #[doc = "Use the underlying AEAD to"] + #[doc = $op_desc] + #[doc = "the next AEAD message in this STREAM in-place."] + pub fn $next_in_place_method( + &mut self, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + if self.position == S::COUNTER_MAX { + // Counter overflow. Note that the maximum counter value is + // deliberately disallowed, as it would preclude being able + // to encrypt a last block (i.e. with `$last_in_place_method`) + return Err(Error); + } + + self.stream + .$in_place_op(self.position, false, associated_data, buffer)?; + + // Note: overflow checked above + self.position += S::COUNTER_INCR; + Ok(()) + } + + #[doc = "Use the underlying AEAD to"] + #[doc = $op_desc] + #[doc = "the last AEAD message in this STREAM,"] + #[doc = "consuming the "] + #[doc = $obj_desc] + #[doc = "object in order to prevent further use."] + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + pub fn $last_method<'msg, 'aad>( + self, + payload: impl Into>, + ) -> Result> { + self.stream.$op(self.position, true, payload) + } + + #[doc = "Use the underlying AEAD to"] + #[doc = $op_desc] + #[doc = "the last AEAD message in this STREAM in-place,"] + #[doc = "consuming the "] + #[doc = $obj_desc] + #[doc = "object in order to prevent further use."] + pub fn $last_in_place_method( + self, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + self.stream + .$in_place_op(self.position, true, associated_data, buffer) + } + } + }; +} + +impl_stream_object!( + Encryptor, + encrypt_next, + encrypt_next_in_place, + encrypt_last, + encrypt_last_in_place, + encrypt, + encrypt_in_place, + "encrypt", + "ℰ STREAM encryptor" +); + +impl_stream_object!( + Decryptor, + decrypt_next, + decrypt_next_in_place, + decrypt_last, + decrypt_last_in_place, + decrypt, + decrypt_in_place, + "decrypt", + "𝒟 STREAM decryptor" +); + +/// The original "Rogaway-flavored" STREAM as described in the paper +/// [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]. +/// +/// Uses a 32-bit big endian counter and 1-byte "last block" flag stored as +/// the last 5-bytes of the AEAD nonce. +/// +/// [1]: https://eprint.iacr.org/2015/189.pdf +pub struct StreamBE32 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + /// Underlying AEAD cipher + aead: A, + + /// Nonce (sans STREAM overhead) + nonce: Nonce, +} + +impl NewStream for StreamBE32 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + fn from_aead(aead: A, nonce: &Nonce) -> Self { + Self { + aead, + nonce: nonce.clone(), + } + } +} + +impl StreamPrimitive for StreamBE32 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + type NonceOverhead = U5; + type Counter = u32; + const COUNTER_INCR: u32 = 1; + const COUNTER_MAX: u32 = core::u32::MAX; + + fn encrypt_in_place( + &self, + position: u32, + last_block: bool, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + let nonce = self.aead_nonce(position, last_block); + self.aead.encrypt_in_place(&nonce, associated_data, buffer) + } + + fn decrypt_in_place( + &self, + position: Self::Counter, + last_block: bool, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + let nonce = self.aead_nonce(position, last_block); + self.aead.decrypt_in_place(&nonce, associated_data, buffer) + } +} + +impl StreamBE32 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + /// Compute the full AEAD nonce including the STREAM counter and last + /// block flag. + fn aead_nonce(&self, position: u32, last_block: bool) -> crate::Nonce { + let mut result = GenericArray::default(); + + // TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics) + let (prefix, tail) = result.split_at_mut(NonceSize::::to_usize()); + prefix.copy_from_slice(&self.nonce); + + let (counter, flag) = tail.split_at_mut(4); + counter.copy_from_slice(&position.to_be_bytes()); + flag[0] = last_block as u8; + + result + } +} + +/// STREAM as instantiated with a 31-bit little endian counter and 1-bit +/// "last block" flag stored as the most significant bit of the counter +/// when interpreted as a 32-bit integer. +/// +/// The 31-bit + 1-bit value is stored as the last 4 bytes of the AEAD nonce. +pub struct StreamLE31 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + /// Underlying AEAD cipher + aead: A, + + /// Nonce (sans STREAM overhead) + nonce: Nonce, +} + +impl NewStream for StreamLE31 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + fn from_aead(aead: A, nonce: &Nonce) -> Self { + Self { + aead, + nonce: nonce.clone(), + } + } +} + +impl StreamPrimitive for StreamLE31 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + type NonceOverhead = U4; + type Counter = u32; + const COUNTER_INCR: u32 = 1; + const COUNTER_MAX: u32 = 0xfff_ffff; + + fn encrypt_in_place( + &self, + position: u32, + last_block: bool, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + let nonce = self.aead_nonce(position, last_block)?; + self.aead.encrypt_in_place(&nonce, associated_data, buffer) + } + + fn decrypt_in_place( + &self, + position: Self::Counter, + last_block: bool, + associated_data: &[u8], + buffer: &mut dyn Buffer, + ) -> Result<()> { + let nonce = self.aead_nonce(position, last_block)?; + self.aead.decrypt_in_place(&nonce, associated_data, buffer) + } +} + +impl StreamLE31 +where + A: AeadInPlace, + A::NonceSize: Sub, + <::NonceSize as Sub>::Output: ArrayLength, +{ + /// Compute the full AEAD nonce including the STREAM counter and last + /// block flag. + fn aead_nonce(&self, position: u32, last_block: bool) -> Result> { + if position > Self::COUNTER_MAX { + return Err(Error); + } + + let mut result = GenericArray::default(); + + // TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics) + let (prefix, tail) = result.split_at_mut(NonceSize::::to_usize()); + prefix.copy_from_slice(&self.nonce); + + let position_with_flag = position | ((last_block as u32) << 31); + tail.copy_from_slice(&position_with_flag.to_le_bytes()); + + Ok(result) + } +} diff --git a/vendor/aes-gcm/.cargo-checksum.json b/vendor/aes-gcm/.cargo-checksum.json new file mode 100644 index 00000000..49a57baf --- /dev/null +++ b/vendor/aes-gcm/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8b877289aed51a5c313286e2387abc4f17b3e6c284dc04eaf0f98846ccb18534","Cargo.toml":"cc58c8b539bdfdfa7f665340209afcf428962b8368c6b0beef3809dac3559506","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"3c0dfa33fd2e6976038555b52095699452653b1fcabe113074f14e0848a6b11e","README.md":"20c9c6169af0c2b9ef737de89cf3d2d36f7122bdb8e4b6d95ccb4b04e75afecc","src/lib.rs":"9261306cb6e8ce08a3559d69b2c301b9c0474234b3ff4b92e3e3c8cd7937f479","tests/aes128gcm.rs":"fef2d95b49d245714256370207f6ce324bf90c7eb06dc742f9908470b39ae616","tests/aes256gcm.rs":"eac354157fa0574e58d569cfd541222bb1e4a0ca9561e2a578e3e1101214bbbc","tests/common/mod.rs":"f54a4dd4147b2e726139606e2afe6bf36444d5eff44a6fea61fb633e326985ba","tests/data/wycheproof-128.blb":"50031c7935b9c0608955601ca0aa573de58517aaa4986fc16550a91fa286ff8b","tests/data/wycheproof-256.blb":"d301c0cc24dccb3cdcb9db71b55e694d7dc31b166bf830ce2b3fc896567e1e1c","tests/other_ivlen.rs":"4ef546d000ba162c8a795f35a1c7eb9e6a6d563e0cc1214071ecb6573f79a3a2"},"package":"831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"} \ No newline at end of file diff --git a/vendor/aes-gcm/CHANGELOG.md b/vendor/aes-gcm/CHANGELOG.md new file mode 100644 index 00000000..160ec41a --- /dev/null +++ b/vendor/aes-gcm/CHANGELOG.md @@ -0,0 +1,179 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.10.3 (2023-09-21) +### Security +- Avoid exposing plaintext on tag verification failure ([#551]) + +[#551]: https://github.com/RustCrypto/AEADs/pull/551 + +## 0.10.2 (2023-05-20) +### Added +- `rand_core` feature to all crates ([#467]) +- Support for partial tag sizes ([#501]) +- `ArrayVec` support ([#503]) + +[#467]: https://github.com/RustCrypto/AEADs/pull/467 +[#501]: https://github.com/RustCrypto/AEADs/pull/501 +[#503]: https://github.com/RustCrypto/AEADs/pull/503 + +## 0.10.1 (2022-07-31) +### Fixed +- rustdoc typos and formatting ([#461], [#462]) + +[#461]: https://github.com/RustCrypto/AEADs/pull/461 +[#462]: https://github.com/RustCrypto/AEADs/pull/462 + +## 0.10.0 (2022-07-31) +### Added +- `getrandom` feature ([#446]) + +### Changed +- Bump `aes` dependency to v0.8 ([#430]) +- Rust 2021 edition upgrade; MSRV 1.56+ ([#435]) +- Bump `aead` dependency to v0.5 ([#444]) +- Bump `ghash` dependency to v0.5 ([#454]) + +[#435]: https://github.com/RustCrypto/AEADs/pull/435 +[#444]: https://github.com/RustCrypto/AEADs/pull/444 +[#446]: https://github.com/RustCrypto/AEADs/pull/446 +[#454]: https://github.com/RustCrypto/AEADs/pull/454 + +## 0.9.4 (2021-08-28) +### Changed +- Relax `subtle` and `zeroize` requirements ([#360]) + +[#360]: https://github.com/RustCrypto/AEADs/pull/360 + +## 0.9.3 (2021-07-20) +### Changed +- Pin `zeroize` dependency to v1.3 and `subtle` to v2.4 ([#349]) + +[#349]: https://github.com/RustCrypto/AEADs/pull/349 + +## 0.9.2 (2021-05-31) +### Added +- Nightly-only `armv8` feature ([#318]) + +[#318]: https://github.com/RustCrypto/AEADs/pull/318 + +## 0.9.1 (2021-05-04) +### Added +- `force-soft` feature ([#305]) + +[#305]: https://github.com/RustCrypto/AEADs/pull/305 + +## 0.9.0 (2021-04-29) +### Added +- Wycheproof test vectors ([#274]) + +### Changed +- Bump `aead` crate dependency to v0.4 ([#270]) +- Bump `aes` crate dependency to v0.7; MSRV 1.49+ ([#283]) +- Bump `ctr` crate dependency to v0.7 ([#283]) +- Bump `ghash` crate dependency to v0.4 ([#284]) + +[#270]: https://github.com/RustCrypto/AEADs/pull/270 +[#274]: https://github.com/RustCrypto/AEADs/pull/274 +[#283]: https://github.com/RustCrypto/AEADs/pull/283 +[#284]: https://github.com/RustCrypto/AEADs/pull/284 + +## 0.8.0 (2020-10-16) +### Changed +- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#229]) +- Bump `aes` dependency to v0.6 ([#229]) +- Use `ctr::Ctr32BE` ([#227]) + +[#229]: https://github.com/RustCrypto/AEADs/pull/229 +[#227]: https://github.com/RustCrypto/AEADs/pull/227 + +## 0.7.0 (2020-09-17) +### Added +- Optional `std` feature; disabled by default ([#217]) + +### Changed +- Renamed generic parameters to `Aes` and `NonceSize` ([#166]) +- Upgrade `aes` to v0.5; `block-cipher` to v0.8 ([#209]) + +[#217]: https://github.com/RustCrypto/AEADs/pull/217 +[#209]: https://github.com/RustCrypto/AEADs/pull/209 +[#166]: https://github.com/RustCrypto/AEADs/pull/166 + +## 0.6.0 (2020-06-06) +### Changed +- Bump `aead` crate dependency to v0.3.0; MSRV 1.41+ ([#140]) + +[#140]: https://github.com/RustCrypto/AEADs/pull/140 + +## 0.5.0 (2020-03-15) +### Added +- Support for non-96-bit nonces ([#126]) + +### Changed +- `AesGcm` type is now generic around nonce size ([#126]) + +[#126]: https://github.com/RustCrypto/AEADs/pull/126 + +## 0.4.2 (2020-03-09) +### Fixed +- Off-by-one error in `debug_assert` for `BlockCipher::ParBlocks` ([#104]) + +[#104]: https://github.com/RustCrypto/AEADs/pull/104 + +## 0.4.1 (2020-03-07) - YANKED, see [#104] +### Added +- Support instantiation from an existing cipher instance ([#101]) + +[#101]: https://github.com/RustCrypto/AEADs/pull/101 + +## 0.4.0 (2020-03-07) - YANKED, see [#104] +### Added +- `aes` cargo feature; 3rd-party AES crate support ([#96]) + +### Changed +- Make generic around `BlockCipher::ParBlocks` ([#97]) + +[#96]: https://github.com/RustCrypto/AEADs/pull/96 +[#97]: https://github.com/RustCrypto/AEADs/pull/97 + +## 0.3.2 (2020-02-27) +### Fixed +- Wording in documentation about security audit ([#84]) + +[#84]: https://github.com/RustCrypto/AEADs/pull/84 + +## 0.3.1 (2020-02-26) +### Added +- Notes about NCC audit to documentation ([#80]) + +[#80]: https://github.com/RustCrypto/AEADs/pull/80 + +## 0.3.0 (2019-11-26) +### Added +- `heapless` feature ([#51]) + +[#51]: https://github.com/RustCrypto/AEADs/pull/51 + +## 0.2.1 (2019-11-26) +### Added +- Document in-place API ([#49]) + +[#49]: https://github.com/RustCrypto/AEADs/pull/49 + +## 0.2.0 (2019-11-26) +### Changed +- Upgrade `aead` crate to v0.2; `alloc` now optional ([#43]) + +[#43]: https://github.com/RustCrypto/AEADs/pull/43 + +## 0.1.1 (2019-11-14) +### Changed +- Upgrade `zeroize` to 1.0 ([#36]) + +[#36]: https://github.com/RustCrypto/AEADs/pull/36 + +## 0.1.0 (2019-10-06) +- Initial release diff --git a/vendor/aes-gcm/Cargo.toml b/vendor/aes-gcm/Cargo.toml new file mode 100644 index 00000000..1257b557 --- /dev/null +++ b/vendor/aes-gcm/Cargo.toml @@ -0,0 +1,100 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "aes-gcm" +version = "0.10.3" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of the AES-GCM (Galois/Counter Mode) +Authenticated Encryption with Associated Data (AEAD) Cipher +with optional architecture-specific hardware acceleration +""" +documentation = "https://docs.rs/aes-gcm" +readme = "README.md" +keywords = [ + "aead", + "aes", + "encryption", + "gcm", + "ghash", +] +categories = [ + "cryptography", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/AEADs" +resolver = "1" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.aead] +version = "0.5" +default-features = false + +[dependencies.aes] +version = "0.8" +optional = true + +[dependencies.cipher] +version = "0.4" + +[dependencies.ctr] +version = "0.9" + +[dependencies.ghash] +version = "0.5" +default-features = false + +[dependencies.subtle] +version = "2" +default-features = false + +[dependencies.zeroize] +version = "1" +optional = true +default-features = false + +[dev-dependencies.aead] +version = "0.5" +features = ["dev"] +default-features = false + +[dev-dependencies.hex-literal] +version = "0.3" + +[features] +alloc = ["aead/alloc"] +arrayvec = ["aead/arrayvec"] +default = [ + "aes", + "alloc", + "getrandom", +] +getrandom = [ + "aead/getrandom", + "rand_core", +] +heapless = ["aead/heapless"] +rand_core = ["aead/rand_core"] +std = [ + "aead/std", + "alloc", +] +stream = ["aead/stream"] diff --git a/vendor/aes-gcm/LICENSE-APACHE b/vendor/aes-gcm/LICENSE-APACHE new file mode 100644 index 00000000..78173fa2 --- /dev/null +++ b/vendor/aes-gcm/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 [yyyy] [name of copyright owner] + +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/vendor/aes-gcm/LICENSE-MIT b/vendor/aes-gcm/LICENSE-MIT new file mode 100644 index 00000000..b7f57116 --- /dev/null +++ b/vendor/aes-gcm/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2019 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/vendor/aes-gcm/README.md b/vendor/aes-gcm/README.md new file mode 100644 index 00000000..4f0e5962 --- /dev/null +++ b/vendor/aes-gcm/README.md @@ -0,0 +1,61 @@ +# RustCrypto: AES-GCM + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] +[![Build Status][build-image]][build-link] + +Pure Rust implementation of the AES-GCM +[Authenticated Encryption with Associated Data (AEAD)][1] cipher. + +[Documentation][docs-link] + +## Security Notes + +This crate has received one [security audit by NCC Group][2], with no significant +findings. We would like to thank [MobileCoin][3] for funding the audit. + +All implementations contained in the crate are designed to execute in constant +time, either by relying on hardware intrinsics (i.e. AES-NI and CLMUL on +x86/x86_64), or using a portable implementation which is only constant time +on processors which implement constant-time multiplication. + +It is not suitable for use on processors with a variable-time multiplication +operation (e.g. short circuit on multiply-by-zero / multiply-by-one, such as +certain 32-bit PowerPC CPUs and some non-ARM microcontrollers). + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://buildstats.info/crate/aes-gcm +[crate-link]: https://crates.io/crates/aes-gcm +[docs-image]: https://docs.rs/aes-gcm/badge.svg +[docs-link]: https://docs.rs/aes-gcm/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260038-AEADs +[build-image]: https://github.com/RustCrypto/AEADs/workflows/aes-gcm/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/AEADs/actions + +[//]: # (general links) + +[1]: https://en.wikipedia.org/wiki/Authenticated_encryption +[2]: https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/ +[3]: https://www.mobilecoin.com/ diff --git a/vendor/aes-gcm/src/lib.rs b/vendor/aes-gcm/src/lib.rs new file mode 100644 index 00000000..4006c368 --- /dev/null +++ b/vendor/aes-gcm/src/lib.rs @@ -0,0 +1,373 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc = include_str!("../README.md")] +#![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" +)] +#![deny(unsafe_code)] +#![warn(missing_docs, rust_2018_idioms)] + +//! # Usage +//! +//! Simple usage (allocating, no associated data): +//! +//! ``` +//! use aes_gcm::{ +//! aead::{Aead, AeadCore, KeyInit, OsRng}, +//! Aes256Gcm, Nonce, Key // Or `Aes128Gcm` +//! }; +//! +//! # fn gen_key() -> Result<(), core::array::TryFromSliceError> { +//! // The encryption key can be generated randomly: +//! # #[cfg(all(feature = "getrandom", feature = "std"))] { +//! let key = Aes256Gcm::generate_key(OsRng); +//! # } +//! +//! // Transformed from a byte array: +//! let key: &[u8; 32] = &[42; 32]; +//! let key: &Key = key.into(); +//! +//! // Note that you can get byte array from slice using the `TryInto` trait: +//! let key: &[u8] = &[42; 32]; +//! let key: [u8; 32] = key.try_into()?; +//! # Ok(()) } +//! +//! # fn main() -> Result<(), aes_gcm::Error> { +//! // Alternatively, the key can be transformed directly from a byte slice +//! // (panicks on length mismatch): +//! # let key: &[u8] = &[42; 32]; +//! let key = Key::::from_slice(key); +//! +//! let cipher = Aes256Gcm::new(&key); +//! let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits; unique per message +//! let ciphertext = cipher.encrypt(&nonce, b"plaintext message".as_ref())?; +//! let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref())?; +//! assert_eq!(&plaintext, b"plaintext message"); +//! # Ok(()) +//! # } +//! ``` +//! +//! ## 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_attr( + all(feature = "getrandom", feature = "heapless", feature = "std"), + doc = "```" +)] +#![cfg_attr( + not(all(feature = "getrandom", feature = "heapless", feature = "std")), + doc = "```ignore" +)] +//! # fn main() -> Result<(), Box> { +//! use aes_gcm::{ +//! aead::{AeadCore, AeadInPlace, KeyInit, OsRng, heapless::Vec}, +//! Aes256Gcm, Nonce, // Or `Aes128Gcm` +//! }; +//! +//! let key = Aes256Gcm::generate_key(&mut OsRng); +//! let cipher = Aes256Gcm::new(&key); +//! let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits; unique per message +//! +//! let mut buffer: Vec = Vec::new(); // Note: buffer needs 16-bytes overhead for auth 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)?; +//! +//! // `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)?; +//! assert_eq!(&buffer, b"plaintext message"); +//! # Ok(()) +//! # } +//! ``` +//! +//! Similarly, enabling the `arrayvec` feature of this crate will provide an impl of +//! [`aead::Buffer`] for `arrayvec::ArrayVec` (re-exported from the [`aead`] crate as +//! [`aead::arrayvec::ArrayVec`]). + +pub use aead::{self, AeadCore, AeadInPlace, Error, Key, KeyInit, KeySizeUser}; + +#[cfg(feature = "aes")] +pub use aes; + +use cipher::{ + consts::{U0, U16}, + generic_array::{ArrayLength, GenericArray}, + BlockCipher, BlockEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, +}; +use core::marker::PhantomData; +use ghash::{universal_hash::UniversalHash, GHash}; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +#[cfg(feature = "aes")] +use aes::{cipher::consts::U12, Aes128, Aes256}; + +/// Maximum length of associated data. +pub const A_MAX: u64 = 1 << 36; + +/// Maximum length of plaintext. +pub const P_MAX: u64 = 1 << 36; + +/// Maximum length of ciphertext. +pub const C_MAX: u64 = (1 << 36) + 16; + +/// AES-GCM nonces. +pub type Nonce = GenericArray; + +/// AES-GCM tags. +pub type Tag = GenericArray; + +/// Trait implemented for valid tag sizes, i.e. +/// [`U12`][consts::U12], [`U13`][consts::U13], [`U14`][consts::U14], +/// [`U15`][consts::U15] and [`U16`][consts::U16]. +pub trait TagSize: private::SealedTagSize {} + +impl TagSize for T {} + +mod private { + use aead::generic_array::ArrayLength; + use cipher::{consts, Unsigned}; + + // Sealed traits stop other crates from implementing any traits that use it. + pub trait SealedTagSize: ArrayLength + Unsigned {} + + impl SealedTagSize for consts::U12 {} + impl SealedTagSize for consts::U13 {} + impl SealedTagSize for consts::U14 {} + impl SealedTagSize for consts::U15 {} + impl SealedTagSize for consts::U16 {} +} + +/// AES-GCM with a 128-bit key and 96-bit nonce. +#[cfg(feature = "aes")] +#[cfg_attr(docsrs, doc(cfg(feature = "aes")))] +pub type Aes128Gcm = AesGcm; + +/// AES-GCM with a 256-bit key and 96-bit nonce. +#[cfg(feature = "aes")] +#[cfg_attr(docsrs, doc(cfg(feature = "aes")))] +pub type Aes256Gcm = AesGcm; + +/// AES block. +type Block = GenericArray; + +/// Counter mode with a 32-bit big endian counter. +type Ctr32BE = ctr::CtrCore; + +/// AES-GCM: generic over an underlying AES implementation and nonce size. +/// +/// This type is generic to support substituting alternative AES implementations +/// (e.g. embedded hardware implementations) +/// +/// It is NOT intended to be instantiated with any block cipher besides AES! +/// Doing so runs the risk of unintended cryptographic properties! +/// +/// The `NonceSize` generic parameter can be used to instantiate AES-GCM with other +/// nonce sizes, however it's recommended to use it with `typenum::U12`, +/// the default of 96-bits. +/// +/// The `TagSize` generic parameter can be used to instantiate AES-GCM with other +/// authorization tag sizes, however it's recommended to use it with `typenum::U16`, +/// the default of 128-bits. +/// +/// If in doubt, use the built-in [`Aes128Gcm`] and [`Aes256Gcm`] type aliases. +#[derive(Clone)] +pub struct AesGcm +where + TagSize: self::TagSize, +{ + /// Encryption cipher. + cipher: Aes, + + /// GHASH authenticator. + ghash: GHash, + + /// Length of the nonce. + nonce_size: PhantomData, + + /// Length of the tag. + tag_size: PhantomData, +} + +impl KeySizeUser for AesGcm +where + Aes: KeySizeUser, + TagSize: self::TagSize, +{ + type KeySize = Aes::KeySize; +} + +impl KeyInit for AesGcm +where + Aes: BlockSizeUser + BlockEncrypt + KeyInit, + TagSize: self::TagSize, +{ + fn new(key: &Key) -> Self { + Aes::new(key).into() + } +} + +impl From for AesGcm +where + Aes: BlockSizeUser + BlockEncrypt, + TagSize: self::TagSize, +{ + fn from(cipher: Aes) -> Self { + let mut ghash_key = ghash::Key::default(); + cipher.encrypt_block(&mut ghash_key); + + let ghash = GHash::new(&ghash_key); + + #[cfg(feature = "zeroize")] + ghash_key.zeroize(); + + Self { + cipher, + ghash, + nonce_size: PhantomData, + tag_size: PhantomData, + } + } +} + +impl AeadCore for AesGcm +where + NonceSize: ArrayLength, + TagSize: self::TagSize, +{ + type NonceSize = NonceSize; + type TagSize = TagSize; + type CiphertextOverhead = U0; +} + +impl AeadInPlace for AesGcm +where + Aes: BlockCipher + BlockSizeUser + BlockEncrypt, + NonceSize: ArrayLength, + TagSize: self::TagSize, +{ + fn encrypt_in_place_detached( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + ) -> Result, Error> { + if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { + return Err(Error); + } + + let (ctr, mask) = self.init_ctr(nonce); + + // TODO(tarcieri): interleave encryption with GHASH + // See: + ctr.apply_keystream_partial(buffer.into()); + + let full_tag = self.compute_tag(mask, associated_data, buffer); + Ok(Tag::clone_from_slice(&full_tag[..TagSize::to_usize()])) + } + + fn decrypt_in_place_detached( + &self, + nonce: &Nonce, + associated_data: &[u8], + buffer: &mut [u8], + tag: &Tag, + ) -> Result<(), Error> { + if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { + return Err(Error); + } + + let (ctr, mask) = self.init_ctr(nonce); + + // TODO(tarcieri): interleave encryption with GHASH + // See: + let expected_tag = self.compute_tag(mask, associated_data, buffer); + + use subtle::ConstantTimeEq; + if expected_tag[..TagSize::to_usize()].ct_eq(tag).into() { + ctr.apply_keystream_partial(buffer.into()); + Ok(()) + } else { + Err(Error) + } + } +} + +impl AesGcm +where + Aes: BlockCipher + BlockSizeUser + BlockEncrypt, + NonceSize: ArrayLength, + TagSize: self::TagSize, +{ + /// Initialize counter mode. + /// + /// See algorithm described in Section 7.2 of NIST SP800-38D: + /// + /// + /// > Define a block, J0, as follows: + /// > If len(IV)=96, then J0 = IV || 0{31} || 1. + /// > If len(IV) ≠ 96, then let s = 128 ⎡len(IV)/128⎤-len(IV), and + /// > J0=GHASH(IV||0s+64||[len(IV)]64). + fn init_ctr(&self, nonce: &Nonce) -> (Ctr32BE<&Aes>, Block) { + let j0 = if NonceSize::to_usize() == 12 { + let mut block = ghash::Block::default(); + block[..12].copy_from_slice(nonce); + block[15] = 1; + block + } else { + let mut ghash = self.ghash.clone(); + ghash.update_padded(nonce); + + let mut block = ghash::Block::default(); + let nonce_bits = (NonceSize::to_usize() as u64) * 8; + block[8..].copy_from_slice(&nonce_bits.to_be_bytes()); + ghash.update(&[block]); + ghash.finalize() + }; + + let mut ctr = Ctr32BE::inner_iv_init(&self.cipher, &j0); + let mut tag_mask = Block::default(); + ctr.write_keystream_block(&mut tag_mask); + (ctr, tag_mask) + } + + /// Authenticate the given plaintext and associated data using GHASH. + fn compute_tag(&self, mask: Block, associated_data: &[u8], buffer: &[u8]) -> Tag { + let mut ghash = self.ghash.clone(); + ghash.update_padded(associated_data); + ghash.update_padded(buffer); + + let associated_data_bits = (associated_data.len() as u64) * 8; + let buffer_bits = (buffer.len() as u64) * 8; + + let mut block = ghash::Block::default(); + block[..8].copy_from_slice(&associated_data_bits.to_be_bytes()); + block[8..].copy_from_slice(&buffer_bits.to_be_bytes()); + ghash.update(&[block]); + + let mut tag = ghash.finalize(); + for (a, b) in tag.as_mut_slice().iter_mut().zip(mask.as_slice()) { + *a ^= *b; + } + + tag + } +} diff --git a/vendor/aes-gcm/tests/aes128gcm.rs b/vendor/aes-gcm/tests/aes128gcm.rs new file mode 100644 index 00000000..8834636f --- /dev/null +++ b/vendor/aes-gcm/tests/aes128gcm.rs @@ -0,0 +1,3022 @@ +//! AES-128-auth tag tests + +#[macro_use] +mod common; + +use self::common::TestVector; +use aes_gcm::aead::{generic_array::GenericArray, Aead, AeadInPlace, KeyInit, Payload}; +use aes_gcm::Aes128Gcm; +use hex_literal::hex; + +/// NIST CAVS vectors +/// +/// +/// +/// From: `gcmEncryptExtIV128.rsp` +const TEST_VECTORS: &[TestVector<[u8; 16]>] = &[ + TestVector { + key: &hex!("11754cd72aec309bf52f7687212e8957"), + nonce: &hex!("3c819d9a9bed087615030b65"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("250327c674aaf477aef2675748cf6971"), + }, + TestVector { + key: &hex!("ca47248ac0b6f8372a97ac43508308ed"), + nonce: &hex!("ffd2b598feabc9019262d2be"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("60d20404af527d248d893ae495707d1a"), + }, + TestVector { + key: &hex!("db1ad0bd1cf6db0b5d86efdd8914b218"), + nonce: &hex!("36fad6acb3c98e0138aeb9b1"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("5ee2ba737d3f2a944b335a81f6653cce"), + }, + TestVector { + key: &hex!("1c7135af627c04c32957f33f9ac08590"), + nonce: &hex!("355c094fa09c8e9281178d34"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("b6ab2c7d906c9d9ec4c1498d2cbb5029"), + }, + TestVector { + key: &hex!("6ca2c11205a6e55ab504dbf3491f8bdc"), + nonce: &hex!("b1008b650a2fee642175c60d"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("7a9a225d5f9a0ebfe0e69f371871a672"), + }, + TestVector { + key: &hex!("69f2ca78bb5690acc6587302628828d5"), + nonce: &hex!("701da282cb6b6018dabd00d3"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("ab1d40dda1798d56687892e2159decfd"), + }, + TestVector { + key: &hex!("dcf4e339c487b6797aaca931725f7bbd"), + nonce: &hex!("2c1d955e35366760ead8817c"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("32b542c5f344cceceb460a02938d6b0c"), + }, + TestVector { + key: &hex!("7658cdbb81572a23a78ee4596f844ee9"), + nonce: &hex!("1c3baae9b9065961842cbe52"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("70c7123fc819aa060ed2d3c159b6ea41"), + }, + TestVector { + key: &hex!("281a570b1e8f265ee09303ecae0cc46d"), + nonce: &hex!("8c2941f73cf8713ad5bc13df"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("a42e5e5f6fb00a9f1206b302edbfd87c"), + }, + TestVector { + key: &hex!("cd332a986f82d98c215278131ad387b7"), + nonce: &hex!("1d12b259f44b873d3942bc11"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("34238023648185d7ef0cfcf5836e93cc"), + }, + TestVector { + key: &hex!("80e1d98d10b27237386f029189ec0448"), + nonce: &hex!("239ebab2f524fd62c554a190"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("4c0f29d963f0ed68dccf34496cf43d00"), + }, + TestVector { + key: &hex!("40650cdb61e3e19a1a98fb4e05377d35"), + nonce: &hex!("69f0a81aaf6bb8486282f1b9"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("2657e12dec21c3ecf071af6179529fb4"), + }, + TestVector { + key: &hex!("1e89a6cd7528cce1e2b2b5f7fd2b6b52"), + nonce: &hex!("e11fd427a782d543f78efc60"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("eeedff874c8edeea53e8be2a13afd81b"), + }, + TestVector { + key: &hex!("2a7ad6146676057db777dea4683d0d45"), + nonce: &hex!("ed721ea67456d4594aafbd51"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("ee3cab5778888439d90fa718b75738ad"), + }, + TestVector { + key: &hex!("a364f494a4cd0147c34731074dc1a85b"), + nonce: &hex!("4aa8470dd404e4054b30093a"), + plaintext: &hex!(""), + aad: &hex!(""), + ciphertext: &hex!(""), + tag: &hex!("d8a7bba3a451902e3adc01060c3c91a7"), + }, + TestVector { + key: &hex!("77be63708971c4e240d1cb79e8d77feb"), + nonce: &hex!("e0e00f19fed7ba0136a797f3"), + plaintext: &hex!(""), + aad: &hex!("7a43ec1d9c0a5a78a0b16533a6213cab"), + ciphertext: &hex!(""), + tag: &hex!("209fcc8d3675ed938e9c7166709dd946"), + }, + TestVector { + key: &hex!("7680c5d3ca6154758e510f4d25b98820"), + nonce: &hex!("f8f105f9c3df4965780321f8"), + plaintext: &hex!(""), + aad: &hex!("c94c410194c765e3dcc7964379758ed3"), + ciphertext: &hex!(""), + tag: &hex!("94dca8edfcf90bb74b153c8d48a17930"), + }, + TestVector { + key: &hex!("a82bb1edc7c01a3689006f34bfed783e"), + nonce: &hex!("963836b67b188becf9ba1411"), + plaintext: &hex!(""), + aad: &hex!("9d115bb9bbd119fb777b6316065a9ac8"), + ciphertext: &hex!(""), + tag: &hex!("c491889fa3eca4544ba0d51b8e0f3837"), + }, + TestVector { + key: &hex!("b9782d0a5986c63f352d3bc4c7ecc96d"), + nonce: &hex!("4541e15b92edea44eceb1f2a"), + plaintext: &hex!(""), + aad: &hex!("f1a9f0723429c5b26185ac3ea7e13d7a"), + ciphertext: &hex!(""), + tag: &hex!("74d0d36949f0276670f9ddc579e94f3a"), + }, + TestVector { + key: &hex!("59b95785b30f205679fc4f3f9a90102f"), + nonce: &hex!("1908787cc1e1880a6ef5dd17"), + plaintext: &hex!(""), + aad: &hex!("39852d3182944a5177db277b63910702"), + ciphertext: &hex!(""), + tag: &hex!("8f9a96c013992485b43e2b62745ad173"), + }, + TestVector { + key: &hex!("34dd7926ab13d4078160d87de2e3c724"), + nonce: &hex!("c11ccdaf798ab03af2d97ef9"), + plaintext: &hex!(""), + aad: &hex!("af698717a6d790b3bfc39195857bb5ff"), + ciphertext: &hex!(""), + tag: &hex!("48116050bbd9118270d0be252d29d5d4"), + }, + TestVector { + key: &hex!("8ec86fab55aaab0e77455e9cd3dbc78e"), + nonce: &hex!("15fd90a9867e14f0d63b53b9"), + plaintext: &hex!(""), + aad: &hex!("e7509e276209a6d3ecfabb53ccdcd236"), + ciphertext: &hex!(""), + tag: &hex!("d96d6ac0d309cebedeba2af9f262132f"), + }, + TestVector { + key: &hex!("66b2473d9e0121666d47633f7008eb1c"), + nonce: &hex!("c1716c68a24d57770b867e51"), + plaintext: &hex!(""), + aad: &hex!("c20f686317d67e53dd79bae5c46dc111"), + ciphertext: &hex!(""), + tag: &hex!("9a08616809cf15247dfeb9756ba4f609"), + }, + TestVector { + key: &hex!("5b262a9d00904d30a2587caade091381"), + nonce: &hex!("f7bc154ca562e8f2c1845598"), + plaintext: &hex!(""), + aad: &hex!("23112d078c9914fa3dfe5218cd191016"), + ciphertext: &hex!(""), + tag: &hex!("98854d193a06dbe32ce4497eec5c9a8b"), + }, + TestVector { + key: &hex!("2e4fb9cc320188a6f1fa89a7a252273a"), + nonce: &hex!("7a6d4ee69c7256c14fba8f5e"), + plaintext: &hex!(""), + aad: &hex!("80ba4a202a68c3590d6557912c6f878e"), + ciphertext: &hex!(""), + tag: &hex!("9280313273befb8afa0bceca5a966d85"), + }, + TestVector { + key: &hex!("5ea94973d8616dafa7f31db0716d1729"), + nonce: &hex!("a05b62669d250e61b077d28a"), + plaintext: &hex!(""), + aad: &hex!("9620baf2f58d013f8a4c4871989c1b17"), + ciphertext: &hex!(""), + tag: &hex!("7e550398dee728256d6928cdaac43b73"), + }, + TestVector { + key: &hex!("910385f6f07f9e57e483c47dd5206bcc"), + nonce: &hex!("518f56e33658df311d42d9fe"), + plaintext: &hex!(""), + aad: &hex!("5d157909a2a4607117e77da0e4493b88"), + ciphertext: &hex!(""), + tag: &hex!("a7041ea4a1d74d9e66b9571b59b6a1d8"), + }, + TestVector { + key: &hex!("cab3af7a15b430e034e793bb30db8ab2"), + nonce: &hex!("963a56e2e12f387062e18498"), + plaintext: &hex!(""), + aad: &hex!("a094a1dd1121d3aa52c81e8f10bf9f0c"), + ciphertext: &hex!(""), + tag: &hex!("1a31d295601eb3c82a54b234984ffdf5"), + }, + TestVector { + key: &hex!("89c949e9c804af014d5604b39459f2c8"), + nonce: &hex!("d1b104c815bf1e94e28c8f16"), + plaintext: &hex!(""), + aad: &hex!("82adcd638d3fa9d9f3e84100d61e0777"), + ciphertext: &hex!(""), + tag: &hex!("88db9d62172ed043aa10f16d227dc41b"), + }, + TestVector { + key: &hex!("a4d994c4ac5ac0f02913245714fbe235"), + nonce: &hex!("a9472dadcca8d7e0e3b8084d"), + plaintext: &hex!(""), + aad: &hex!("eb318b9e17575203dd29ebed20ec82f9"), + ciphertext: &hex!(""), + tag: &hex!("323df7f33694106f56739de0973216a3"), + }, + TestVector { + key: &hex!("2fb45e5b8f993a2bfebc4b15b533e0b4"), + nonce: &hex!("5b05755f984d2b90f94b8027"), + plaintext: &hex!(""), + aad: &hex!("e85491b2202caf1d7dce03b97e09331c32473941"), + ciphertext: &hex!(""), + tag: &hex!("c75b7832b2a2d9bd827412b6ef5769db"), + }, + TestVector { + key: &hex!("952117048f77e276c2ef6580537c1403"), + nonce: &hex!("070b8fb46a7ad52885be1b26"), + plaintext: &hex!(""), + aad: &hex!("34b088f982818b5f07dabe2b62f9547f4ed09912"), + ciphertext: &hex!(""), + tag: &hex!("bedd4cf30fd7a4abc49bdcc3f3b248b1"), + }, + TestVector { + key: &hex!("7f6453b39bde018560a16a2704217543"), + nonce: &hex!("0f3eecf48d68353226a77fe4"), + plaintext: &hex!(""), + aad: &hex!("11e4ecb256ebff56453fa2e75e43eb9d641049e6"), + ciphertext: &hex!(""), + tag: &hex!("b512623a12d5492b7d76d39be0df5777"), + }, + TestVector { + key: &hex!("9332e433bf6100c6cc23b08710627c40"), + nonce: &hex!("aab3db3015b29d24f329beb4"), + plaintext: &hex!(""), + aad: &hex!("bd843a08f0a822f8f4f76c3648380aab7622e719"), + ciphertext: &hex!(""), + tag: &hex!("e54f1d18c61d8be15484727605b5a5dc"), + }, + TestVector { + key: &hex!("5773750a493096a99d84c0563fc293e9"), + nonce: &hex!("c390ed70dc9497234413ad52"), + plaintext: &hex!(""), + aad: &hex!("6012517258716c1f0035efa60a0f36b5c65e7379"), + ciphertext: &hex!(""), + tag: &hex!("b011b264610e58082705476f040b8c86"), + }, + TestVector { + key: &hex!("41b0d0fce5d31359cfd5db4064e2d46b"), + nonce: &hex!("b903e9d0cea25795a82e73e3"), + plaintext: &hex!(""), + aad: &hex!("4cba501876f33e1fda9cd456e3180683e3863bd9"), + ciphertext: &hex!(""), + tag: &hex!("18bc39d0b95cf059cd8c25004f5e507c"), + }, + TestVector { + key: &hex!("4748b782e3fe5e4effeb7c67232d2b07"), + nonce: &hex!("c5e4dcf18f86076b88a5d5e9"), + plaintext: &hex!(""), + aad: &hex!("3b2fcad8739ed87e1d02e80845f120e249ea92b1"), + ciphertext: &hex!(""), + tag: &hex!("b8ae718e2879c9cb658d5d1122e69bb7"), + }, + TestVector { + key: &hex!("e30cc22077d5951216d07f37c51b58f9"), + nonce: &hex!("fc583ad159b52e0b6378157e"), + plaintext: &hex!(""), + aad: &hex!("c3cb7be8888ef44ca5aa93dde26d2751288e1f5a"), + ciphertext: &hex!(""), + tag: &hex!("a8ce25b5dc8f84e2f5dae5f085aaccd4"), + }, + TestVector { + key: &hex!("7c8b10ba75ee6ab4a997d3f598b79d40"), + nonce: &hex!("6fb55188ddf00dde09596587"), + plaintext: &hex!(""), + aad: &hex!("2ddc0acf9705f8d18f905b8f9d472e7dbf6b91e3"), + ciphertext: &hex!(""), + tag: &hex!("5791d3805109c5e18adff4e80906a018"), + }, + TestVector { + key: &hex!("72c7db6ca29f83641c3fff5b71c4bc30"), + nonce: &hex!("f2000742e249ac56d5b2f65f"), + plaintext: &hex!(""), + aad: &hex!("cd994d2d08232770927d854ef2b6ca2f087370cf"), + ciphertext: &hex!(""), + tag: &hex!("a5966df39feeba0336f0b9a3f4ffe6c3"), + }, + TestVector { + key: &hex!("2833cc10195030e4a1155532666cb049"), + nonce: &hex!("ad802b9a5c9409fa3e7dcfcc"), + plaintext: &hex!(""), + aad: &hex!("b3ecbea2797d006c07b8ce621be3b0eccd37c3ec"), + ciphertext: &hex!(""), + tag: &hex!("81deab8bdee0d391495eed4029a6d205"), + }, + TestVector { + key: &hex!("d8985bb5ac0258adad86660ebbc6d19f"), + nonce: &hex!("b5ee26f8c463bbfc27115b0a"), + plaintext: &hex!(""), + aad: &hex!("613f51f832fbf434b8e3fe9454ae46a862d831f0"), + ciphertext: &hex!(""), + tag: &hex!("fe9f0b1bdc68dee6e8dc2ce12665d336"), + }, + TestVector { + key: &hex!("9b8f6924dc22f1073c1a38448a2f0447"), + nonce: &hex!("09cdabf87d82828eca1c0c7f"), + plaintext: &hex!(""), + aad: &hex!("69210e4e0a1cfd5038756652790b9a8cfbbd943d"), + ciphertext: &hex!(""), + tag: &hex!("a60c104a6fb4638427a88a86c04923bd"), + }, + TestVector { + key: &hex!("72132213d5d95309bf7e10f8318d7c20"), + nonce: &hex!("fb90bf283c5411230355d7a1"), + plaintext: &hex!(""), + aad: &hex!("a30bb17c8089c6f5f61b250a94cbbbfdf5f2a3e6"), + ciphertext: &hex!(""), + tag: &hex!("09191af418949fe6be8dbf13e006527a"), + }, + TestVector { + key: &hex!("652ffbad4e1fcbe75564395e6c1c3924"), + nonce: &hex!("111349636d106fd5f6a1e088"), + plaintext: &hex!(""), + aad: &hex!("5f52aa85dc3ac042647e32ada050d67e59b519aa"), + ciphertext: &hex!(""), + tag: &hex!("28d980d7bfd878c227c140de3482765b"), + }, + TestVector { + key: &hex!("99e3e8793e686e571d8285c564f75e2b"), + nonce: &hex!("c2dd0ab868da6aa8ad9c0d23"), + plaintext: &hex!(""), + aad: &hex!("b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc"), + ciphertext: &hex!(""), + tag: &hex!("3f4fba100eaf1f34b0baadaae9995d85"), + }, + TestVector { + key: &hex!("f8e29efd00a423c4ea9456863f83c54f"), + nonce: &hex!("2d3cf67cbce69d639bd1c092"), + plaintext: &hex!(""), + aad: &hex!("02c70fc8a2544619c1c3e9fce6b3c6c3bc24643e0f140e6b48ac505ea666cd9a2010c3a8e2f5f10437887fe803b54db3"), + ciphertext: &hex!(""), + tag: &hex!("963cb50aca3e09dd0d9a013c8734155f"), + }, + TestVector { + key: &hex!("00e3491dfcf3bec39c89ccfd80a5a896"), + nonce: &hex!("29f6ff4edc4ac3e97ffb1680"), + plaintext: &hex!(""), + aad: &hex!("73813351b39f5e4000a9ee8d2b85f131634acaede0dd25d691a2b829ad4fe9ea699f12242519847cb083b0b4d3d8b3bc"), + ciphertext: &hex!(""), + tag: &hex!("01b2e9ba719ad77c753b364ecc5aabeb"), + }, + TestVector { + key: &hex!("0ad06f4c19af1d5f602b38f86e56291c"), + nonce: &hex!("0b235c6a75cecdfcba9001ce"), + plaintext: &hex!(""), + aad: &hex!("7d4f26f7895b2ef3da2e4f93e411cdb74025c7759c038d872344a45ce56d92a581862c3bace039090a2ccfa43b623dcb"), + ciphertext: &hex!(""), + tag: &hex!("b4bc9ce1475d0c93dfd5a5d8d45bd8e5"), + }, + TestVector { + key: &hex!("eeeb33e0c8a406ea236a075cdbe9d6f9"), + nonce: &hex!("b935e8eed66227836ede189a"), + plaintext: &hex!(""), + aad: &hex!("9a4291acb9924bba4241b0c9c3c2e1262b25a7c7f02c92adeadf92254d618ab59388aa30b47eafa58899c357cf281e31"), + ciphertext: &hex!(""), + tag: &hex!("143d6954eb6fe70aff70da978ccd4509"), + }, + TestVector { + key: &hex!("600b5442a0b550a38f85d2fb0acc9c96"), + nonce: &hex!("5e65dd6e8b20d6b2931fe6c2"), + plaintext: &hex!(""), + aad: &hex!("461e54a092f8392466849fb0370ae30c14c1bf3987ab2ebbe98e18d13f041d09d043f7aea78bfcc42f864a9fb40f0031"), + ciphertext: &hex!(""), + tag: &hex!("2cd626f9a0686300cf23c0bc597c63b4"), + }, + TestVector { + key: &hex!("ce8d1103100fa290f953fbb439efdee4"), + nonce: &hex!("4874c6f8082366fc7e49b933"), + plaintext: &hex!(""), + aad: &hex!("d69d033c32029789263c689e11ff7e9e8eefc48ddbc4e10eeae1c9edbb44f04e7cc6471501eadda3940ab433d0a8c210"), + ciphertext: &hex!(""), + tag: &hex!("a5964b77af0b8aecd844d6adec8b7b1c"), + }, + TestVector { + key: &hex!("ae7114c09ffa04298834412f6a8de453"), + nonce: &hex!("f380c2d860be2af41e1be5c6"), + plaintext: &hex!(""), + aad: &hex!("7e16082f689c63e8adddd5cb2da610bbfb88d073cf8b204384a937aab0376523a50d3d5f1392978f79609f12df8fc288"), + ciphertext: &hex!(""), + tag: &hex!("40d3a36358a6f6caaa6af92cfd874a22"), + }, + TestVector { + key: &hex!("d8f520b6f3cf6b835ce4cce48f4cb033"), + nonce: &hex!("019a55c98615c022afff9644"), + plaintext: &hex!(""), + aad: &hex!("c3fb518ddb2d73417e243359a0ed8c126750eb163e7bd845637159397075e3db1db72fe2f0e13b599c333c473feb2245"), + ciphertext: &hex!(""), + tag: &hex!("467cfad5af11852d6eca289c86f967ad"), + }, + TestVector { + key: &hex!("13ba95606b01af035bf961e39852e34b"), + nonce: &hex!("9ec9cf3b002cfed9e761934f"), + plaintext: &hex!(""), + aad: &hex!("bb9de563836d1f1b1de964514ecebb8ad10501db562280b7bd98804814735817908b2856cafadecd40b04832fbde2bfb"), + ciphertext: &hex!(""), + tag: &hex!("172a3bcbc5001dfd3815175a88f7056c"), + }, + TestVector { + key: &hex!("1c97da5fc5a9640f289622842408cba2"), + nonce: &hex!("6d765a988e934588163e29b7"), + plaintext: &hex!(""), + aad: &hex!("1026a590816d2e1aa67aa0d13d50a8413af4d8ee9b1fa5ceb8deacc9f41e8e764b3ac15f98295e8800adf6a7175448cd"), + ciphertext: &hex!(""), + tag: &hex!("4945a79d5edbb934c5cf94395c359deb"), + }, + TestVector { + key: &hex!("8dd46f271a201cc21ca0823248157e6b"), + nonce: &hex!("1821b310ce2dba999cdf7576"), + plaintext: &hex!(""), + aad: &hex!("34ba409997ceba065f4a5457078a9e232a84f594011aecfdbfbd24a802ca129e01cb1327e265b4a9004fb4c5003fffd3"), + ciphertext: &hex!(""), + tag: &hex!("304cc2cd2fcdd4abc844bc9c1cbe0241"), + }, + TestVector { + key: &hex!("0c545d95333b6acf8b2928f3efd083de"), + nonce: &hex!("31de89d07e7577956fa95ef3"), + plaintext: &hex!(""), + aad: &hex!("5574d65f5afffb2d31cca8f58cf5945b83553cd45d2dba0e05fa54e42aa3f5a051e1624de16d4b93cbab7988c6d95f8c"), + ciphertext: &hex!(""), + tag: &hex!("4ed91cfe90a49900e0565697bc82b659"), + }, + TestVector { + key: &hex!("790b39f301383a82b377f585d3bf0f26"), + nonce: &hex!("2fd9c142b5fc62e87efff1fd"), + plaintext: &hex!(""), + aad: &hex!("45634e0afc59ae9f6e30f7f5fe43cf5a4e1f78d0aebb9e5a7ad9d86f25278e521f4845d49d6cb533cac6439839647fd0"), + ciphertext: &hex!(""), + tag: &hex!("69637c3f9233da23f8df7b09e8cfb252"), + }, + TestVector { + key: &hex!("8f63652632d07b2a4a83c26dedd32657"), + nonce: &hex!("747bee0e1d462a9016f1468d"), + plaintext: &hex!(""), + aad: &hex!("9c00ff969b55a497dc523fa0cedaa339dc3c6ce18e61c7bf800c361201351bc49728c3bb15067e906162ee791b8d333a"), + ciphertext: &hex!(""), + tag: &hex!("bd5a0cbf859a6133a7f2d504d97cae05"), + }, + TestVector { + key: &hex!("20b5b6b854e187b058a84d57bc1538b6"), + nonce: &hex!("94c1935afc061cbf254b936f"), + plaintext: &hex!(""), + aad: &hex!("ca418e71dbf810038174eaa3719b3fcb80531c7110ad9192d105eeaafa15b819ac005668752b344ed1b22faf77048baf03dbddb3b47d6b00e95c4f005e0cc9b7627ccafd3f21b3312aa8d91d3fa0893fe5bff7d44ca46f23afe0"), + ciphertext: &hex!(""), + tag: &hex!("b37286ebaf4a54e0ffc2a1deafc9f6db"), + }, + TestVector { + key: &hex!("7aa53188a9c597126a10d248603ebb62"), + nonce: &hex!("aa45ca5dac41a825c45d36bf"), + plaintext: &hex!(""), + aad: &hex!("417fd5147d56de0c74329597824ec2788a344fb60b403edf0187afa12e72a05009bb70f83ccad11efa487c1965cf84feac067c1ffdbf531fca97c554f875c4a1a1d3ab3c53c8a74ef3ee9415a87e231699c82d764debeda18132"), + ciphertext: &hex!(""), + tag: &hex!("997bf84654bb9616c0cc9b45f82c7673"), + }, + TestVector { + key: &hex!("72b5848ed1d2badbd427e16fc3b3e44d"), + nonce: &hex!("a84c7e928dc6e6379a513a20"), + plaintext: &hex!(""), + aad: &hex!("1c0dfcecbd7bb0e680ce042d08b2d9a741267bd1da768df2ba08379233a9973f14928e9da6353768b9b2601c033fd964b16a16daaa3ea35ad7cef7e31eb1f7340aa34e8bfc08b0a6e6205292570ced43316876d0d499d9192e6b"), + ciphertext: &hex!(""), + tag: &hex!("270cd786b95e6820cdb65a231b7530ed"), + }, + TestVector { + key: &hex!("6d0512ebf2e73d63f42849c57f073fd0"), + nonce: &hex!("c1c46927c74c03f19342c33a"), + plaintext: &hex!(""), + aad: &hex!("28bf8903b2dfb7e69f1a735121c7efe9a4c42b6a295327bceb0246c85d782ce62bf075dbdf6e8ec6589c26d30696ccceef03870bd0abfd26d30600eafc65613740b54d777d379e8aacf241ecfba11b060186ac065db171aab099"), + ciphertext: &hex!(""), + tag: &hex!("a686f5941ceb510e126a6316e3404dc0"), + }, + TestVector { + key: &hex!("6438bc79520def5db58e49639774687a"), + nonce: &hex!("d682b47418ceb5bc09c713c2"), + plaintext: &hex!(""), + aad: &hex!("d252b164ae559ed155c8417b96652529df151f24ccf1ce98d0c7ddf293f4f1236630a19b24dc23978d3377a099065d0ba71d4bb8a7dc0cb76760ca7c4a0e12c8cb56c6102646323c08c4f4f56226fd5b71a84590913ad20da287"), + ciphertext: &hex!(""), + tag: &hex!("04e78796dbf42e9ffa6bb9e346581f13"), + }, + TestVector { + key: &hex!("117a0aa592fff17ae36c94917db16c65"), + nonce: &hex!("c3537be6029d54ffefab2730"), + plaintext: &hex!(""), + aad: &hex!("29e959b96817547ae06bf85fe164e82a2693f82a7aeb66d535f0d2c3bffd1ba18e94ef457939f0c0733eda4738d136380fc876075c4943220237a5929b01b32da2bc2a6afd6ae1d89fd470093835962ff6708bb39ba365202f56"), + ciphertext: &hex!(""), + tag: &hex!("b87fcc4d5c484e68ea52c01b55ffa438"), + }, + TestVector { + key: &hex!("5d995a338ed60f8ab0b59da6c9a40c52"), + nonce: &hex!("2723c54e31c5c57f0236e816"), + plaintext: &hex!(""), + aad: &hex!("239c80683feb6afd38f8759a27cb5f350fbc2f757838c40858c9d08f699cc56c4236f4a77bd80df0e8e41d5f9ba732db2e0a3a5e952ede7bfdd5fcbebd23d07271134db5b82461537c47e2ca51b348b0830f5ee575ad4b4414dc"), + ciphertext: &hex!(""), + tag: &hex!("94356a3bfaf07f2ef0ebe3a507076b16"), + }, + TestVector { + key: &hex!("c8a863a1ebaf10c0fc0e80df12444e6e"), + nonce: &hex!("c3e8cdf086827fee7095d0ea"), + plaintext: &hex!(""), + aad: &hex!("9927da88c5d336256699c76845e946dc53c87bf0e11e4bec9450981602b32010d2b52bfc91283a6329d455598998ede2e61e352e553110154b4da5ce668d664b83f671c010bf220b7d32b34f4ca69b66cc87233d792337cb2bff"), + ciphertext: &hex!(""), + tag: &hex!("098837de27707ea3593e31ceb8276732"), + }, + TestVector { + key: &hex!("69cc28b161f214a580e6ba4bc2e3de9d"), + nonce: &hex!("f2a566f9cf83fd280c8fe08e"), + plaintext: &hex!(""), + aad: &hex!("f8c5263a4e06b49e184589a1e071978643c353aa27b4817fe39e45abc442e22ab5d683bcee5dbbd589fa583f171bb59536addd2b6cefd49823413005efb2a665e26a6029c927d3891cb0d4f23e8ccc60cfd02ce8978c451ddc11"), + ciphertext: &hex!(""), + tag: &hex!("c9c806cb8b1a889809695c2ec5a7a86e"), + }, + TestVector { + key: &hex!("bbf35920fcab2cedaafdf3f00321f544"), + nonce: &hex!("2c7ee3ff1df84f3650bc9298"), + plaintext: &hex!(""), + aad: &hex!("a75f50ba9a50f48799594b6195b3125ed92df73144bfcb624ce67323d834ba1afaf0df4c6c022c11d48bd75c86675a5927ac1250030f720f97498d4fe0787bae655dc5537ac1bcac198a893f9af7c2ef9b971dd64f7e7b62603e"), + ciphertext: &hex!(""), + tag: &hex!("c7cd3f938f4ab18642d86234edfc17ed"), + }, + TestVector { + key: &hex!("9690de669702ba72aeb934f5ac50e03c"), + nonce: &hex!("da8713fe2b2058c438aff260"), + plaintext: &hex!(""), + aad: &hex!("f30ee950da37c7224b5c93e9a29cafdbf8e2070f65c226244b1a683459e0c5c11c9b77c8fc286d4298a5b9cd1fee3e13d4690a88780d35b558b5d9e52b1a67fc8857076691dca7f5fe8ef22065cc5d9c003ffd25ebe23e61440e"), + ciphertext: &hex!(""), + tag: &hex!("7f92914518ddbe842b06771f64c40f59"), + }, + TestVector { + key: &hex!("e5d8c6e2ac6935c85e81ee0ef723eacf"), + nonce: &hex!("c73140ee90cc1dcf88457da2"), + plaintext: &hex!(""), + aad: &hex!("f6c267a6ae5ce3cf4bcdf59cfd1f777c66133e0ec4772785f33e5fa800d310b24b5773bc603a76b30fc32328a8e40f02f823a813a9e4b4fac726e992c183bd0815111c1d3a35884a4eff32027ba60dba679b469af31bc50c0591"), + ciphertext: &hex!(""), + tag: &hex!("f938fd0d8c148d81765109df66dac9aa"), + }, + TestVector { + key: &hex!("e23458f6b304c2d8feb3dedd3741bc24"), + nonce: &hex!("4619036b50ba012fe50be1d7"), + plaintext: &hex!(""), + aad: &hex!("74bfdc6bc4bfc38d666b985cfe043c67798b2db98f149268dba24436cab83e9a91f244ffc5748c93f8df339ae24ba4318c50da011ab368d3167c16e503309b01351a11f14d067cc6769b9989c7d952e3315011ee2ea034db8cb8"), + ciphertext: &hex!(""), + tag: &hex!("6053ab80c746821ec50c97e5a1424a85"), + }, + TestVector { + key: &hex!("5372ac5d3b08d860919110bdeb7f31df"), + nonce: &hex!("06ca979d8c250d9b7be45573"), + plaintext: &hex!(""), + aad: &hex!("e1f958834e63c75c8c758bafaa2f257ea5689d0d55b877b4d67b8b73c25ce24e9b094b976db920a159968da9d33c511aa8999aba42b8bb886e6545dd108693150af357496bb5898b4e8f725d50ef474afb836a3358da2217bb93"), + ciphertext: &hex!(""), + tag: &hex!("9338e14fe0b08a969a104c828528a6a4"), + }, + TestVector { + key: &hex!("bf1cb49e980cec0b153fe3573875ac6c"), + nonce: &hex!("5426669d25524036fbe81e89"), + plaintext: &hex!(""), + aad: &hex!("b336949766e9948a7e6f36a2d377b84a25c4b4988794f3deab7af4b14a12dac641e25fe2ae9ff53450ace1513acd0b284a490b455f04f40af94418c8792ec1a0983fb1d9a31d93dc3ed2c75e6a6ce092111eabad039bac2a49f6"), + ciphertext: &hex!(""), + tag: &hex!("e2996a2b3b6bf52217cfc4d0f5bb351b"), + }, + TestVector { + key: &hex!("7fddb57453c241d03efbed3ac44e371c"), + nonce: &hex!("ee283a3fc75575e33efd4887"), + plaintext: &hex!("d5de42b461646c255c87bd2962d3b9a2"), + aad: &hex!(""), + ciphertext: &hex!("2ccda4a5415cb91e135c2a0f78c9b2fd"), + tag: &hex!("b36d1df9b9d5e596f83e8b7f52971cb3"), + }, + TestVector { + key: &hex!("ab72c77b97cb5fe9a382d9fe81ffdbed"), + nonce: &hex!("54cc7dc2c37ec006bcc6d1da"), + plaintext: &hex!("007c5e5b3e59df24a7c355584fc1518d"), + aad: &hex!(""), + ciphertext: &hex!("0e1bde206a07a9c2c1b65300f8c64997"), + tag: &hex!("2b4401346697138c7a4891ee59867d0c"), + }, + TestVector { + key: &hex!("77b0a58a1e60541e5ea3d4d42007940e"), + nonce: &hex!("ae7a27904d95fe800e83b345"), + plaintext: &hex!("6931a3ea07a9e95207334f0274a454dd"), + aad: &hex!(""), + ciphertext: &hex!("76e39fad4000a07d35d879b785bd7fca"), + tag: &hex!("5cb3724712f129f86b7927f13b45c835"), + }, + TestVector { + key: &hex!("caaa3f6fd31822ed2d2125f225b0169f"), + nonce: &hex!("7f6d9041483e8c1412fa552a"), + plaintext: &hex!("84c907b11ae3b79fc4451d1bf17f4a99"), + aad: &hex!(""), + ciphertext: &hex!("fdb4aafa3519d3c055be8b347764ea33"), + tag: &hex!("89e43bfead01692c4ebe656586e3fbe3"), + }, + TestVector { + key: &hex!("02c8e81debc563e99cd262bfc64b0e11"), + nonce: &hex!("b49057c9778d8c02fe00d029"), + plaintext: &hex!("ca2a51e9d05e96e6f1d14ced36811c5c"), + aad: &hex!(""), + ciphertext: &hex!("5db602fb31bb9268d233bee0dd6b87ae"), + tag: &hex!("789d2be2cc70b7c389b31912e1c0a041"), + }, + TestVector { + key: &hex!("4e625a3edc61f0cb2f002da8f8a70245"), + nonce: &hex!("66d632dd5ca10b08d4d8f97b"), + plaintext: &hex!("0b76d498add6e09c96d7694e5d620bd5"), + aad: &hex!(""), + ciphertext: &hex!("17bdc7ef5649bec9cf6c565ce33cf889"), + tag: &hex!("3f7944bad062605f937ff6d6598a7651"), + }, + TestVector { + key: &hex!("41ab3fc488f8d4a820e65b9d41a87de3"), + nonce: &hex!("9b5d27d75a0571e93f581885"), + plaintext: &hex!("5ed0836e0a52777599800d4fe754ccbe"), + aad: &hex!(""), + ciphertext: &hex!("88c0eb8c33a10a22e7561866566b191f"), + tag: &hex!("83e885802a594a8b008a94aa7ef06907"), + }, + TestVector { + key: &hex!("0047184240a5948ed55701eac2c4c26c"), + nonce: &hex!("a3ab8da22648c2453cdef55b"), + plaintext: &hex!("89ee9502871be15ee4a8c47ab123bfc9"), + aad: &hex!(""), + ciphertext: &hex!("8b5cb59e7ad2e15c40d5fbcde28a0d17"), + tag: &hex!("538e79f880e2f65c72148f5ade4080a1"), + }, + TestVector { + key: &hex!("735c5a4ff2438852df3530c23590ac28"), + nonce: &hex!("7bee7c6938f1ae59671e2ddb"), + plaintext: &hex!("479e8d3bf0de4ce7cd4377d2ed3925cd"), + aad: &hex!(""), + ciphertext: &hex!("2ca09b58178fbbfb82556599b92329a3"), + tag: &hex!("2e3cf2895f111ec2a86508c36a24e45d"), + }, + TestVector { + key: &hex!("016dbb38daa76dfe7da384ebf1240364"), + nonce: &hex!("0793ef3ada782f78c98affe3"), + plaintext: &hex!("4b34a9ec5763524b191d5616c547f6b7"), + aad: &hex!(""), + ciphertext: &hex!("609aa3f4541bc0fe9931daad2ee15d0c"), + tag: &hex!("33afec59c45baf689a5e1b13ae423619"), + }, + TestVector { + key: &hex!("2d176607883aface75011d14818f1be6"), + nonce: &hex!("02162c3635bf6d543e1cc148"), + plaintext: &hex!("71905ad5df601d056effd80dd7333662"), + aad: &hex!(""), + ciphertext: &hex!("1b68598e1676d2cfd37aa00396fa9676"), + tag: &hex!("5d060aa8a729774da001aa9fdef2b3d2"), + }, + TestVector { + key: &hex!("94fd0269a0ce813133626f93c4af7e6f"), + nonce: &hex!("11fc3928028dfa34db06a1bc"), + plaintext: &hex!("a1aefec976cd87cf8a4c21bbe902f7b4"), + aad: &hex!(""), + ciphertext: &hex!("b1baf8c58cdec88238b1b0ab0b40337d"), + tag: &hex!("882f865df7da529f768d4944e8387f69"), + }, + TestVector { + key: &hex!("a7bec5e24f0db2629a257d02fdfaea02"), + nonce: &hex!("9d2ec94b927327793583b818"), + plaintext: &hex!("a17bc5d428700f94c641e74aaacf2c5d"), + aad: &hex!(""), + ciphertext: &hex!("d460fda5b24425b5caa8176c8c67b3a9"), + tag: &hex!("0df724340b8ca56e8dea6bbeb4b55c35"), + }, + TestVector { + key: &hex!("39d945a00e05d70a16e61334d2010209"), + nonce: &hex!("1f931448e9013ec4ec61af0c"), + plaintext: &hex!("9dd90ebfc054da214cbb30db7f75c692"), + aad: &hex!(""), + ciphertext: &hex!("e4cb765408697cf85917a7a9264086e4"), + tag: &hex!("fe9a1fe7a58d66e3b922693a163c1ff4"), + }, + TestVector { + key: &hex!("6620ca65f72de7b865de731928a4723e"), + nonce: &hex!("e6428b6b77e9b6993b809aef"), + plaintext: &hex!("7044f7c27d776f6a7d43abea35908de4"), + aad: &hex!(""), + ciphertext: &hex!("a1c5634a07d05ca909dba87bf02228e4"), + tag: &hex!("d8b40a60a65237337db05b045de8074c"), + }, + TestVector { + key: &hex!("c939cc13397c1d37de6ae0e1cb7c423c"), + nonce: &hex!("b3d8cc017cbb89b39e0f67e2"), + plaintext: &hex!("c3b3c41f113a31b73d9a5cd432103069"), + aad: &hex!("24825602bd12a984e0092d3e448eda5f"), + ciphertext: &hex!("93fe7d9e9bfd10348a5606e5cafa7354"), + tag: &hex!("0032a1dc85f1c9786925a2e71d8272dd"), + }, + TestVector { + key: &hex!("599eb65e6b2a2a7fcc40e51c4f6e3257"), + nonce: &hex!("d407301cfa29af8525981c17"), + plaintext: &hex!("a6c9e0f248f07a3046ece12125666921"), + aad: &hex!("10e72efe048648d40139477a2016f8ce"), + ciphertext: &hex!("1be9359a543fd7ec3c4bc6f3c9395e89"), + tag: &hex!("e2e9c07d4c3c10a6137ca433da42f9a8"), + }, + TestVector { + key: &hex!("2d265491712fe6d7087a5545852f4f44"), + nonce: &hex!("c59868b8701fbf88e6343262"), + plaintext: &hex!("301873be69f05a84f22408aa0862d19a"), + aad: &hex!("67105634ac9fbf849970dc416de7ad30"), + ciphertext: &hex!("98b03c77a67831bcf16b1dd96c324e1c"), + tag: &hex!("39152e26bdc4d17e8c00493fa0be92f2"), + }, + TestVector { + key: &hex!("1fd1e536a1c39c75fd583bc8e3372029"), + nonce: &hex!("281f2552f8c34fb9b3ec85aa"), + plaintext: &hex!("f801e0839619d2c1465f0245869360da"), + aad: &hex!("bf12a140d86727f67b860bcf6f34e55f"), + ciphertext: &hex!("35371f2779f4140dfdb1afe79d563ed9"), + tag: &hex!("cc2b0b0f1f8b3db5dc1b41ce73f5c221"), + }, + TestVector { + key: &hex!("7b0345f6dcf469ecf9b17efa39de5359"), + nonce: &hex!("b15d6fcde5e6cf1fa99ba145"), + plaintext: &hex!("822ae01a0372b6aa46c2e5bf19db92f2"), + aad: &hex!("72e9cb26885154d4629e7bc91279bb19"), + ciphertext: &hex!("382e440694b0c93be8dd438e37635194"), + tag: &hex!("2fa042bff9a9cd35e343b520017841bb"), + }, + TestVector { + key: &hex!("9db91a40020cdb07f88769309a6ac40b"), + nonce: &hex!("f89e1b7e598cc2535a5c8659"), + plaintext: &hex!("f4a5003db4a4ebbc2fdb8c6756830391"), + aad: &hex!("70910598e7abd4f0503ecd9e21bdafb5"), + ciphertext: &hex!("40d7fc4ccc8147581f40655a07f23ee9"), + tag: &hex!("243331b48404859c66af4d7b2ee44109"), + }, + TestVector { + key: &hex!("e2f483989b349efb59ae0a7cadc74b7a"), + nonce: &hex!("3338343f9b97ebb784e75027"), + plaintext: &hex!("14d80ad66e8f5f2e6c43c3109e023a93"), + aad: &hex!("8b12987e600ff58df54f1f5e62e59e61"), + ciphertext: &hex!("43c2d68384d486e9788950bbb8cd8fd1"), + tag: &hex!("47d7e9144ff0ed4aa3300a944a007882"), + }, + TestVector { + key: &hex!("5c1155084cc0ede76b3bc22e9f7574ef"), + nonce: &hex!("9549e4ba69a61cad7856efc1"), + plaintext: &hex!("d1448fa852b84408e2dad8381f363de7"), + aad: &hex!("e98e9d9c618e46fef32660976f854ee3"), + ciphertext: &hex!("f78b60ca125218493bea1c50a2e12ef4"), + tag: &hex!("d72da7f5c6cf0bca7242c71835809449"), + }, + TestVector { + key: &hex!("2352503740a4e1b22dcc9c002f53bd11"), + nonce: &hex!("474ecccc3182e03c80a7be74"), + plaintext: &hex!("dc1c35bc78b985f2d2b1a13ce635dd69"), + aad: &hex!("a1bc98dacec4b6aa7fee6dfa0802f21a"), + ciphertext: &hex!("3f6f4daf6d07743b9bd2a069d3710834"), + tag: &hex!("b9c2b319adbd743f5e4ffd44304a1b5f"), + }, + TestVector { + key: &hex!("fc1f971b514a167865341b828a4295d6"), + nonce: &hex!("8851ea68d20ce0beff1e3a98"), + plaintext: &hex!("2fec17b1a9570f6651bbe9a657d82bce"), + aad: &hex!("ece8d5f63aebda80ebde4b750637f654"), + ciphertext: &hex!("2d27e5fa08e218f02b2e36dfad87a50e"), + tag: &hex!("eb9966774c588a31b71c4d8daa495e9e"), + }, + TestVector { + key: &hex!("00ef3c6762be3fbab38154d902ff43b5"), + nonce: &hex!("c3c1c3079cda49a75a53b3cc"), + plaintext: &hex!("be425e008e9b0c083b19a2d945c2ede9"), + aad: &hex!("714fa1d6904187b3c5c08a30dffc86e8"), + ciphertext: &hex!("c961a1758dcf91e539658372db18968e"), + tag: &hex!("eaf9bda9b3322f501f7329cb61c1c428"), + }, + TestVector { + key: &hex!("2d70b9569943cc49cdef8495bdb6f0e6"), + nonce: &hex!("b401d0f50880a6211fde9d9c"), + plaintext: &hex!("47a87a387944f739bd3cb03e0e8be499"), + aad: &hex!("592e7276bda066327f2b3cd8cc39f571"), + ciphertext: &hex!("c1b2af4d273231e71e7e066c206bf567"), + tag: &hex!("c68d8d3cf8b89e6b15f623d60fef60bd"), + }, + TestVector { + key: &hex!("775cb7f8dc73f04fe4f9d22126bb7b57"), + nonce: &hex!("81ceb17deee19b8153ff927c"), + plaintext: &hex!("8242c6c0eed6d5d1ab69cd11dbe361d0"), + aad: &hex!("97e07cd65065d1edc863192de98bc62c"), + ciphertext: &hex!("580f063ab1a4801d279e4ee773200abe"), + tag: &hex!("29e4d7e054a6b0a4e01133573fbe632b"), + }, + TestVector { + key: &hex!("58ba3cb7c0a0cf5775002bf3b112d051"), + nonce: &hex!("bb923c93ddca303ab131238d"), + plaintext: &hex!("6b93d2d92de05b53769ec398ab8097dc"), + aad: &hex!("0898ea55c0ca0594806e2dc78be15c27"), + ciphertext: &hex!("d0564006b1897bf21922fef4f6386fd4"), + tag: &hex!("3a92f3c9e3ae6b0c69dcb8868d4de27c"), + }, + TestVector { + key: &hex!("955b761de8e98f37acb41259fa308442"), + nonce: &hex!("a103db8a0825e606b70427fc"), + plaintext: &hex!("d18344c86caffc4237d2daae47817b13"), + aad: &hex!("c2d0d8b77a6fd03ced080e0f89de8a4b"), + ciphertext: &hex!("065d228c1289007a682aa847a36b6f30"), + tag: &hex!("fb367f47922d67c84bf47aabb2b98421"), + }, + TestVector { + key: &hex!("d4a22488f8dd1d5c6c19a7d6ca17964c"), + nonce: &hex!("f3d5837f22ac1a0425e0d1d5"), + plaintext: &hex!("7b43016a16896497fb457be6d2a54122"), + aad: &hex!("f1c5d424b83f96c6ad8cb28ca0d20e475e023b5a"), + ciphertext: &hex!("c2bd67eef5e95cac27e3b06e3031d0a8"), + tag: &hex!("f23eacf9d1cdf8737726c58648826e9c"), + }, + TestVector { + key: &hex!("e8899345e4d89b76f7695ddf2a24bb3c"), + nonce: &hex!("9dfaeb5d73372ceb06ca7bbe"), + plaintext: &hex!("c2807e403e9babf645268c92bc9d1de6"), + aad: &hex!("fed0b45a9a7b07c6da5474907f5890e317e74a42"), + ciphertext: &hex!("8e44bf07454255aa9e36eb34cdfd0036"), + tag: &hex!("2f501e5249aa595a53e1985e90346a22"), + }, + TestVector { + key: &hex!("c1629d6320b9da80a23c81be53f0ef57"), + nonce: &hex!("b8615f6ffa30668947556cd8"), + plaintext: &hex!("65771ab52532c9cdfcb3a9eb7b8193df"), + aad: &hex!("5f2955e4301852a70684f978f89e7a61531f0861"), + ciphertext: &hex!("c2a72d693181c819f69b42b52088d3a2"), + tag: &hex!("cadaee305d8bb6d70259a6503280d99a"), + }, + TestVector { + key: &hex!("196ed78281bb7543d60e68cca2aaa941"), + nonce: &hex!("6e7d2c8f135715532a075c50"), + plaintext: &hex!("15b42e7ea21a8ad5dcd7a9bba0253d44"), + aad: &hex!("d6fc98c632d2e2641041ff7384d92a8358ae9abe"), + ciphertext: &hex!("06e5cc81c2d022cb2b5de5a881c62d09"), + tag: &hex!("28e8cad3346ce583d5eebaa796e50974"), + }, + TestVector { + key: &hex!("55fe8a1bdc6806ed2f4a84891db943a0"), + nonce: &hex!("af4d0ba0a90f1e713d71ae94"), + plaintext: &hex!("81315972f0b1aeaa005363e9eca09d7a"), + aad: &hex!("677cd4e6c0a67913085dba4cc2a778b894e174ad"), + ciphertext: &hex!("c47bcb27c5a8d9beb19fee38b90861b7"), + tag: &hex!("e061ee4868edf2d969e875b8685ca8a9"), + }, + TestVector { + key: &hex!("6d86a855508657f804091be2290a17e0"), + nonce: &hex!("65dce18a4461afd83f1480f5"), + plaintext: &hex!("0423bd1c8aea943637c7c3b0ca61d54b"), + aad: &hex!("e0ef8f0e1f442a2c090568d2af336ec59f57c896"), + ciphertext: &hex!("53505d449369c9bcd8a138740ea6602e"), + tag: &hex!("86f928b4532825af9cac3820234afe73"), + }, + TestVector { + key: &hex!("66bd7b5dfd0aaaed8bb8890eee9b9c9a"), + nonce: &hex!("6e92bf7e8fd0fb932451fdf2"), + plaintext: &hex!("8005865c8794b79612447f5ef33397d0"), + aad: &hex!("60459c681bda631ece1aacca4a7b1b369c56d2bb"), + ciphertext: &hex!("83b99253de05625aa8e68490bb368bb9"), + tag: &hex!("65d444b02a23e854a85423217562d07f"), + }, + TestVector { + key: &hex!("e7e825707c5b7ccf6cfc009dd134f166"), + nonce: &hex!("dd0c7a9c68d14e073f16a7a0"), + plaintext: &hex!("88b1b11e47dfe2f81096c360cf1e30e7"), + aad: &hex!("11c69ed187f165160683e7f0103038b77512460b"), + ciphertext: &hex!("550fa499a7cb4783c1957288a5cc557f"), + tag: &hex!("5d2c2f71a2e6ad9b3001bdbf04690093"), + }, + TestVector { + key: &hex!("92591b15e28ce471316c575f3963103a"), + nonce: &hex!("2c30d215e5c950f1fe9184f6"), + plaintext: &hex!("dc8842b3c146678627600742126ea714"), + aad: &hex!("46e1bd5fa646e4605e2fbec700fa592a714bc7ef"), + ciphertext: &hex!("a541d3d8f079bfe053ba8835e02b349d"), + tag: &hex!("d322a924bf44809cb8cfe8c4b972a307"), + }, + TestVector { + key: &hex!("74f08353d4139ddad46691da888ee897"), + nonce: &hex!("e2619217dc8b093e2c7c5b78"), + plaintext: &hex!("1690d6c8f95ef5ac35c56e3129717b44"), + aad: &hex!("92277cf78abe24720ce219bba3a7a339a2e011b2"), + ciphertext: &hex!("b413557c0df29e3072bb1b326e2002dc"), + tag: &hex!("3bb6273687ec6a3f4a0366f1b54bd318"), + }, + TestVector { + key: &hex!("5c951cd038a3c65cd65325bfdde86964"), + nonce: &hex!("3bf5623fd1155f1036ea893f"), + plaintext: &hex!("b609ec6673e394176dd982b981a5436b"), + aad: &hex!("dc34014513fd0eede8e9ca44a16e400a5f89cdd0"), + ciphertext: &hex!("009cf623e57a3129626a30489b730607"), + tag: &hex!("1d202825db813c0fc521c284dd543fff"), + }, + TestVector { + key: &hex!("72301c093ba804671c44a6bf52839d9c"), + nonce: &hex!("87cc7e6579cc92822f5744f6"), + plaintext: &hex!("d59bbae4ff3e3755c0a61a9b6d3e234c"), + aad: &hex!("f461946c4feba79c18366555d85311248d269c87"), + ciphertext: &hex!("ee743d29dcbaa084fda91eb48b3be961"), + tag: &hex!("07934a5372d41928f2ee7d4bb8c18982"), + }, + TestVector { + key: &hex!("39b4f826b520830941b3b1bcd57e41d5"), + nonce: &hex!("ca32ac523fe7dfefe415cba1"), + plaintext: &hex!("aa2b7a6c918ed6715441d046858b525f"), + aad: &hex!("c586cd939b27821695b4ee4dd799fb0e3449a80e"), + ciphertext: &hex!("8b64f5ea9a8cb521c66df9c74d4b7ecd"), + tag: &hex!("3db56a792b67ac6d0c4001e17f446111"), + }, + TestVector { + key: &hex!("79449e5f670d55ee2d91ca994a267a8c"), + nonce: &hex!("c779da00d672811d8a5124f1"), + plaintext: &hex!("767e120debd8a1dc8d2db8b7f4750741"), + aad: &hex!("54780846dc3df77c8d90c9f2decb0738da36fbda"), + ciphertext: &hex!("eb864412add08abb4f89d72d412d0085"), + tag: &hex!("494a547f617840267d3fed5280e3eb30"), + }, + TestVector { + key: &hex!("cc90c2f37f970f97ac97e3e3b88e8ae3"), + nonce: &hex!("67bcc08f223f12107e4d9122"), + plaintext: &hex!("b0fe0dcdcd526017f551da1f73ef9fe1"), + aad: &hex!("065acdc19233af4be7c067744aabab024c677c5e"), + ciphertext: &hex!("501cda2c954f830e8922c3d7405b5ee1"), + tag: &hex!("9deee5d0e4778a9f770367f19c74daef"), + }, + TestVector { + key: &hex!("89850dd398e1f1e28443a33d40162664"), + nonce: &hex!("e462c58482fe8264aeeb7231"), + plaintext: &hex!("2805cdefb3ef6cc35cd1f169f98da81a"), + aad: &hex!("d74e99d1bdaa712864eec422ac507bddbe2b0d4633cd3dff29ce5059b49fe868526c59a2a3a604457bc2afea866e7606"), + ciphertext: &hex!("ba80e244b7fc9025cd031d0f63677e06"), + tag: &hex!("d84a8c3eac57d1bb0e890a8f461d1065"), + }, + TestVector { + key: &hex!("cdb850da94d3b56563897c5961ef3ad8"), + nonce: &hex!("841587b7174fb38fb7b3626e"), + plaintext: &hex!("c16837cb486c04bd30dcae4bcd0bc098"), + aad: &hex!("de33e6d20c14796484293dff48caffc784367f4bd7b957512ec026c0abc4a39217af0db35be154c45833b97a0b6454df"), + ciphertext: &hex!("f41a9ba9ff296ebdbe3fdd8b1c27dcdb"), + tag: &hex!("506cc2136c15238b0f24f61b520fb5e6"), + }, + TestVector { + key: &hex!("45551710464a9ea105a30e056167cfb0"), + nonce: &hex!("5727688c9e74bcd23c14a345"), + plaintext: &hex!("6adeaaa151b58c337471653c99affbdc"), + aad: &hex!("3eebcdc5c5e9970b3fca94bd0d28ead70d1f36a94f27780472bc3cc9ff39dd7b7e3a76ebce967d6ae5724ad904dc5548"), + ciphertext: &hex!("ec18f1d675dd056baeb374829ce45a33"), + tag: &hex!("378bdc4c34753a1284b654af049b853a"), + }, + TestVector { + key: &hex!("c8650e8695396b84a3fdeea8f95c8215"), + nonce: &hex!("5a1c26d3848910137df9f76c"), + plaintext: &hex!("88aecd97435d97e2dff8763f640a5640"), + aad: &hex!("3dace39b7284ea2786a6bc670ced1c7cc0c28c4ae4e7494a6d834eb09260b68898b914d5a6b0b5334eff9669f233aeb8"), + ciphertext: &hex!("49a9398c70a89c0e43ce7a7bd7a90c58"), + tag: &hex!("8509ef5fa8046a48a5f081e5215db2eb"), + }, + TestVector { + key: &hex!("76470ff92aaeeeb24172b823fce630b1"), + nonce: &hex!("c70088e92633688bebe3265b"), + plaintext: &hex!("ff4f74af151c292a0b35ba7049c9a5ad"), + aad: &hex!("a262fc02a3d0db113493d4179cc9ec806825f20f5864bb105c6116ea72f0284950ecc8a05dc548023853a657b67ce01e"), + ciphertext: &hex!("2404868e6bfee5ffe6ec851785618aab"), + tag: &hex!("b338a9ccf10d45dfd4e0ccb8a87b3c1a"), + }, + TestVector { + key: &hex!("247b0330aa35a8a855142f933d182581"), + nonce: &hex!("6df7990b60e41f1fac5f283f"), + plaintext: &hex!("fa979c20be9f7f7e802fd5ca55c14618"), + aad: &hex!("0cec69d6f6532bf781f5b0fe70e33e1cd68f8b2019aa73951baf978bc1141b51083a8e5c785c994b12ffeca01b6c94f4"), + ciphertext: &hex!("ca4b66a09606caae8a100ce994da9452"), + tag: &hex!("534188f439b929183d21109d962145ea"), + }, + TestVector { + key: &hex!("1ea5cdfe206130596b655bc6fb935fad"), + nonce: &hex!("0ec93072e726ec58352d5a90"), + plaintext: &hex!("1ac044b5f8b693fa236986ad1621edd8"), + aad: &hex!("d9da4741fda4821eb391a23f7f6b377bed923260b6f8c8ac9bbca4edef1bc2a48a45c8676cb598a668e28fe1103efa23"), + ciphertext: &hex!("33d387a3b73a590bfd78320ddad8c169"), + tag: &hex!("ef36d6c01b5a54bf06ba218aa237fa54"), + }, + TestVector { + key: &hex!("d5a707d2e3163fbd9fba2f12e8dd980c"), + nonce: &hex!("4a4ed3d33e5a1dd6befdb382"), + plaintext: &hex!("639331ff4efaadc93e92e58de9e886ee"), + aad: &hex!("f5392e014cbe2d33cd0a0497cf0398883338748491a8543991990f9958e4a827e190e6f5ce89baac5f3bef91dcb5858b"), + ciphertext: &hex!("c986c4c805092a51103176b56507dd95"), + tag: &hex!("5da4fe4e281e995d0c75587b4945ca85"), + }, + TestVector { + key: &hex!("3d2c604398c247e3ae7d90cc1e11f6cf"), + nonce: &hex!("5dfafa52cbb52f57ac304381"), + plaintext: &hex!("9c12cb73902608e7b2ea30da7397b66a"), + aad: &hex!("53e050b559308705376a23ee2b22b7642f06ab77a00259bf7bf28cf6665912af4b8901f8af76e982a8bcbafe5ea1aaf6"), + ciphertext: &hex!("7fe6b5a881c8a6b8e3e29f1a3819383b"), + tag: &hex!("c528fddf8166a5c0ec3f0295b2c3d7a6"), + }, + TestVector { + key: &hex!("a335f0577c876e61d94522d526159f57"), + nonce: &hex!("6ea85a74513f664a907fef80"), + plaintext: &hex!("db38cf3bb14825a6c11ac978fb516647"), + aad: &hex!("038af270aece9687e34c55ec30494e9f72b6a90ac43280a9b8e958353d8c02a83ed163c6924b7201759615779cd5661e"), + ciphertext: &hex!("7e81df8bf0b671e89a639d6432d44952"), + tag: &hex!("2180e6c8fe8fbb3394f9dfdc1c439d80"), + }, + TestVector { + key: &hex!("afb3ab51cf05e0cfa2ccc2c3c8f4b67f"), + nonce: &hex!("26a5d1667feae062c14663bc"), + plaintext: &hex!("26821b2fe21c26d20843af266fce1f16"), + aad: &hex!("130b15bde79749d0577bff6c98ab50f035abae041b0d5f666db27c262c0ed2a801c24feffcfe248cf3af5afcb6b0dd1a"), + ciphertext: &hex!("c5317ad695606124662453dbfb96a26d"), + tag: &hex!("2ace2fa75daa31fe4f2020cea9e71ec6"), + }, + TestVector { + key: &hex!("0b4d033bf0182bb06f8b9714d525ee74"), + nonce: &hex!("f0807dcca355aa339febada2"), + plaintext: &hex!("7c90709d6ea3e586bbf11913bb2b5261"), + aad: &hex!("9cb373a8b7cc61eb382dfe1ea17d78877e9366207c3a5161a1f34b75ac503dc20e4af9d9962b7d4fb0f39ac9666c660c"), + ciphertext: &hex!("bfdde06e311240348f04277504fd75fb"), + tag: &hex!("1dc5898c49e2dab4ae1a599547a76ab1"), + }, + TestVector { + key: &hex!("d32b7c3cb327780d1422116c40470ab0"), + nonce: &hex!("fcc79573051011685ee0d9e1"), + plaintext: &hex!("f015f4ab3bc159db9cf6b4bb6750db46"), + aad: &hex!("cdaae988d8bf01e24a4baf489893ee329b7d0dcfdef684fe3e382b200cbd5a7ea3e46be281b0c6cc00417d67f4d3db02"), + ciphertext: &hex!("48bec210f66942f877993e9486a678e7"), + tag: &hex!("e4a3821709626cc3006c805a75f067cc"), + }, + TestVector { + key: &hex!("086a0cdd8d520a8a695d17e869e03efc"), + nonce: &hex!("f0a463c0d1e28633da98b1e2"), + plaintext: &hex!("ad6fbcf714ab893455eddb3c5fb406dc"), + aad: &hex!("aa7ebac61f7e0b9da0d941e801730a393b2728476dfd065e2f6ef4b343bc2ba6e17c59a2e5381597948a73ff25493f8e"), + ciphertext: &hex!("f0b1a368b832ed35d54c80067a06a2ae"), + tag: &hex!("e3c80910db9ce1f3ad2519fe1ee2dfd7"), + }, + TestVector { + key: &hex!("e47e1e3a95627418ed659452a3c92d45"), + nonce: &hex!("78adcf3f732dd3787cb5490b"), + plaintext: &hex!("801efcab1e329a536a7b506c4a7509ec"), + aad: &hex!("41913a6c5c4dddae06f3c0f68e8ece139ca902fe340a820e7c40d895b35e8f4cba7809c7eed0b2b7ad45c6d152ec3053"), + ciphertext: &hex!("6751a4a5e0cc3c0f46cb5540937efde8"), + tag: &hex!("7b07d21a4cbadeedcadce817d9ab81be"), + }, + TestVector { + key: &hex!("bd7c5c63b7542b56a00ebe71336a1588"), + nonce: &hex!("87721f23ba9c3c8ea5571abc"), + plaintext: &hex!("de15ddbb1e202161e8a79af6a55ac6f3"), + aad: &hex!("a6ec8075a0d3370eb7598918f3b93e48444751624997b899a87fa6a9939f844e008aa8b70e9f4c3b1a19d3286bf543e7127bfecba1ad17a5ec53fccc26faecacc4c75369498eaa7d706aef634d0009279b11e4ba6c993e5e9ed9"), + ciphertext: &hex!("41eb28c0fee4d762de972361c863bc80"), + tag: &hex!("9cb567220d0b252eb97bff46e4b00ff8"), + }, + TestVector { + key: &hex!("11f47551416154006bf89e7594ea2082"), + nonce: &hex!("d546fcd3ff2a6a17461e9e94"), + plaintext: &hex!("d3783a3d7a1e091f9cb647bf45604457"), + aad: &hex!("49efdce48e821eb14eca5f1dd661f8b6b9a5a6917b08ec9486c29124ef1e7a9af2217494eecad3d8eef9fc22d29ce18d92006de1588c3b06f8db9fe809bede40908cef4f46d2c4b6f92ff5a8304362749143dab266de45bf5b4a"), + ciphertext: &hex!("e97988a6645b93a32e8296bb1dbcb8f9"), + tag: &hex!("399345f974a82a2a75007c84aa08dc1a"), + }, + TestVector { + key: &hex!("0736a1f074919dfe23bf2a828eac2b26"), + nonce: &hex!("5b2105166bcb15efc07f1c03"), + plaintext: &hex!("402b5b45dbbef7f1d955423e95cda404"), + aad: &hex!("f331a6f6d31de69f116b27fcd7f914aa0b2c3a09490360e7863417a2346030cc99b6ba389e65e0f10fe0815d383e6f98dd8bb97d29908560ce98e4bf177e42e14a7137cfd30b7dcb4d8655b3c03514e95adf698645584475865a"), + ciphertext: &hex!("6e9e79e29f3085183e0a7ac7f6ba1d67"), + tag: &hex!("84434e0c82b858ec27e61c54ecf6cd94"), + }, + TestVector { + key: &hex!("a3929d753fe45a6f326a85bb9f1e777f"), + nonce: &hex!("aed85f89844f061113004d2c"), + plaintext: &hex!("f024e796f449712b70d5c7fe5be5fe14"), + aad: &hex!("ecef72a7ae9e6bd15e63c8e9fb2a3a7c53eb9a88bc05296ff6f25544f681fff5289a099d38abb68316eed8215ead9ca0462065bee79fdb63b4405384053fdc68fe4124a883f50a2b4bc4df6e29383c2ceea424e4ac539b26c9ce"), + ciphertext: &hex!("349e770a7f7dc2fb41fa089bf723f6b6"), + tag: &hex!("26f12bc8777d724fe59ad4fe2b9757f4"), + }, + TestVector { + key: &hex!("85abd6c7b90314b29bbd293ff113637e"), + nonce: &hex!("f48f4ed2eb7b7aaeb017ee72"), + plaintext: &hex!("542c6fa7e7cdaf21e6f6b34517f26ab5"), + aad: &hex!("2b825d477eb96e0d8d787ee4f284eca567fb5214b47e26705389cf9fce4b8dbc49a152df5e4accb0adaa19b37c90fe7d6eb456a067f1c2b63b61f6d596209f7ee96c85aa48f1870e9338743edff1d8ffb61dbdab88b6755fa135"), + ciphertext: &hex!("8374f96f03780724a8e8d1f11768d44f"), + tag: &hex!("b41b53c46ae76eff505cfee47a8daaa3"), + }, + TestVector { + key: &hex!("0a2f29710feb7c86175a37c41e32fadd"), + nonce: &hex!("b190fdb91061a08ef82100b8"), + plaintext: &hex!("dfb6284ffd6cc195ed75db0c9faf5559"), + aad: &hex!("0af4d5c1ec517a1fc104aea7d513b591b603634fc558007e06d6cd22997407eb8281a742aef6e88ba08f10c64b423121d898bcd04c1f1d6c7c12d673aa1abb004a8525f1d7abc23c8724885179e292c0565a39d9f5c6d2369e37"), + ciphertext: &hex!("fb6cb6527b92dc2ef6a227e8067879aa"), + tag: &hex!("e01037f6e9d62c18b163a714f85a92cc"), + }, + TestVector { + key: &hex!("470d577137c5014b78137dc6b24efa6d"), + nonce: &hex!("4afa7f5766f8345a1b12042b"), + plaintext: &hex!("4745cb9a3ee3a76ae166dad5a1b62b1c"), + aad: &hex!("cfdd5d42e0d0127a1c0d3c4bad302ef23ab63d879fad71109f4792e5b21156dafdcec022fc323028a9fbcafe0c3606ed61b582bfa00ba6e5c9a1b13b976d67c14c79905a769399d967b0dd45f0e74967b67d7bb67d9466618fa1"), + ciphertext: &hex!("ca58ced863696bf80ae0191de1252333"), + tag: &hex!("246d451faab88511467e38b60c5b46c7"), + }, + TestVector { + key: &hex!("5cf9cfa4d367752f1354037e132bc948"), + nonce: &hex!("13e6a286a6c7b189974d7ea3"), + plaintext: &hex!("c7ef33e7abc8f298b2f224cf5218661d"), + aad: &hex!("65da4dbd6cef7fc8a09a766a6f5b474e9711a2d40faf841c467a8838e5c8cada3f1cca74ed3b4cdda6d5d334c91763e798b9c7891b291dbf46d89ddc728d72f93c95e081bc340448519aeccc6d105bf1696b7ff9c0b7c006444c"), + ciphertext: &hex!("ad88f4e7b980be05b3df0fc05a49d1eb"), + tag: &hex!("0ad15378f18f4338966e8e17951d8dad"), + }, + TestVector { + key: &hex!("d1dafd9e07ab0f903a9b00d6e353d67f"), + nonce: &hex!("8a96a0fe88f0c7e3077c38f4"), + plaintext: &hex!("bbe4ccbd26522d35ca0d483341385e2b"), + aad: &hex!("d3e1ecd06f79e6839767d957c4d715b4228f4cbca7afa429d860c5db2a6bf4a3ade2d00b91875fedbf9b09e9ee5e69182f326fb36fcc35475efb32e5eada3a6fa6046c8d0c0ee933b0e7f37c87b3eb8b9c0c2b457f8695d25875"), + ciphertext: &hex!("9d016cd94933c07c10b92af40eafac7d"), + tag: &hex!("022e2dd58ac862962e7fa0536bad87cb"), + }, + TestVector { + key: &hex!("da5236b254ee2ff5d7e73d7a09574177"), + nonce: &hex!("d2d91f5c302212557fd62bce"), + plaintext: &hex!("3aaa2a7b2605686c3444bb16df8c57a5"), + aad: &hex!("9ddfa05290e228e5eceb7e96de3a097afaa96d8d3e0d5ffc0e0116f43814f5b0947919267c2dbf0e5f52a97296e7826f2891dd4a043c845046c9ab9ae8327346c7695a72875b9062dd5578be8985edf9faa4917981aacc6f112f"), + ciphertext: &hex!("202a8e67d7f22ff83757fc9ef9b20a0f"), + tag: &hex!("a55bab242a4ebe73b52cc7202f5cdd57"), + }, + TestVector { + key: &hex!("c3e577da2a2b7fdd05c99dc6fc81ccdd"), + nonce: &hex!("dfa747b08f536915345766f0"), + plaintext: &hex!("b863120426d4cbd5c73124c7b0342fa7"), + aad: &hex!("872a6d0e3a0a3b32f4c92a4e5baf7efb7270a9ab9cfcd3c1173a2fcb2c155a923f9d8b8e35a965b11d15e2e0cc591e953da81c172b8882344cff7b40eeaa30d4793900dd85cb65fbeae9d1d3b2a62c66cb932dac1e6806ab6150"), + ciphertext: &hex!("43da888047cb1cfc7dd42329310c8234"), + tag: &hex!("f8267635aa7b51b89c80fa979861eb3f"), + }, + TestVector { + key: &hex!("69e1c0917ca8d49aa69f38cf9c66eb4d"), + nonce: &hex!("0c55672336d219e64c60e15d"), + plaintext: &hex!("7dac3e31269dd79399c94798f4bbc640"), + aad: &hex!("c1b423f27d794e947bc56aace3995065279221f5b8bef6568b5b2882209bf0dd7776e9ae6eb1a1eda0b768aeaaed9e3884cc3968b6d179e9e5abf08df8261c3ee54f8b0eaf2646cb221288a879c5ea4e9183805dc1da8a636a58"), + ciphertext: &hex!("37d215a13362bf087bcba8f95901eb05"), + tag: &hex!("1b3eecb7ae9386dbc1409e70f5827f58"), + }, + TestVector { + key: &hex!("08818d516558631161e49eebd621f78d"), + nonce: &hex!("f1f855eb8aeccc9ddf7aa80e"), + plaintext: &hex!("1a89c9c9623a26b7c8062c5f6a5f7f98"), + aad: &hex!("68fedf6a42b780eeb011aa0b242636668e5c8941d6045b05c948f82c5db3977831435ab4049895b607e854f710e3d8b7a26afaa2e7913093313e93c3e106a8356d6c44579398ce4341aacb3b726e7f42fab75934920df230cb4b"), + ciphertext: &hex!("9e12e3842ff7f5c25a171cc4c5a3dfa8"), + tag: &hex!("01cd4980d92df6739bedf22201a2cc12"), + }, + TestVector { + key: &hex!("bfa4a12b357605b11e65fa92b90d22fc"), + nonce: &hex!("9aeb721b698db40dc9080e23"), + plaintext: &hex!("9383358a4065f3e365924f7fa664012b"), + aad: &hex!("53bc66164811866e12ebcd64447c999777378119a257fe00d45b5c9392d5618f2c2c784696f5a9fea85d0f8c9cb5438b15b3f5661d49e0b0980ff61aeee0cdf650ab4fa82bcb0d0390f99daf02d8561bf5bca5627e3b194951ae"), + ciphertext: &hex!("df469d986744c33244682184912cdd68"), + tag: &hex!("8c12f8338ffb7840e085fdedaa6ab3cc"), + }, + TestVector { + key: &hex!("e16a57c83f230c368a0f599a7ebf3f5e"), + nonce: &hex!("2631b811ea57cb7d58fa232a"), + plaintext: &hex!("2a37e380f575e4365116fe89a58ee8dc"), + aad: &hex!("d5bc101ad26f7d03999eac122f4e060f20a402ff8a2a0324a77754e1eb8b7a65f78743ac2ee34b5429ec9fd6120fe6d17e71f738cebf0ae39a5be5a4dde85384d98cd90d218785b08daa662f24187156118fba981b9691cf12f8"), + ciphertext: &hex!("9278d1eab07dc7fa68742059d9fdbe60"), + tag: &hex!("27a474294ff811db4f6e0c88b1a86b0c"), + }, + TestVector { + key: &hex!("fe9bb47deb3a61e423c2231841cfd1fb"), + nonce: &hex!("4d328eb776f500a2f7fb47aa"), + plaintext: &hex!("f1cc3818e421876bb6b8bbd6c9"), + aad: &hex!(""), + ciphertext: &hex!("b88c5c1977b35b517b0aeae967"), + tag: &hex!("43fd4727fe5cdb4b5b42818dea7ef8c9"), + }, + TestVector { + key: &hex!("6703df3701a7f54911ca72e24dca046a"), + nonce: &hex!("12823ab601c350ea4bc2488c"), + plaintext: &hex!("793cd125b0b84a043e3ac67717"), + aad: &hex!(""), + ciphertext: &hex!("b2051c80014f42f08735a7b0cd"), + tag: &hex!("38e6bcd29962e5f2c13626b85a877101"), + }, + TestVector { + key: &hex!("5bd7362f38bafd33ff4068860eb35c27"), + nonce: &hex!("6064368166c48633b090cb9a"), + plaintext: &hex!("634852a6b68543ead889aa19ef"), + aad: &hex!(""), + ciphertext: &hex!("3a44f911376c371e6d597539d3"), + tag: &hex!("452b67e9d36a9ec5a893272b4d2f2103"), + }, + TestVector { + key: &hex!("2591360228dd945aae8fba95dc2725c5"), + nonce: &hex!("2adabc15c16e5c5954c8ab01"), + plaintext: &hex!("c580b051600dd902b273e26677"), + aad: &hex!(""), + ciphertext: &hex!("9ac66aa93d7547bc0a45baf5ac"), + tag: &hex!("a609413c9c13817287f39cfcf4da2e6e"), + }, + TestVector { + key: &hex!("3c85f64e35953f2caded63f987592611"), + nonce: &hex!("7ad13cb40e21ee633251968f"), + plaintext: &hex!("7bddb4037c2be00f4ef6f85ccd"), + aad: &hex!(""), + ciphertext: &hex!("9c2030e3e19e490c309610d889"), + tag: &hex!("b0e4080a8dae54a6770f4e21d5324e90"), + }, + TestVector { + key: &hex!("7b8d32382d29c00198f1d41fc6b52b8c"), + nonce: &hex!("bd65d7281a9a6aa9fc268f61"), + plaintext: &hex!("10f27dabb9c9e9facbd21b13cd"), + aad: &hex!(""), + ciphertext: &hex!("707efbd54aabbecc22ee6b5304"), + tag: &hex!("ca35f5dea869508653ce556c9c05d32e"), + }, + TestVector { + key: &hex!("dd95a8ca25883353aff5c414ad9ac5c0"), + nonce: &hex!("be2ed3a4d38fa65cf341e5ee"), + plaintext: &hex!("5b0c29c8bef219d52932b33041"), + aad: &hex!(""), + ciphertext: &hex!("4918ace25961fae06dbd891d16"), + tag: &hex!("ae6f069accfacba61a38323dd65f4c02"), + }, + TestVector { + key: &hex!("4db01983f6ad9e39385070b810c26c80"), + nonce: &hex!("2342dc3fb660e3925509b6ed"), + plaintext: &hex!("5cef6c4f05073ae39e05356dc5"), + aad: &hex!(""), + ciphertext: &hex!("12e41f4373f1e5dcfcf758e2c8"), + tag: &hex!("36fe1b8981946fd16cf12ad80f04d59e"), + }, + TestVector { + key: &hex!("8d59f931d4cf8a2683e269008ee86062"), + nonce: &hex!("7ac862a09c3408b667e8cd38"), + plaintext: &hex!("2c47413a8256f25677b1de8ef1"), + aad: &hex!(""), + ciphertext: &hex!("284ff4dfe4255f56b4a56585a7"), + tag: &hex!("16c0a4a5826e291d4b3f7ead6892c392"), + }, + TestVector { + key: &hex!("01c681e2cf1d7c8484c3811201376187"), + nonce: &hex!("56a8f48a3198b977f5064d02"), + plaintext: &hex!("37dc0f572c9e51c6fc18642d7f"), + aad: &hex!(""), + ciphertext: &hex!("54922c65023605c1eba146d448"), + tag: &hex!("dddbf654030e73be0dd6d26b67efd0e6"), + }, + TestVector { + key: &hex!("dae6cfda8979801d9399006797a2366b"), + nonce: &hex!("1cb41dac13ffa72e72a405d0"), + plaintext: &hex!("9f43ac53d4cec80dd29a902d86"), + aad: &hex!(""), + ciphertext: &hex!("e156a5f0711096cadd489937a7"), + tag: &hex!("dfa2d2a342b78ac6e7276365f2fa6dc0"), + }, + TestVector { + key: &hex!("5146ebe3d1fdf166ffa4099b638c5b64"), + nonce: &hex!("10014449817d881328c2b882"), + plaintext: &hex!("700af6989527eb16ffab6634d2"), + aad: &hex!(""), + ciphertext: &hex!("8ab35c288f09084da3c0cbd240"), + tag: &hex!("eec8232f2907b2e1cb2c940622530d25"), + }, + TestVector { + key: &hex!("cd70f86fc0a1780740fefef5742e4398"), + nonce: &hex!("c2abd119f22d310b34f41c5c"), + plaintext: &hex!("39fb497a2691264f02fcba4887"), + aad: &hex!(""), + ciphertext: &hex!("01339a3a9119836f6b038a1a50"), + tag: &hex!("e45a0a12c84ebaaf1885f457507b9a5e"), + }, + TestVector { + key: &hex!("8828454ceefd9004e30ae8a03d71f9d1"), + nonce: &hex!("8d9e3c61aa687a8f2b9ee30a"), + plaintext: &hex!("a94b020f4724178a3f4f9137c5"), + aad: &hex!(""), + ciphertext: &hex!("c4a94f89e03305aa415c7b350c"), + tag: &hex!("1acc1c75b9fc826af2e950cc7be6cf64"), + }, + TestVector { + key: &hex!("47982f133cb72342dd642f3475bde634"), + nonce: &hex!("8304304acea2def778f2bf9e"), + plaintext: &hex!("2c97a5fb6df85153a5c3bf414c"), + aad: &hex!(""), + ciphertext: &hex!("37e0962960edcf0a09a8538cac"), + tag: &hex!("07459fa438e1f159a6649a8ed6f934b8"), + }, + TestVector { + key: &hex!("dfefde23c6122bf0370ab5890e804b73"), + nonce: &hex!("92d6a8029990670f16de79e2"), + plaintext: &hex!("64260a8c287de978e96c7521d0"), + aad: &hex!("a2b16d78251de6c191ce350e5c5ef242"), + ciphertext: &hex!("bf78de948a847c173649d4b4d0"), + tag: &hex!("9da3829968cdc50794d1c30d41cd4515"), + }, + TestVector { + key: &hex!("3016620015db1d85eef09bbce50ae294"), + nonce: &hex!("eb481db3a52201173e2d4ad7"), + plaintext: &hex!("38b57c0d4151d7ee57e032829f"), + aad: &hex!("fa3d95b81a619638cea3f68dfbc02133"), + ciphertext: &hex!("7738601ab14748223164d1f69d"), + tag: &hex!("63ca9e8c27d9fa837ca4a0bb7039e390"), + }, + TestVector { + key: &hex!("b3ba382909e94ef5d318ee32cb54a33e"), + nonce: &hex!("3cf10b1700711486119cfd9e"), + plaintext: &hex!("4a90ad3f97c9c7e82efcbb318b"), + aad: &hex!("d1e17c0189b04561699bd2f791d69491"), + ciphertext: &hex!("bdf6a8a11288e83126932cd946"), + tag: &hex!("ca7ff7458c3adf388eef7e0e32d6b2c4"), + }, + TestVector { + key: &hex!("0a8fc9e07eb50b092cd9fccb3db2373e"), + nonce: &hex!("371d0af80bb20f2ead09dc22"), + plaintext: &hex!("7826bf01e962a201f5c8e7f742"), + aad: &hex!("9f42976847531ddfe428694f61260b2a"), + ciphertext: &hex!("665cdb3e2568ee1157d877dd25"), + tag: &hex!("c66fc129ecb30ea0d54b6d6932d9d7a8"), + }, + TestVector { + key: &hex!("3d1fc93233e86cb882e4cd754df63754"), + nonce: &hex!("1ede8cadc78bb4733c341bac"), + plaintext: &hex!("74232bfedc377efd5a63ab77cc"), + aad: &hex!("5807c856944fee1e6c2e70ad9a08de00"), + ciphertext: &hex!("ff3e09311d59bf1f3dff474fd4"), + tag: &hex!("7dbaf75ab6084504e080460ebfd255af"), + }, + TestVector { + key: &hex!("936ba9fc715c6e2d70a7986b14b82ce6"), + nonce: &hex!("45b3239d045bd56ea5a0e77f"), + plaintext: &hex!("941255369704ec192bab1cf039"), + aad: &hex!("a2570d9548bd6c05f824577871784ee4"), + ciphertext: &hex!("b3ead079446053a8206f4a37a6"), + tag: &hex!("fa5d98f053e8520f45e1597ee38b3751"), + }, + TestVector { + key: &hex!("96a05889a7591c1918472fd26977451a"), + nonce: &hex!("7d80492afefce80da6689ffc"), + plaintext: &hex!("b09b2dc5c5463a03dd5c9b0ecf"), + aad: &hex!("f4ffa36a478c795e0d28d37fa9e6fcc2"), + ciphertext: &hex!("f7cb053d447dddcb6e3a2d891f"), + tag: &hex!("2a38f63a1b7cdccec426683b34a44ff5"), + }, + TestVector { + key: &hex!("7c98567fb5ae9601fca412e72dc9fe2f"), + nonce: &hex!("1218ce69073eefd25a7944e6"), + plaintext: &hex!("0df75d39d8facc3accbdefc87c"), + aad: &hex!("df4203c3402d2b328bcb44e7683e08ab"), + ciphertext: &hex!("7e5ca0d1c1ff83bc3633f2301c"), + tag: &hex!("7ea717458ca93d8844da5df7ef74005a"), + }, + TestVector { + key: &hex!("4e1b199c12f12b591c051c7edc608d11"), + nonce: &hex!("a4bd3af7f35d0fa21f73641e"), + plaintext: &hex!("051ed5d700a7e59990f0358928"), + aad: &hex!("dae2cd749195bcfb67a663789e85995e"), + ciphertext: &hex!("ae50359f104ba2089ae98eb45a"), + tag: &hex!("c08a7cce7c38626604032d2be9bd519c"), + }, + TestVector { + key: &hex!("9491cb5d4f2b94cc5a50dc67bfedd074"), + nonce: &hex!("8377399607418e8d51dac5ea"), + plaintext: &hex!("2a1e50ccb5a52be3d338e8f0a6"), + aad: &hex!("972d9c486961334afc104765c2863253"), + ciphertext: &hex!("afe759b51318f67d872a1dfdae"), + tag: &hex!("77a4493aed7e3a6e014d0a1a314c3f86"), + }, + TestVector { + key: &hex!("0993571183089c4a7bd8e8789854c265"), + nonce: &hex!("d72ce6db33b33e2a2d430d2e"), + plaintext: &hex!("daf7f3ec2e2592c65847734f40"), + aad: &hex!("e47252d2a8ef5190faf328176588609b"), + ciphertext: &hex!("c6fadec0c7520f717144f0104a"), + tag: &hex!("6670c8cbf7e9eb431e899f61acccf456"), + }, + TestVector { + key: &hex!("d45b6c85293d609310eb3179cfbac4fb"), + nonce: &hex!("b02328302cc469cda1c7eb48"), + plaintext: &hex!("70f5af8c1da987f6ab5dea31de"), + aad: &hex!("74ca5b46ab31a11b4b4c253666844b32"), + ciphertext: &hex!("da6b359072accf5f036c85600d"), + tag: &hex!("d8e496c53797b124e356967ee525c0ca"), + }, + TestVector { + key: &hex!("9326155a9b81013c1edb143f9f5ae9d2"), + nonce: &hex!("c95383eb3050ebea4deb80e9"), + plaintext: &hex!("aa80cbebfb01b035a4e1e50e35"), + aad: &hex!("64a73f0497746436ac94c3c18e1ef6e1"), + ciphertext: &hex!("45ec8de633c7bb585c0a7fea1f"), + tag: &hex!("537b6103b0f7c5dce82bfa37c2734877"), + }, + TestVector { + key: &hex!("9192ce4d383752e9d9c66b93ef7f05ab"), + nonce: &hex!("adabd3baa4374697c53b4289"), + plaintext: &hex!("c55b5d16e3cee22bad1f5420ba"), + aad: &hex!("14cad0cb1736ccde73f86897ea017570"), + ciphertext: &hex!("3aa22a57646229fd33bbfae6ce"), + tag: &hex!("5ce7cd439823538fbc194886348ff029"), + }, + TestVector { + key: &hex!("3dd104297e803dc22b8f11f1951c8508"), + nonce: &hex!("8abd1fd8cd88ef848e8ce082"), + plaintext: &hex!("e1eb53704ccd5d7992f1c91097"), + aad: &hex!("96f6c82aa93ccca47056efc3ac971613"), + ciphertext: &hex!("8e4125514870003f0b0e8044a8"), + tag: &hex!("d951047cd8d50ca5f7ffdebf78725c56"), + }, + TestVector { + key: &hex!("fe0121f42e599f88ff02a985403e19bb"), + nonce: &hex!("3bb9eb7724cbe1943d43de21"), + plaintext: &hex!("fd331ca8646091c29f21e5f0a1"), + aad: &hex!("2662d895035b6519f3510eae0faa3900ad23cfdf"), + ciphertext: &hex!("59fe29b07b0de8d869efbbd9b4"), + tag: &hex!("d24c3e9c1c73c0af1097e26061c857de"), + }, + TestVector { + key: &hex!("544ec82f837fbe561f371b266cc52ed5"), + nonce: &hex!("b756952a0e98cf4cb024a499"), + plaintext: &hex!("a2e81f78b8e3e39e6cdf2f2982"), + aad: &hex!("cd0a24fd0f6a693a1578b9dfd2a212e990aa662b"), + ciphertext: &hex!("a4f08997e2d93c3c622137f9a8"), + tag: &hex!("059cf266240236fd3f41a3f4fabb36bf"), + }, + TestVector { + key: &hex!("91b73e2061b02b1e5e4c150ce1df4d27"), + nonce: &hex!("8b15597c84db62e2d8b03857"), + plaintext: &hex!("21e1b4b405050408b08e5e2a97"), + aad: &hex!("eba7f1a060e81f4ae7a77346d74dae9263ec284c"), + ciphertext: &hex!("0f819b25fc683c182533503ad8"), + tag: &hex!("5a1da6290fef801f2131614f7cd2d0bf"), + }, + TestVector { + key: &hex!("e6a1e4260efb2bb3073a1ab475e901b9"), + nonce: &hex!("be445fbabc3866d702965b08"), + plaintext: &hex!("2897d77c7f20679cbf27181aca"), + aad: &hex!("9452137225de644f94556b382ac13915e8261913"), + ciphertext: &hex!("d56e2d6d52923205291fffa50a"), + tag: &hex!("a6acf19c5434f95e333827ed9c7b88ec"), + }, + TestVector { + key: &hex!("49c18bed9412346a8ef02351cd4680d6"), + nonce: &hex!("7b5a7e9beec5b627f78bfd1d"), + plaintext: &hex!("bafe851c800f6df67e941fb496"), + aad: &hex!("251b9e935d72c1ed05795c74c88b6d4a03bd729b"), + ciphertext: &hex!("6f0c2eeb0a37d51d78314c3414"), + tag: &hex!("1a75d962d34205d60f79e4de87381046"), + }, + TestVector { + key: &hex!("ed0334239eb6f1ee1d686df163d219b7"), + nonce: &hex!("6146338e40fcd8bf264bc83b"), + plaintext: &hex!("954ddf553bf66473657110a028"), + aad: &hex!("cdba8eb5713075497eb5abf1434045a010f81832"), + ciphertext: &hex!("3eb76dfd40c5ebc840951d1b28"), + tag: &hex!("5d5aa1dc4a663eeb847e540f9a468155"), + }, + TestVector { + key: &hex!("14ab4d3a91e8f8320edba5b045b9474a"), + nonce: &hex!("83c6ac97704afdd24fbe3eba"), + plaintext: &hex!("de5f1521ce9423526932917863"), + aad: &hex!("e3981ea2e7468973a6a998deb7676d06630bad47"), + ciphertext: &hex!("19936ae7d6620899649a5c7887"), + tag: &hex!("66a805353bde0b1315f772d49eeaf8f2"), + }, + TestVector { + key: &hex!("f822c39eaba3ebb3d8b58cff3845ac59"), + nonce: &hex!("1f5d11c469e9fb74f19d8581"), + plaintext: &hex!("c0fac87ca518ab22853c8fa02b"), + aad: &hex!("b33871f65233bb2ba773cd8fedb517179a2a24a5"), + ciphertext: &hex!("a072381956210925148e3bc55d"), + tag: &hex!("f716ec012f7f9be988a9e450da7aa2fe"), + }, + TestVector { + key: &hex!("c566e9995c03a777f9999446382ef2fc"), + nonce: &hex!("4f343477387f48b9c6d15e69"), + plaintext: &hex!("a9eafd8903c71862c7c99cf068"), + aad: &hex!("c2b73bf0d1abd6d484df725a760f184bc315e0ba"), + ciphertext: &hex!("9f9551a3ad017c3fa518964704"), + tag: &hex!("15383fb8ace2e001c194474031c14e87"), + }, + TestVector { + key: &hex!("fa2fe01b7cb4ca24aba5880da268398a"), + nonce: &hex!("93f19d0a8edf1f29364743f2"), + plaintext: &hex!("006c3b0681f21ad705cf94d070"), + aad: &hex!("e80f337eb56c336d1e928db3b7eeee968e2f75bd"), + ciphertext: &hex!("a73b314c7f0bbd79ee56bd77bb"), + tag: &hex!("d2f9ecc80a5ae2e1d2735b9fbf01be25"), + }, + TestVector { + key: &hex!("77b34970d4300069e0092cd64ad17305"), + nonce: &hex!("d88e76814f3cf7a2f887e371"), + plaintext: &hex!("4e65a46a4579f08130272e5c83"), + aad: &hex!("7c772010e83befec22f6aebe8e18a0437f50a573"), + ciphertext: &hex!("d2d8ffd3f841e6039f1d551905"), + tag: &hex!("ee2c73c455081d84a631b18a7fe5f789"), + }, + TestVector { + key: &hex!("3c1c2aae3954d6f645ce2a697a4f3af8"), + nonce: &hex!("04b54f6447ebbcfbda57445a"), + plaintext: &hex!("f73e226b50a75558a389ccd738"), + aad: &hex!("e7a9d5c8328278311dca3e84da2bf0f573198d4f"), + ciphertext: &hex!("770e4b798b91850ec4e90136ca"), + tag: &hex!("8cb9ce2c90417f1c49a235de9b2ada2d"), + }, + TestVector { + key: &hex!("15ca2910df4e43c44a7c01d485b99157"), + nonce: &hex!("4a65ca77dde14bbf131dd597"), + plaintext: &hex!("786744b394e40bfe5db938c0ad"), + aad: &hex!("f9011e2cfb9c82d37f6b3f2af730a2e28c036f2c"), + ciphertext: &hex!("43c00fac7c11c3273078f09fe2"), + tag: &hex!("955beaa87737d3094bacc42a15986d83"), + }, + TestVector { + key: &hex!("998990fe4a9a6c56efdf1deac41a1ef5"), + nonce: &hex!("1b7a766436f4a674b5ed86ab"), + plaintext: &hex!("e53a9954c3943691dee5b17991"), + aad: &hex!("2eba6f2c61704917434507f4a2db16c4906bb4e5"), + ciphertext: &hex!("e5682045f438f4a96ac870690b"), + tag: &hex!("1afddc03809e565321ea66d8c83a324a"), + }, + TestVector { + key: &hex!("268ba76816d00e20997da268bd8faa18"), + nonce: &hex!("21cd5d21ed193612fd6db854"), + plaintext: &hex!("16339986d092027e7cbece0fb6"), + aad: &hex!("1971b90da0554ee7b6b0a5e9a782f05d511c1b99"), + ciphertext: &hex!("7cfd53b8c3c834c213d9860499"), + tag: &hex!("1f8522bfab97bec436d768332ae37c20"), + }, + TestVector { + key: &hex!("cbd3b8dbfcfb11ce345706e6cd73881a"), + nonce: &hex!("dc62bb68d0ec9a5d759d6741"), + plaintext: &hex!("85f83bf598dfd55bc8bfde2a64"), + aad: &hex!("0944b661fe6294f3c92abb087ec1b259b032dc4e0c5f28681cbe6e63c2178f474326f35ad3ca80c28e3485e7e5b252c8"), + ciphertext: &hex!("206f6b3bb032dfecd39f8340b1"), + tag: &hex!("425a21b2ea90580c889134032b914bb5"), + }, + TestVector { + key: &hex!("a78f34cd0cac70aab64acae18e3cbeee"), + nonce: &hex!("3c88570498da96e7b52c7929"), + plaintext: &hex!("bf61b1fb3b24506cc8c730d399"), + aad: &hex!("36b66ff81ec23a28944c98d2834cc764bb70703f0b26e079b6eb008ec11ccfb54a189ad393878f0824436ae69e7e2d8c"), + ciphertext: &hex!("f72057f873ad12b5e19ce433e0"), + tag: &hex!("1fea5b4176464b1f5dce11558a75ec21"), + }, + TestVector { + key: &hex!("0e038a1368999e2e70b6e350e01684bd"), + nonce: &hex!("a58952b8135420cd0f61be18"), + plaintext: &hex!("801bbabf908ff04d5856cadc2b"), + aad: &hex!("765203b3d61537be2883fba9899c3f3eff60cb9714e54de3a78a96dbf29cf53d82112e19b10141f13b11627a8fa55026"), + ciphertext: &hex!("7f0f35cb15fb4e7e3820d9ab1f"), + tag: &hex!("8dce643720d9d6f90f13a155e0be5936"), + }, + TestVector { + key: &hex!("b69d82e78b22a473af6234066b891778"), + nonce: &hex!("0415ab2f32d2a15006c3bdd5"), + plaintext: &hex!("d4ab346edaca5c84d45b45c6fe"), + aad: &hex!("f0be65105e1cd4fd1a272f7f6db958040b44edd0608b2225789cf34217cfcd6a5879b8e79dfa7d24345ad20f0c4f9a1c"), + ciphertext: &hex!("ad77c91c6ba6cb29eb5e4f6071"), + tag: &hex!("f67061dbded1a8df55fe9fcd68f61168"), + }, + TestVector { + key: &hex!("78faf937758f34b6d314e2fa30f60c2e"), + nonce: &hex!("85c9ef0e17ebcbb7227ba4c1"), + plaintext: &hex!("0ad91a8be4ccd6ee0ce75413a3"), + aad: &hex!("70fec6e608b6264228b822e7490e5e76398494c6489de5e839fb80513442cd0dfcf883000995185213e283f49234280b"), + ciphertext: &hex!("4298d0a1ea4c54950021d91921"), + tag: &hex!("19893b83fd24a8c21bb4ff14612cdb27"), + }, + TestVector { + key: &hex!("f812627cb6dc5921d3567dd17f1f3b9a"), + nonce: &hex!("37beb9c060f240d9ff78c844"), + plaintext: &hex!("dbce5235bccd0bc6249b30e9b1"), + aad: &hex!("a27fd811330efa672bbfa1cb2a221fa45bab88c5183eed6383e34c7e7450fd577f6c783c75d9ecaf74bb2ad2b2e8c143"), + ciphertext: &hex!("100ab04960a762db73174666b4"), + tag: &hex!("122172ee3093b8cb238a7c991da3b94f"), + }, + TestVector { + key: &hex!("a495f82751bf7781fee36d265607aa6b"), + nonce: &hex!("729a513baf1ccd1c97311700"), + plaintext: &hex!("0ac413fa533b01be459e95d784"), + aad: &hex!("3a44a7ea6d3ed13005d46c19f5ec7d2f7e50e8a268fc49e3c6fe15b41b6f6ea7245d88cb358e53cdba82cf297ea0ea97"), + ciphertext: &hex!("d05f52a875f56d3a6971495b7b"), + tag: &hex!("14ae378a5f75b386202194c677377803"), + }, + TestVector { + key: &hex!("63eed2623c80ea1c5d06a0003c4b3065"), + nonce: &hex!("3a276f4361cc6d7bdb340986"), + plaintext: &hex!("65067b281d5aafc0146d206fe2"), + aad: &hex!("d484646fdca9f5d3d4fa2c85ed145f99e3c73f4d81f6c08eadf318694bd7cc94382cc73a5610f9cbfd9987dc167d670c"), + ciphertext: &hex!("4cf2ff71e44a39eb6a9611e150"), + tag: &hex!("113e7d239946d784c331bccd5e098194"), + }, + TestVector { + key: &hex!("3ad85304b4267dd603070c1a999eb658"), + nonce: &hex!("2a02a6220d395dc91fa0d220"), + plaintext: &hex!("e0620a9e28ad8dba32b601c662"), + aad: &hex!("7a1511cab8aa9f7277f7b26cdee602e4a608b5565a20eedd66d70507a90e79da6521cae1e2ca810771392567af51d883"), + ciphertext: &hex!("cf38f7abaf4f92414ecb7021a8"), + tag: &hex!("8bebb0b62c81a4a3ae765dbc7c8747a8"), + }, + TestVector { + key: &hex!("63010b75ada3ccd0c1338613d57e3f53"), + nonce: &hex!("9898b912da0a2f169c3bf907"), + plaintext: &hex!("fc10d85cb5485be263374aaadf"), + aad: &hex!("565e1e581089098451ccaf1d594d1b4edbdcd5cb00ba4b2e08e4db780ce8258df41d01dbdd50521b75a72a8259f70321"), + ciphertext: &hex!("8f2390e88bc6f18ecdc1a1b9d2"), + tag: &hex!("15c40e98b6bd5b07d4757727ad6b7b71"), + }, + TestVector { + key: &hex!("d2a18188bb88312ec18916431b6dd880"), + nonce: &hex!("aedf2efb80b633d7afbe5a51"), + plaintext: &hex!("343f8363662077fb0ab50ba284"), + aad: &hex!("52492921f6b76e888baa5a4cb391af04faeb31bf00e8ed4363482fa95148f573b9adbebabf48d3ad33cb5ed3c0d6df61"), + ciphertext: &hex!("97a6f44a04055850779bc70842"), + tag: &hex!("5ffb75b58b4572366fb006455f692f93"), + }, + TestVector { + key: &hex!("7b3b81fa87f6fc20795e5fe33fe0d1e8"), + nonce: &hex!("b858127e11ea0d5ba523f7ce"), + plaintext: &hex!("e574920cdba3524bac8c2294bf"), + aad: &hex!("c23d4cf74bd76adee0973e4b3ac31a96fdeb0f2455e044d2d1b82ebd1937e09623921c81b6a1b9698b5b097b7c5c483d"), + ciphertext: &hex!("016a7b57db778fd019628016f6"), + tag: &hex!("e8035022b05e4c10792321d195b75854"), + }, + TestVector { + key: &hex!("852c34591e7ffef09259a9edf25020e1"), + nonce: &hex!("9e4243f5356d48f853cc3acb"), + plaintext: &hex!("c991389c242c48e31a9ae00d59"), + aad: &hex!("8a4514a5e7d4e2e036490b541206bfe6471c14bb50af6fc869048bae954b5dd813429359ee5eef23ee42ea35e0c36bb8"), + ciphertext: &hex!("5c319983e5e276658f10a58edb"), + tag: &hex!("5343086d4ac0e45e4adc6dc27d566296"), + }, + TestVector { + key: &hex!("b9840f1c04f7c9e9b2c9bec0c6176738"), + nonce: &hex!("7af462cc891270fe78566890"), + plaintext: &hex!("c9171685284b205bf4fd9d3f45"), + aad: &hex!("493ef83c18389c1e52050d2569f0d6f955cf8e76cf0a1697ffcb1665e285fe6e3595f456cff7f32feb7bde4cc82d4ebb"), + ciphertext: &hex!("988c2c3df37c68fc8bc7a29b11"), + tag: &hex!("d81b0bc3543fef4a929867bff63a1c17"), + }, + TestVector { + key: &hex!("9449043071de904f5e6e7922b263f122"), + nonce: &hex!("39f0713e60cbc8e41e4d7328"), + plaintext: &hex!("869a917e056f4460d6c2076d10"), + aad: &hex!("0b7a25e3e3027095772f3f8b8336813b607031eddd6f354a171e4b585504952cb51326c3edf4c48e41498da441cc090f"), + ciphertext: &hex!("cc878c8f760961e4ad08ad09a5"), + tag: &hex!("c303c9680b673c049e9b7bec8c28428b"), + }, + TestVector { + key: &hex!("e5b1e7a94e9e1fda0873571eec713429"), + nonce: &hex!("5ddde829a81713346af8e5b7"), + plaintext: &hex!("850069e5ed768b5dc9ed7ad485"), + aad: &hex!("b0ce75da427fba93da6d3455b2b440a877599a6d8d6d2d66ee90b5cf9a33baaa8329a9ffaac290e8e33f2af2548c2a8a181b3d4d9f8fac860cc26b0d26b9cc53bc9f405afa73605ebeb376f2d1d7fcb065bab92f20f295556ade"), + ciphertext: &hex!("c211d9079d5562659db01e17d1"), + tag: &hex!("884893fb035d3d7237d47c363de62bb3"), + }, + TestVector { + key: &hex!("1b96a8699f84058591f28590a5e63c0e"), + nonce: &hex!("d437b28673240ddc63d22d2b"), + plaintext: &hex!("802192b9c2d78e1df9ac223598"), + aad: &hex!("0f985a66d350c153a4882d0a4fc6e1b8b8450cd0825182358521b1be5fc734338af72a48170fde7512a8a92ac81d12e3a7fdcf7d98933732a9893d92d9435fcaee6033b726d28f73c5f76fd6b93d13bc8904d11cd4a713cd353f"), + ciphertext: &hex!("8c13cded61d08c1f2db878378e"), + tag: &hex!("43ee877c121d4a329e81e51d68a9d845"), + }, + TestVector { + key: &hex!("94874b6f3738d963577553a19155f4fa"), + nonce: &hex!("8e9f61edc853db24fb162062"), + plaintext: &hex!("ab5fa8933bf8b4b6eb8fd4a0f6"), + aad: &hex!("d30b11456b68d89dfecc00930c5102cabdb207abadfc7e26286e822a14c6e723ea5492ef53cc2206dbe9860583e2fd2a8ed26fcf5dba8914cae4829ff83745bcf203c2c9729ec5f635d368f8697139b18f1c39ea4e3e849f4b3f"), + ciphertext: &hex!("e359459af9418493dd8af46d27"), + tag: &hex!("4dd94f3b128f34ddd4036886fa084506"), + }, + TestVector { + key: &hex!("7434e4ec0aa26aa89f7a025b7cabee6b"), + nonce: &hex!("ed9fa99d2a22cb4fcb2d25ee"), + plaintext: &hex!("fd53183688a51d4bcbe52f6d37"), + aad: &hex!("ec9bad331852febf4ee1928c65d57df5eea95caf852fbb821c022978d33d07fec1ced606caed13624bb6d08a22da7e23e39298e10395b29d91a46220f64ca4d7d333d93ddec412322b67d5e101784e0a65088779b8c44f7cd05d"), + ciphertext: &hex!("97f74cd6ff2ea7d43262fe6f19"), + tag: &hex!("7ed5bcf0ce0448fa661d0c0fbcd36578"), + }, + TestVector { + key: &hex!("72a565d3b3b6814bea37db7f659ba1d2"), + nonce: &hex!("6f975cfb8f0973eba7cff602"), + plaintext: &hex!("46a9956585a9c06507ec073e2c"), + aad: &hex!("bac017084cdd4c035a1917de4abc453e875d1ec9f7d603683cccdd64e6273eaf11619acbef407fed03ff3e76373132c5bd680f7645e4fcdb09ccc60ce65584f607a090426f660df5bf4daba95e7cfb3f30e4197218f8decf0dca"), + ciphertext: &hex!("a657482d12377846ebe3ca6f66"), + tag: &hex!("0f10964e776b25ae079b357e199c8cd0"), + }, + TestVector { + key: &hex!("a85a8e0f16c7af9e7f32c817611a0249"), + nonce: &hex!("12b4a1c1bed206c426c1d977"), + plaintext: &hex!("4544079578dc90631c616a89cb"), + aad: &hex!("40741eac93ba6f3b60fdf1ac1b17fa3dd70d1ad4755f5a6bbd59c9c5aa99bb65bf7e077e5863b1d0b93104dea7b8e455d7bc149668822dc788b46980b2b439c33e10cc7c17415529c942e9eaf33eaeb627bc4cffc35cae4d37c9"), + ciphertext: &hex!("b0be95166bf557bae6152b360b"), + tag: &hex!("46391f35d73901732a7b9c7eb976aed9"), + }, + TestVector { + key: &hex!("96c837ca5294446d389a6f06cb42e737"), + nonce: &hex!("b37ce0928e17982ef783b2b8"), + plaintext: &hex!("8b77fe7aac6a70fcae1ee74157"), + aad: &hex!("8f67abbb7a9394821c7196349262c589d5e1c156d6126fb3da0562bf403e733508f1f1926d6c9045350cad3d1243504dc70aa17a4de748e4a1fd804ae262c8ad557adaf799466434266b91d2c083f96218473adfc9dd2e8c3700"), + ciphertext: &hex!("d950ab8631a66c313d6801977d"), + tag: &hex!("31e109753cbb651ed194369f00840323"), + }, + TestVector { + key: &hex!("fad699fe2dfb8a2b955708ff97b15892"), + nonce: &hex!("61d9979bb5dd655e826abf68"), + plaintext: &hex!("ca88d99b2c88b078a9878fcfde"), + aad: &hex!("7c02b7f2e7be357843a86596d7ba3a87e922bb0a982c32a20e809491c6343cfee2ee92fa2b6f898ee5b77a9ec5719de356c5e7507b1cac49b06e6fd5311eb9cf7a0c42b5252ca90632296d12ff5316a56253cc6666fb4d0a38f2"), + ciphertext: &hex!("bfa286323d4904de8cd21389c0"), + tag: &hex!("cf3af80df6bde595d6b5a28d6b7112f1"), + }, + TestVector { + key: &hex!("ca83a1109cf5bfb7d24d6ba72c6c1a74"), + nonce: &hex!("ee40762d9a5fcdb41438ce05"), + plaintext: &hex!("53c7fa9eba69541113c1998c46"), + aad: &hex!("f54c4418df498c782ed61ccba4e657c8de9032231fd6a98c718063600d96f0e5f17fa73b9492faa264b5b9706e0d096386983694fb41b904c109b32b67c4e472e2a416fdd8f2a41fbfb1c5ecdf5be97fcd347c2541c1e50cfe18"), + ciphertext: &hex!("8cedd6149a203beb47d78489ff"), + tag: &hex!("00906817785539306d07775e215bfb4b"), + }, + TestVector { + key: &hex!("65a467d5e8d503a0916e5ccaaf240b20"), + nonce: &hex!("0cc6f2f2a5cf96ce6adc2c5e"), + plaintext: &hex!("b619af43215d41b1b0650bbe0d"), + aad: &hex!("ae98d8e675bca2cd4bf8f0860d46bd2c18f2d15dd431c51fe63c878cc9b1cf47a3b84cf1e9a02a4f0a8940008b72f4f1ed9cb5aae670899705573a8045008cad1284cddd1532791d38c8067694669d8b7d06a46969c413e6e35c"), + ciphertext: &hex!("6c24bd0ecc97873f0f7c8802c5"), + tag: &hex!("03168a06b495f3f31d46f0de87d5471a"), + }, + TestVector { + key: &hex!("4cf328e1f2f180c2dd9e6d703cae188f"), + nonce: &hex!("35b7cfe65331e520265d6657"), + plaintext: &hex!("9c1a195735a84e6491a8ac07ff"), + aad: &hex!("72a6a4f43598b91169a834d906cbe4cb40da1a41502a7f4bc80265a239330a9102de94a7fe8d57d28dc125aa5e6d061e7d2a90cdad8406ee899687d02f780f0c1ae8e944b300b61cd3489852d61eb2349a447be85d25d3cdde0e"), + ciphertext: &hex!("eb4d38c23be97445c25e8bf2f4"), + tag: &hex!("b005f424f77a81f4a965aa7a1bf8cfe5"), + }, + TestVector { + key: &hex!("7d62b16a551c12ac2102472492a4d3af"), + nonce: &hex!("d464c988013cfee4bafd7a9b"), + plaintext: &hex!("6de52d4b0878c26b0d8a6ff127"), + aad: &hex!("12a9155e72f6c19a9f00a651fe52d6dac331cac06b3ba594e24021900cdaa7d73a75a0968dd5d7d2f16ebab2197c620a1768bbc0839e21c8a37203af4c2ba146fdcac2b48701cc4bb5863f514c6562e01e807cd5308c9274ad9e"), + ciphertext: &hex!("a6dd42b752cacb47f1de9adaa1"), + tag: &hex!("c6472e722a39ae44be5e4242cc58e046"), + }, + TestVector { + key: &hex!("ef6c85fa490919d342734357fe3656bd"), + nonce: &hex!("7790d3a8deb8712c68ddae80"), + plaintext: &hex!("bf45d58e3cf0cd47bfe90814ea"), + aad: &hex!("fb04ccc1d78523c9aef6e8285fa991026c5aa4cbc8c37f9e0969d74c571e2409775d116c4a55b03f029842d7e3a53df8f7ceb9469b4461649dfb4183e57ebea8971bd967ee95d5f656873368a83313fa31cf6ab11d7b2c77d20d"), + ciphertext: &hex!("7cf1afa60d3428c8fd25d9479b"), + tag: &hex!("63e3a5eebcd72468e8ffab55e3caefe7"), + }, + TestVector { + key: &hex!("ac5b4ad09c73ed0b80931b920ceb0fad"), + nonce: &hex!("1c0ab2941025ce7f084b8509"), + plaintext: &hex!("bf64de420133b29d1d50f4757d"), + aad: &hex!("e8cb8547ac67dccb3cb88e0443f9566944a79adaed7680b9e174080751d91e4d83357f28802a576e0fb53fb32e8d4d879d55aa9e79e201be363f4ddb16dad35e058a7d69e262c359c036f0d72151aa0bf04fbef5c4c3f7e91d05"), + ciphertext: &hex!("3761f611ec3ff853c915e61ef6"), + tag: &hex!("bf906c3dabd785968ba5c7abd4a1eceb"), + }, + TestVector { + key: &hex!("35818c93c54a321f2ccc28e967d22ce1"), + nonce: &hex!("18dfcc73829a3c13287a6112"), + plaintext: &hex!("6f32f25bfc511e8a7c60854944"), + aad: &hex!("09be731cd52fe4f7c6dd9aef978f8f117c358997842ffbb2df96727625669b58513e2bc97ef9c7119afa6b088a4f9312bebebfa6e71080a6e7f369207f3396f9c240a13143d7bfc5cad5049cb067ce4f57876d883bc8283fed87"), + ciphertext: &hex!("9553eb0378229fdb213fd46002"), + tag: &hex!("ec228ec0fc273b67d922c2ba3dde5bdf"), + }, + TestVector { + key: &hex!("9971071059abc009e4f2bd69869db338"), + nonce: &hex!("07a9a95ea3821e9c13c63251"), + plaintext: &hex!("f54bc3501fed4f6f6dfb5ea80106df0bd836e6826225b75c0222f6e859b35983"), + aad: &hex!(""), + ciphertext: &hex!("0556c159f84ef36cb1602b4526b12009c775611bffb64dc0d9ca9297cd2c6a01"), + tag: &hex!("7870d9117f54811a346970f1de090c41"), + }, + TestVector { + key: &hex!("f0a551c56973e1cfdfe2d353aad66c2a"), + nonce: &hex!("94e95e0544ab0b0b9997aee3"), + plaintext: &hex!("734c0907ef49a1d86bc665bb9da9cedeeecd2abfed7f591c201ac360ca42f941"), + aad: &hex!(""), + ciphertext: &hex!("f2c2f0c35e0bf6c5f5c24d8aadba19ed35848959b9c586604c396428493418d0"), + tag: &hex!("8855aecbe9604a839fa5d481f8760ffc"), + }, + TestVector { + key: &hex!("c635775fa1416abe375c792ea7a486ac"), + nonce: &hex!("5b9f038596f55115986a3109"), + plaintext: &hex!("54172156fcb2c40392009807bd3ec4a11c2c1b6d69ad20c773df3d9e7cf35e3d"), + aad: &hex!(""), + ciphertext: &hex!("73a9d9de0a3dcdc52dd9745fdf12353f4d63d0c7646443f5206883f6b7da2b94"), + tag: &hex!("11970a60855b0fe890d4f5988f6cafae"), + }, + TestVector { + key: &hex!("43d0651aa5d06f2846fed833fbb72241"), + nonce: &hex!("2ae626772b73c7cd25dab014"), + plaintext: &hex!("cec1607ccdc6332e5371766190cc7b03a09fb814b3d2afc52edc747d70b7fff4"), + aad: &hex!(""), + ciphertext: &hex!("ea742cc41afac5ffbfa81e89bad82f1f8a07eca281fc253b533cc157eceec4e0"), + tag: &hex!("db1e19fb545ae218f4ad3c9a6da64997"), + }, + TestVector { + key: &hex!("defa2f0eba651799c6041e6f28a0db3b"), + nonce: &hex!("102158d6ed54ecc7efdeba7a"), + plaintext: &hex!("67844577a198b456fa410afcede8fc24fb970459096ebae03bfe1dd32a6b9665"), + aad: &hex!(""), + ciphertext: &hex!("4d87782c99ea2b18c58393eef975007b9019f42667b98098404137dc085d631b"), + tag: &hex!("fbdf857c1bff89bd725b8ca90d643e5b"), + }, + TestVector { + key: &hex!("f098deb1e8149b3c88320efbfea087e2"), + nonce: &hex!("8146393ed0dd09d89d1ae7e5"), + plaintext: &hex!("8ee6f4c01e98b501a9914f57239bda7d5831ac147c320651863e06db60c1a02d"), + aad: &hex!(""), + ciphertext: &hex!("122309ab94c98901104bda0488efb563959da64979653ee4f8e658a3ea8a3c9c"), + tag: &hex!("93e3d93d0580c5567ecfac274da211e2"), + }, + TestVector { + key: &hex!("63b28aec8f7dd44af269e48e35294a34"), + nonce: &hex!("4c3d88500f6a483b63ba1139"), + plaintext: &hex!("5b86eb718b3917537d4ef51b6c74a85cc9a90002410d8f346cbe56c86ac72d4d"), + aad: &hex!(""), + ciphertext: &hex!("d0281117e29fbf9676f7887811b010a19a34475ad9e4516cd8424d0b9e5a2c3c"), + tag: &hex!("904ba928205fdda9e2674805be07e93e"), + }, + TestVector { + key: &hex!("765ed884a7554c792cc671e93c02433f"), + nonce: &hex!("667467b168db56adf48a26e2"), + plaintext: &hex!("b941bb1f73980b0d76324a49a6c33623d4a1063b05c82cb43e4b0cdd4f913860"), + aad: &hex!(""), + ciphertext: &hex!("84906e78ac79df67a0fb4ccf4c8da439094339adc92d98abbe032cdf4f5d92ec"), + tag: &hex!("750a89a842a6dd7d1317f561b9038402"), + }, + TestVector { + key: &hex!("816ed7edadca9e8fa2b2b9f9ebd14d51"), + nonce: &hex!("7da514e274b5b812722b5c3f"), + plaintext: &hex!("c76908234954ff939ba2293fa1ac654a4bee41a574f2694d090980481a08083f"), + aad: &hex!(""), + ciphertext: &hex!("b59a50e4414b4903c195ff47e8f9028d77b7e73a9a54e1ced9ebb1636b123864"), + tag: &hex!("007af223e7ac139eafd78d0a2c87ca25"), + }, + TestVector { + key: &hex!("f7b38d0d340373b98b89725fd889be49"), + nonce: &hex!("bc2b87a883af1c0bff8388fb"), + plaintext: &hex!("0a8de4df6e01bc7b2a36e4a123af8ce6240bec42cd4e4f09aa92520c1658103c"), + aad: &hex!(""), + ciphertext: &hex!("65ee08ab751bef3720db313491fca20a87cdfd6b8b028f53bf352304da504911"), + tag: &hex!("abbc81ca718fcbc6a75c85ada74e466f"), + }, + TestVector { + key: &hex!("dc662c77a2d520a067cbd6bd7e119696"), + nonce: &hex!("23aa76d1e8c3a72be862a5eb"), + plaintext: &hex!("5fb66e144d2564e096832065647dae768659d6dcd10a1dbe00858ce4f5148912"), + aad: &hex!(""), + ciphertext: &hex!("612713f9e6bd8017f61410c10ba1bd21adc87565bafbd1839d9572e270e94210"), + tag: &hex!("9d7616c3b486107cc74a8a2aa9c65209"), + }, + TestVector { + key: &hex!("5c5b3799a19098b9c5737783ef0c80e9"), + nonce: &hex!("34fb9e101915639def30f40e"), + plaintext: &hex!("05f15cd45a82f36bc4e5e3d6db7a60640faa0e929c00f0354e913bcb02d83118"), + aad: &hex!(""), + ciphertext: &hex!("ad60f53d51b6b00fc3366a4b4bc16b678ecd12473e8bd55c363bc0d94a844b70"), + tag: &hex!("1a528398ee2c9f436743d1a08602c5b4"), + }, + TestVector { + key: &hex!("3a541317198a2fb1b90470e90d6d7f38"), + nonce: &hex!("dfa6eb2b53177ff5d0924295"), + plaintext: &hex!("3ac18af46d3fb15d477b849fe1ead087840742cbd8b2ec31b45b8ac2e4a53975"), + aad: &hex!(""), + ciphertext: &hex!("66755e7ec710a8ed7c776521f214ceb54e550220177eb89fe3949c9e74e2e108"), + tag: &hex!("20425ac5f07868b49edf9896af64396a"), + }, + TestVector { + key: &hex!("8f85d36616a95fc10586c316b3053770"), + nonce: &hex!("d320b500269609ace1be67ce"), + plaintext: &hex!("3a758ee072fc70a64275b56e72cb23a15904589cefbeeb5848ec53ffc06c7a5d"), + aad: &hex!(""), + ciphertext: &hex!("fb2fe3eb40edfbd22a516bec359d4bb4238a0700a46fee1136a0618540229c41"), + tag: &hex!("42269316cece7d882cc68c3ed9d2f0ae"), + }, + TestVector { + key: &hex!("5fe2650c0598d918e49bb33e3c31d5b4"), + nonce: &hex!("dd9501aa9c0e452f6786ebef"), + plaintext: &hex!("5a6b60ec0ac23f6d63ff2b1919ba6382927ef6de693a855f3e3efd49bd4453d8"), + aad: &hex!(""), + ciphertext: &hex!("f0ac2d9153f00be3fce82d24fd3df3ea49f8265137417468724ae1342c6d9f00"), + tag: &hex!("6bab3332c8d370fa31634c6908a4b080"), + }, + TestVector { + key: &hex!("298efa1ccf29cf62ae6824bfc19557fc"), + nonce: &hex!("6f58a93fe1d207fae4ed2f6d"), + plaintext: &hex!("cc38bccd6bc536ad919b1395f5d63801f99f8068d65ca5ac63872daf16b93901"), + aad: &hex!("021fafd238463973ffe80256e5b1c6b1"), + ciphertext: &hex!("dfce4e9cd291103d7fe4e63351d9e79d3dfd391e3267104658212da96521b7db"), + tag: &hex!("542465ef599316f73a7a560509a2d9f2"), + }, + TestVector { + key: &hex!("9b2ddd1af666b91e052d624b04e6b042"), + nonce: &hex!("4ee12e62899c61f9520a13c1"), + plaintext: &hex!("01e5dc87a242782ca3156a27446f386bd9a060ffef1f63c3bc11a93ce305175d"), + aad: &hex!("e591e6ee094981b0e383429a31cceaaa"), + ciphertext: &hex!("87b976488ac07750aa529e1602290db36f4d38d5c5ccb41292b66c3139617ebe"), + tag: &hex!("c4e7ea53efd59354ec6b4b8d9f8b237c"), + }, + TestVector { + key: &hex!("8737490bdc02e3543c312e081e2785cd"), + nonce: &hex!("cf3460b8010d410fd5524720"), + plaintext: &hex!("aa0acbbf2b847910d56ee4da8a9f40973f85d6cce1d6326a777eff01173e66d0"), + aad: &hex!("eba8c1ca49e977cf26eb52325e59afa8"), + ciphertext: &hex!("893902594834c3a72da17bd73ccd53238a581a3e33edf8b9b901662b5f7e1d3a"), + tag: &hex!("36a3a106d3c10a65da7d81942c98b349"), + }, + TestVector { + key: &hex!("f7fc73fc1c428e56af92e6b2870845e3"), + nonce: &hex!("375b1a84fefaaa807ffeba18"), + plaintext: &hex!("f871a9a695b74f9501942f99a3489d4befec6768d7c17d1c38f51fd6cd16adc4"), + aad: &hex!("0d668901163a08a338c427342d31e799"), + ciphertext: &hex!("ef65290d220227147154f66a12004ce292507527f17c5119c69fa4f81e56d0a1"), + tag: &hex!("2d48c8b198610cdea73965f6ab1d9a12"), + }, + TestVector { + key: &hex!("e522d6715bb408401c5a7af3ef190caa"), + nonce: &hex!("1a3b2a313418ed26de8ddf57"), + plaintext: &hex!("d3f10233505f524ffb8d961d8321be88c975704bdd9df958f3795adf0085aaa7"), + aad: &hex!("b993eb193e9d59382919ebbc9e3ad829"), + ciphertext: &hex!("e1519156cc27905b8da24d29fb502d54042eb6fab10c5f6a99d1ef54c92c555d"), + tag: &hex!("7fd04f637b748db17da7ee34099a112a"), + }, + TestVector { + key: &hex!("55190de13cfbbedf4a0787f9ecc34e45"), + nonce: &hex!("87803bcf6a69962abae929e5"), + plaintext: &hex!("ee5da0026ce103140873226149b75fa734888b00518aeac0224466bbb0d23d0c"), + aad: &hex!("067c3857cc240c6bb5f628bcc7cf5559"), + ciphertext: &hex!("06362d236e9618037d31d4f1ea0df6064e0bf06b6c5904530e1002e8479c16fb"), + tag: &hex!("342a27aea0ef0aa26ad92ea3a92afa37"), + }, + TestVector { + key: &hex!("65f7a5ff7feaa8d50736dce3c8524cf9"), + nonce: &hex!("dfa0822065b1ed4987685217"), + plaintext: &hex!("a32d3aed1371cfcddf5e735a9d95b96d1ac59c3ab784be8364cc1cf3b71bf70e"), + aad: &hex!("cc4fd4d82584059b5a165d632d56fe1e"), + ciphertext: &hex!("bdf356a54a5cfa281edbe7e35966b5b8a68894f282cd7a734d502dfee6dcb1f5"), + tag: &hex!("4ff05b2898df6edc27574a2eb395ffc8"), + }, + TestVector { + key: &hex!("df0ceb73dfbd06782f69cd51cc4fc1fb"), + nonce: &hex!("c5fb4bf0b40477e10e5d15d4"), + plaintext: &hex!("fa9da35d8d812585322fa1c0cf4633b06424272cfac1c5a51138b0b9b91d443d"), + aad: &hex!("f292c4c2a2356e70feb0003a28708ed8"), + ciphertext: &hex!("e81cd00a96dcb719fc2c3af7b5420cb5667fed53af8f561dc216fc7215ab16a1"), + tag: &hex!("60848116706be55b4ea939ba899eb2b7"), + }, + TestVector { + key: &hex!("72205e651f03e2c16eea7689af43bc4a"), + nonce: &hex!("42c47b2f95b0ec02652f1fff"), + plaintext: &hex!("7fbe781650c396ca8cdc6b2efddae0007cb008c4fc7310fa17ec5ae060171391"), + aad: &hex!("7f978fc1f1b2f9f37b88b96b8c14ebec"), + ciphertext: &hex!("b3f3a8bfe2906ac1bbc93ddc701a5529c2cb156354cedf85928f605ed6005bdc"), + tag: &hex!("9151c8000dc25eba4a57908b238afb21"), + }, + TestVector { + key: &hex!("a2c96c0b051c633ec10b2fccb43f4517"), + nonce: &hex!("c4c13fc9f15f482bf6bd8d0b"), + plaintext: &hex!("5f0a50d976eb2048bc481d7bca9b3e7367c3b12c9e98ac8521f45c715ae3bfff"), + aad: &hex!("94afc74a7040c47705722627e05f159c"), + ciphertext: &hex!("2bde225ca63b40ce64500c40c00fa5c50086c431e95d1f99678cb9a90bda2502"), + tag: &hex!("6a296aa47e52737304eaafec0c3d0c65"), + }, + TestVector { + key: &hex!("108146de148bd4dba69c4ad2c11a35c0"), + nonce: &hex!("9dfbe2fa46a46c3ebaf31c48"), + plaintext: &hex!("0104c3da4cbe50f31ccfcc426d634d8d39686444a3b75bfb54d67349fb7e7017"), + aad: &hex!("bc83808f9e884967c84d28ce981dfd1b"), + ciphertext: &hex!("3f4424912dfaafd8f8b08ba7baea95effb3e4571720a2626b92ad8f7a69d4477"), + tag: &hex!("eedec85ed9e14a5fcc2cd0ce50ff00a4"), + }, + TestVector { + key: &hex!("37b9352444bcaa9624b267566a59095a"), + nonce: &hex!("d7a72473b99b2890ef7c4928"), + plaintext: &hex!("93037b2b4814541f425ea0bcc88ce1486632919cef443a5374d9944edc7e42ed"), + aad: &hex!("f7751af2dcbf5a7eb81d6bd73ced1220"), + ciphertext: &hex!("491e0893a652a5975d3db72868b5619311a9cddad11c5522e95893c42e3b63a9"), + tag: &hex!("fcd8120512eb3f14295efd3b045b0868"), + }, + TestVector { + key: &hex!("dd1332f17e62b2be889e9a399fb0d3fe"), + nonce: &hex!("3f0028cb7cb8f1091a4e2f4a"), + plaintext: &hex!("9c2e07683c6ca06d012708ad6dae95082eebd36261ccc874226ad354cc8ba82e"), + aad: &hex!("2f33c5f85f976811ef67533f488917fa"), + ciphertext: &hex!("a4fa9311e3c02c3b068a3f11ae7657efc3a3e69991251280503940ac4a7e8950"), + tag: &hex!("0e5e77baa0f36db11cc5bfc27ffc7a49"), + }, + TestVector { + key: &hex!("39e215f1a2572257efd939ac0365ec97"), + nonce: &hex!("e1f4da712c4c1eb31027352c"), + plaintext: &hex!("21f7d62bb2918dde6acf9b6c9b7afed4be7d623c3e2070444b087fb40de7e6f1"), + aad: &hex!("9368e8d525e77707d316542dcd735c6e"), + ciphertext: &hex!("3c93eb8df00556e3f42d54acfd635fbffc0f77f868a68f738ec2918213ba9a22"), + tag: &hex!("0dd8352d507e5253ee0849688d2ee86d"), + }, + TestVector { + key: &hex!("06f36f4939473b540e71db35f398a53d"), + nonce: &hex!("13efe211cb6ef3a374f4da85"), + plaintext: &hex!("a5aafedc4c1ddb7f6b38f7974d16a1c88cf7ef1ebe5027ea4fb55db16101fc20"), + aad: &hex!("8cbe3e3eb19818db197901bd4ee42de2"), + ciphertext: &hex!("7d21fb06002d19f40741b275b72cdbabbe032460ecf13d98f1cafcb30f704af0"), + tag: &hex!("dd4beca1670cf437372aba77bc3e9261"), + }, + TestVector { + key: &hex!("fedc7155192d00b23cdd98750db9ebba"), + nonce: &hex!("a76b74f55c1a1756a08338b1"), + plaintext: &hex!("6831435b8857daf1c513b148820d13b5a72cc490bda79a98a6f520d8763c39d1"), + aad: &hex!("2ad206c4176e7e552aa08836886816fafa77e759"), + ciphertext: &hex!("15823805da89a1923bfc1d6f87784d56bad1128b4dffdbdeefbb2fa562c35e68"), + tag: &hex!("d23dc455ced49887c717e8eabeec2984"), + }, + TestVector { + key: &hex!("8bdec458a733c52cd994b7c2a37947d9"), + nonce: &hex!("bf8d954df5f1ee51fc3f1890"), + plaintext: &hex!("9d5f1c905df900111f2052a60913d8a9d83cd40e43ba88203b05e3dbf0e37fbe"), + aad: &hex!("ffe26874a54bd38a026c5c729e2852a748457412"), + ciphertext: &hex!("f056cf8ea6c4f353f08d54c27a8ef3324ab927a641563f9f5dc5f02c3b2204b1"), + tag: &hex!("2f8b9351426363f09f5d17f634a381a9"), + }, + TestVector { + key: &hex!("0a651f95b6fe5d9442fd311cee245229"), + nonce: &hex!("b7b2349b60ac5cf09885ef4e"), + plaintext: &hex!("1cd7be7611d8f7c9d75fdf3f53d28172ae4d462c06da56cb386687f2c098e28b"), + aad: &hex!("725a089a37ba50e53143722140ce5c37bc0a48e7"), + ciphertext: &hex!("e2926f34c30883a3b7eb0dc47627aad090111654a4980fc4fc952fe7a7b6b60a"), + tag: &hex!("617345dab8973c21ad711c2a51885f83"), + }, + TestVector { + key: &hex!("fec2452d0883a54c0e33fccc092ddcf6"), + nonce: &hex!("9e3e354d30c2c77cd0d9a0fe"), + plaintext: &hex!("95b9c5e6adb7fcce212abf535095bd955c3aa0f7ac2428841f4de9035263446a"), + aad: &hex!("6c12b112110ebf36930910f1bfc9ed49e14440b1"), + ciphertext: &hex!("a85754f451b40f3ab576327b4b99fa09adc95380299f61c5c7a8e28188d2a40b"), + tag: &hex!("94b979f7718ec13412e03f3461440100"), + }, + TestVector { + key: &hex!("e5f6d9f2c8ad08a1500157e027b92219"), + nonce: &hex!("94358eeb6829f1be4de3abfc"), + plaintext: &hex!("3204856040edd9401a890769875cc252e5dcb4a77e951e6eaef6d7318a06bcf4"), + aad: &hex!("b3b860929cdc3fb0e393f21287f3dddc4a1c927a"), + ciphertext: &hex!("b1ba514ae4c41270d7beafaa1bac2fa993cf5af3607a008c6bb4aee2a1212dd4"), + tag: &hex!("7e0f5aa40553128f2c15cb9567c950e1"), + }, + TestVector { + key: &hex!("aeccfc65063c3fccfc5a0b29193d1ef4"), + nonce: &hex!("70649c9d2848d21c575d6914"), + plaintext: &hex!("46ac375da56527c3c6fd5f28f33c63b1ffaf06c33b8f329eae37f8579a62291b"), + aad: &hex!("637dc392cfe3a8e2fe5e871799a46dbe38f59610"), + ciphertext: &hex!("7f8841d3c82907596c4aa6ed433b9eb33b24d66f0a0cdd846d5ea51668975d9d"), + tag: &hex!("dfbab7a42d60cda73b03189034e44ff5"), + }, + TestVector { + key: &hex!("1dbaf0bdd974b48ae373f686a961aeba"), + nonce: &hex!("a3a6454d17ac622248ae9857"), + plaintext: &hex!("83a131f7737b4e881fb255ab9225f7faba96476626ed27168d6342ccca8d3e75"), + aad: &hex!("393843360c388a6e2f83c7202e8da6fa7041a6be"), + ciphertext: &hex!("2471d23957d6305a86520b757c54890a57f665a44a19af2f8d55e6833659e730"), + tag: &hex!("4693b10c8998580e986be0bb26a22e3f"), + }, + TestVector { + key: &hex!("540f40fe8ac2e506b69bb2ba356ff8db"), + nonce: &hex!("0502e51ac42f641d7a0176b0"), + plaintext: &hex!("910a000c5e99245870f08dd658b648f944d04426a70d6d46d8e88ec8eddfb324"), + aad: &hex!("9b1f2b2fd7265792852628df926abc5609aaa762"), + ciphertext: &hex!("9381d4b72d740b58c3f27f8dff01d8bef45e769b834539a439173c88a6d18e62"), + tag: &hex!("7c678893a122a50f777dfcebf514f81d"), + }, + TestVector { + key: &hex!("55d0e0560a2027bb873d84a39ff87046"), + nonce: &hex!("616d61ba94216c9c7c0903b0"), + plaintext: &hex!("1610431777c01136c0a0073f5c114c357f0216d5eaa31cd40b8cd605ac56dfab"), + aad: &hex!("a0203e1f31f66bfdc819d086a48b705d1eb7721b"), + ciphertext: &hex!("5d846a8dfe02cf2454e11075a236b2a6acc59819e9ca6af580690664c195edd3"), + tag: &hex!("24cd0dd950859ab9d1ae654ef7174f98"), + }, + TestVector { + key: &hex!("b7ff8402f1325d945c98662003323db7"), + nonce: &hex!("6b6163fb2d1641bce33459e6"), + plaintext: &hex!("a2a653ee98df41fe873bc036a5fa7ddfea8d63ff0949ae8e1489cdb0c3a80c7f"), + aad: &hex!("50a7649f5ac25f110f9408ecf3289d978a55620a"), + ciphertext: &hex!("820a373f446a8341c8d928d223a5aea854b643ff07902b0c5bd0c6319b42d855"), + tag: &hex!("764c69deed533ab29bd85dd35d4dcf9a"), + }, + TestVector { + key: &hex!("48c901ba4e905bd68afdaec739ae00c2"), + nonce: &hex!("5bbe3dede5ebbd8cb845a9b6"), + plaintext: &hex!("80b845888bd2f25defcd62b72b6bdeebd6152b3aa6b006891b0d69769fcc06d3"), + aad: &hex!("0c0cbcdcdbb35a35116b12b62715df4b647d78c5"), + ciphertext: &hex!("512779582d1fe1831f333bb563634acef8021c3c76b06beb6c7da98daac4c229"), + tag: &hex!("15fd32f96a4b9505bc1373525d40eeb7"), + }, + TestVector { + key: &hex!("c82cc4d9ff0681968839991afd0dfc2a"), + nonce: &hex!("26a95931946fd2118ccd01cb"), + plaintext: &hex!("7516c4a781be02cafc36df4a07d2c9ffb978fdecf5217240097d5c26ff1e77bd"), + aad: &hex!("8bbe80d4f4cd6c61b4fe3d24e98853acd4dd83fc"), + ciphertext: &hex!("f98436fe4bf6e5993adab0f0001bebfb449735eb365b9e7ce4b151f82005c5c7"), + tag: &hex!("c83be461e1fedbb4ddf3ee72b9debe20"), + }, + TestVector { + key: &hex!("748a88bf4e264a1180bfd665072aba65"), + nonce: &hex!("b0a768b62de3cbbc1bcfe93f"), + plaintext: &hex!("1e1df61a9f10c7b4057d684ccef74e09f2a87f7e4aed393a451461d574c8ddbc"), + aad: &hex!("f4b102d885495fb893189aa216d8ab653bb97b99"), + ciphertext: &hex!("5e1af9511989069a615a6850402547ef4788197452461f1241e24be674c60074"), + tag: &hex!("734e1cc937ca384e282410fd9fc4bff2"), + }, + TestVector { + key: &hex!("2393180bb81320965a58424b287c9b3e"), + nonce: &hex!("480053c69ac54b93f5e81338"), + plaintext: &hex!("d46fcbf950bfcfca3906769f922821473d3005d5a1d81278622d4d3cd9721a33"), + aad: &hex!("f6a2a3ac8e462fb01bbedcc9b0f8686ad4477929"), + ciphertext: &hex!("125874ff5a7f8936a76b11587bbebd461e27638bff5a1e993465c9cde82f2bd4"), + tag: &hex!("9b625b4c2f66cf2fc88043b9b4c6f2fa"), + }, + TestVector { + key: &hex!("d651166baf42b75adb26e370b76016e5"), + nonce: &hex!("4af70e3be1357501cbb16bca"), + plaintext: &hex!("21d76d04488d4c33a7e8822797f785b43540bd374206966c9ef7832c51cc009f"), + aad: &hex!("2c1072d5df5306e20d323a9897abac120bfb4d04"), + ciphertext: &hex!("bc557572490f4d63811f8d83e58214ba4d8d24290264381838328a2962f010b2"), + tag: &hex!("8bd1f65c551c4affa517a8b03b6337e2"), + }, + TestVector { + key: &hex!("48b7f337cdf9252687ecc760bd8ec184"), + nonce: &hex!("3e894ebb16ce82a53c3e05b2"), + plaintext: &hex!("bb2bac67a4709430c39c2eb9acfabc0d456c80d30aa1734e57997d548a8f0603"), + aad: &hex!("7d924cfd37b3d046a96eb5e132042405c8731e06509787bbeb41f258275746495e884d69871f77634c584bb007312234"), + ciphertext: &hex!("d263228b8ce051f67e9baf1ce7df97d10cd5f3bc972362055130c7d13c3ab2e7"), + tag: &hex!("71446737ca1fa92e6d026d7d2ed1aa9c"), + }, + TestVector { + key: &hex!("35a7eabe7de2d176e97cdb905c0b7f17"), + nonce: &hex!("2fa0cfef89fd9849df559c98"), + plaintext: &hex!("08f23fc6fde45fe044cc2c397390bb362524bb16cfab7c548de89faf3ad98947"), + aad: &hex!("314e0423ac429f43ed90d731fcb5bdc7849595ee16553a1b7f91412bf98ac4cb052ca91c62a33b3928ee2887ebc273b7"), + ciphertext: &hex!("cf040174f8e280d10aa65eb59db8bf3e4e2a8aa01b1f320564314946b3749af2"), + tag: &hex!("94f78c8ab96107437826050e1a89b9e2"), + }, + TestVector { + key: &hex!("23c31e0e50ed44fae7e6df38abf0b16a"), + nonce: &hex!("779034aee3e3b1942ef3e713"), + plaintext: &hex!("681d498d7e85684c5996ce27270fe8065089e58617cc6deae49cceb27dc1e967"), + aad: &hex!("6a7877001fb018519c7f660d77cae7bd892af075ae2d68940071f9156bda7010eb25d57885913544d4922a21347c808e"), + ciphertext: &hex!("7b14a15674755b66af08d581ee6f8b98691927cb1f5c43e5589de61c1b3883c9"), + tag: &hex!("2fa40d9c65eed28a99f95af468293006"), + }, + TestVector { + key: &hex!("4b4f9155d8db85e0e2b36bf3aa981e6c"), + nonce: &hex!("7c8d933778e1414e7338d934"), + plaintext: &hex!("f8a26c7a9a614a17151fcd54406891adf34e31a0d55046e1b413195b44113bb7"), + aad: &hex!("43b6c54526318efaa8f0a4979ccfa0f299f5d9889433b19971f60a663e359d1f2c1af393928c9b4165c07d7536c910de"), + ciphertext: &hex!("3f9bdea3c3561ad417c205887aea6ca1ee070057388dc80226f331ffb0017de5"), + tag: &hex!("e8ea1d3077df2c3d20f02a5046fdae73"), + }, + TestVector { + key: &hex!("4148dd87bc6aaa908a0dbe1e5d2f6cc7"), + nonce: &hex!("d01ffa7787117f8cb0b4014b"), + plaintext: &hex!("bf1968a91d5da5c9e42ffb5cdf11e0d31b69935b22958c149c005d52576b262b"), + aad: &hex!("fdeceb385ed6de0d2d15453f022dd455b8db3bd9f13e44f085722a6935ea6631058e0cb5fcbd3b9e97db339b529de123"), + ciphertext: &hex!("bfc9ecbbaf49371107cec37f80171f94141e25a486e1b42d8258208a6038fa34"), + tag: &hex!("f2dad0b16bb728cb957ad9ab0716d195"), + }, + TestVector { + key: &hex!("5d50961aa7fad7cae9a8d043e191c9c6"), + nonce: &hex!("263f4dc6464e89110a77f24f"), + plaintext: &hex!("0fed89fa86e5fbc4bf2e352caf8e1e8910f106db7b5092feec9fff5f4f768ae4"), + aad: &hex!("e74cd8621c2db03d6b47cda4ae0671dfe8bb62f26715bd4397adc679c987016bf305a1e555ebc91a048e2a7bdc7cb8b9"), + ciphertext: &hex!("2190380bee10ade973aea0db269835649f4e53e4724598e1a935704a40411b16"), + tag: &hex!("0aa3d68d90ef3d329ff394451db0a2c2"), + }, + TestVector { + key: &hex!("c2428b54a781242f896bbc8816e8176b"), + nonce: &hex!("715d8c8397ee55eb53f86a2a"), + plaintext: &hex!("0088129bb514a66d5a208838e20c7978ea6389cbd56e85de87e0db0608d8c1a4"), + aad: &hex!("435bb2a96fae0ab64c0a499d6e50bf2e5560643338aadabaa795f82d6503588d6522a70e4e475297aa9c5bbca7138b05"), + ciphertext: &hex!("a9fb750c009ffd7fe76703e3588f747fa58cef68b1d9dd2f953bbf3ab6da2b59"), + tag: &hex!("613bb91239aafdced8fb87b6ba0f9e5d"), + }, + TestVector { + key: &hex!("6a3408481a54a1d9231142ffb9fd354f"), + nonce: &hex!("bb2fdedd1a33321ace0a5c66"), + plaintext: &hex!("63c934eeea0dca9732734d800034e57616f4d339aedefd515a829300937e6d5f"), + aad: &hex!("448f17c604cb976cb527b3b1f8d40350420c94545d73ab72a3dc10a32cec537d78a17d32fe073b329e25bb2d538b5bc1"), + ciphertext: &hex!("b413a9c842fa51001b8949aa81dfc10408391892eda84785e725745378536d24"), + tag: &hex!("1e323d12856a644a86f394f96185a07a"), + }, + TestVector { + key: &hex!("c5a7ef970a7f42b83194bfaa62dc092c"), + nonce: &hex!("9505924d0b11200db3c40529"), + plaintext: &hex!("84ba18d1e1503d1c512e0956380811bc70f2d97f65269712431a3720ddac91b3"), + aad: &hex!("c2b989d3d56d6dc0c3e846631e11f096a1c3f016984a2a60f593f5b45acd28319ac9828773c6d1e043c6213ce970e749"), + ciphertext: &hex!("b07c02dabffaa8f7b11f644e547f887f78bdc9babbaa0ca66e350e2b5a293b35"), + tag: &hex!("11393df432636dc7d7a3f183f531166a"), + }, + TestVector { + key: &hex!("3f45c5c7d042ee34e8257bf83a46144e"), + nonce: &hex!("0c732f208ec1f8e0e0de0eb0"), + plaintext: &hex!("d46fafdf04468e91b9b87a84f71261bcd44b438e3a943590c6d1990786909ec1"), + aad: &hex!("991c82c9e48dc887f054bc0b45979dd8d244954ea910e30139da9dad476843691f32c7b494114e058d2b27284ea13a62"), + ciphertext: &hex!("54cbb18328682037bdddb8c585b731b18b5cfc495d9b899c9b8db8a11d9e46e9"), + tag: &hex!("289349ea094839dc6e9570c1d7d62a91"), + }, + TestVector { + key: &hex!("10f0569b4e6c441858f8053a646b775f"), + nonce: &hex!("863dbdc9eb8a9c1ac1af6ac9"), + plaintext: &hex!("f99eead51bb2a17f370a50079d93167179af5c49965af2d3f06d211fd96d6ba0"), + aad: &hex!("41d372deba9b25bb982d8c4662f063f95d1859640550ee6177862644b028f42c435636cdc0cdc57509a5fcb75657e581"), + ciphertext: &hex!("566f59cf4fe7b14dca35575743867351f18b1fa7e39417f8e7fe4e8bf1052ca4"), + tag: &hex!("df39c291b26f8ca2557abc6074694070"), + }, + TestVector { + key: &hex!("66f958e09896ab2b21eb36fc36fbfcad"), + nonce: &hex!("371a4dbdf80e6d46508a9621"), + plaintext: &hex!("c0458f59bac039a4349e39c259edf6cf62fbd87910064409c64d8f6ef55d96ef"), + aad: &hex!("19f19eafb6191fb0452807ba2ba6ae4ac36b37138f092cba1a63be58e4f8b994f2f6958799446b5d226fd23a95fe793b"), + ciphertext: &hex!("192474ad795e3e3e36abcef2d42c038d39ece8119fb058a752b7959fe46703f5"), + tag: &hex!("d17dc61d1513fc1cc2df45283afeb556"), + }, + TestVector { + key: &hex!("0f46ef6999a3cbcc2e539a8952a7fbcc"), + nonce: &hex!("ff8829c2fb56cdf74914ad2d"), + plaintext: &hex!("37401d56052412f91aa9398f3ab3afe68ae500aaf40f7941c8a82ae56379fd5d"), + aad: &hex!("fc9a1c16b0f4cf133843a7664a17e97c02e7aa360153f5b4b881ed3825f7b2a414adae94c9a6479a9eeaaa206f99c3db"), + ciphertext: &hex!("6866aa7699a8ce2c747880001987c28393fea80acb7b24a9e6e61086df68f5b6"), + tag: &hex!("c996fc3e44887ad4d703b72dc2ecb1b8"), + }, + TestVector { + key: &hex!("90838209bbc8d07846127667564dd696"), + nonce: &hex!("febfb4dd04eb313933b9c278"), + plaintext: &hex!("cec0527329847a7eece6afa65c7f50ff2d7df4bc4e8d2990c41bf42aa9bda615"), + aad: &hex!("01cbb3a7a70001027b064c337260ddde8cd07fc786d71e293fe0bd44c794dbf7b054114bcd259e115e3acc98cd2ed7b1"), + ciphertext: &hex!("e6275470454a9e0b6f6ea2a4d64cb93462a6cddc69e80f338098fe8b1d4bc364"), + tag: &hex!("50ddc254d7504590c938a503048cc8fe"), + }, + TestVector { + key: &hex!("f94e9d80b48dc5bdca82f14daa46be16"), + nonce: &hex!("29bf1931f0dc4fe3c807e234"), + plaintext: &hex!("64971fdf74f93f8aae32a998e5acf2b09623795a77cb9ad888abe6c7756b0a9d"), + aad: &hex!("449e68d78fcaa2e0f2811a87a9c48a3cd18e4d644eb88ef05b91f4528e35c713f4df2ff97de251bc5b04a177d2e29299"), + ciphertext: &hex!("f317607d97ed51fcc2f6ff7b394470758df772abb33b7ba049c6748b39fc4005"), + tag: &hex!("6c473bbc8881239f85eddc79f5daa0b9"), + }, + TestVector { + key: &hex!("8fbf7ca12fd525dde91e625873fe51c2"), + nonce: &hex!("200bea517b9790a1cfadaf5e"), + plaintext: &hex!("39d3e6277c4b4963840d1642e6faae0a5be2da97f61c4e55bb57ce021903d4c4"), + aad: &hex!("a414c07fe2e60bec9ccc409e9e899c6fe60580bb2607c861f7f08523e69cda1b9c3a711d1d9c35091771e4c950b9996d0ad04f2e00d1b3105853542a96e09ffffc2ec80f8cf88728f594f0aeb14f98a688234e8bfbf70327b364"), + ciphertext: &hex!("fe678ef76f69ac95db553b6dadd5a07a9dc8e151fe6a9fa3a1cd621636b87868"), + tag: &hex!("7c860774f88332b9a7ce6bbd0272a727"), + }, + TestVector { + key: &hex!("93a45b16f2c06a487218d761eabf1873"), + nonce: &hex!("f658ed7ce508e710d5815f18"), + plaintext: &hex!("b6a2afb916a235c7fac5cd6a8e9057c2fff437b7544532a296a3c80c35f47c99"), + aad: &hex!("33156a775586e8c92c7e99c467a840281abc19483b9a320e707bf1ffe856ff1c473bb52f5b940e44df2c2f766cbe9ed360d844283f8daa3ef68def4bf5f2c3aae3028c2d348ca1963e9227cdfa6f6205dbd9f3832e46a4f552ec"), + ciphertext: &hex!("6564e15287e995886395353c65c830e6fdd295c7ec2633c7f8d280f2340cdd15"), + tag: &hex!("e4f4dfef764270a068a9095b9618ffef"), + }, + TestVector { + key: &hex!("5015f6b267f7ba8f83b46ef9440a0083"), + nonce: &hex!("b66dd42e69f8a614516ab6cf"), + plaintext: &hex!("d1207549cc831a4afc7e82415776a5a42664bc33833d061da409fbe1fb1e84df"), + aad: &hex!("f06fe187ad55df4c1575043afb490c117c66e631b6a026ac8b3663d65f4e605b57f467ed6c0a3fde03db61f82d98a238955a3e0f51bac78d14b94a0b75057a432ff375a09b0a41def3c887fcb103ee99f4b9f4474a64600b87eb"), + ciphertext: &hex!("9600b7aa6f5d8e30d3bbca6800643ee764b59bcb83de3dfd03364bbc9a48252e"), + tag: &hex!("49a0ad2dfbb49e8acc6ad1de4d9311d7"), + }, + TestVector { + key: &hex!("408722e80d9cae213180efc0f2675f32"), + nonce: &hex!("e9ed15b1942f1ab5e9cf9421"), + plaintext: &hex!("39ed45bdd73f72aa16ae833d05c6d9ab1fca2b5ea478db553027787857fc9fcd"), + aad: &hex!("19fb7034ac4f57035cf19f68d76c4581054edbabe884e076a0498542d42f0412f5eb87c2cafbe13b9936c6fcee4c7bb46df2274306fb1a86bae4660290c13eddeb8cfe8de585e415563bc1a6ca9823b66c8f2da5da5df8f41677"), + ciphertext: &hex!("9241526c638c2f0a2d1e52bb049f71039565bba5c59876eb136f92ac68ac7f6c"), + tag: &hex!("a6a9b62c36b156ad4024e705c1d78360"), + }, + TestVector { + key: &hex!("678c4bf414452f1c5a659669646d4161"), + nonce: &hex!("295d2762261d1a536e1c057c"), + plaintext: &hex!("53f4ab78c16a20c07095afa50f7e96d66bdb5da90e7e3a8a49fac34652726edd"), + aad: &hex!("bc84743a0c42bb3423032a89857de5a9355ed7821980bf18379ae503b69da35601608f62bbfcb2e2ad9eff7e03fcb4b6d1768ad3a4d92831c5b2e3fc0eea3ab7b874f64e84c376a8f9e15b9aeb5392de10122605699f7d03a999"), + ciphertext: &hex!("2c821a0eb61cbdb09f84f086f69652b38ac9d07a90985f3ef36482a9ef8edbb2"), + tag: &hex!("e6e042fe0894df45b7d9898e96e9b906"), + }, + TestVector { + key: &hex!("8df843ad9376d7326114143899b4ca6f"), + nonce: &hex!("cdf3b88613e485fe6886e720"), + plaintext: &hex!("c1fcfda327533d17e1a6ac7e25cca02546c66635a115cf3f6d008eba55947d60"), + aad: &hex!("e5bd7fa8a56f3c155120f3bccb0fa557063e7bb9517cd04d9996533ef3924ee6197ee7512c6ef09d2177e75b4909c6cff0e86cdadce20e279a0503956f4c2196391a8ffec2d17a1d6614be7847cd114df70b93959f1765826592"), + ciphertext: &hex!("71b822b6d39c9a801a4c2a2c9173b0f3d9b50cf18e8e95291136527a9778edc2"), + tag: &hex!("b584a7e51d40ab28732c11ed602730a5"), + }, + TestVector { + key: &hex!("64b43dfcdcf30dfb97373d75d09ab733"), + nonce: &hex!("9359d85361a3e4c110d715f4"), + plaintext: &hex!("7c5c94ac7b138273de768d2bda16bef0774799df333fdd1a756e344ec35f2844"), + aad: &hex!("01acee6296478134999280ed47a5bc65dd5122c5d35092df54718900d04cfb81457ba9ec9d01e55dd8a65d6b3865fa0e7a45382f287c688c51ffcc951945e3e9c87b03c5545cec0d966926b8ee0453b69f25ce9fdf0a3065c81e"), + ciphertext: &hex!("5f9aa615e13b7b585bdc2d4c3a83d1304d6f78ebba0d5b329d86ca730a515702"), + tag: &hex!("3cbf9fa530b049e067868433307425db"), + }, + TestVector { + key: &hex!("93a951295d4428902a5cce8fe2068763"), + nonce: &hex!("8aed35ae4ae714cf756e686b"), + plaintext: &hex!("0029b749b4db477dcf47d0296eb88806ef0b56060d598e48c9b5a6f9d046404d"), + aad: &hex!("8186788a93a764a866944a2056279ad7f1d2083a96ce224fe6de60e70b17db18022a1504e1bf45c326c6d6992d8c005b675715016e00ec965b398b2ea4ab09cca2ac4ac312e6840ce00a36f6467028328fa30d4086e5bcb677ba"), + ciphertext: &hex!("792cd1a143304fc737d0739be52b2e61841a908963832cff06ab6ec585be6467"), + tag: &hex!("e1bb3eac7f570055fc2d2f0588c4935e"), + }, + TestVector { + key: &hex!("4f3114710c0e7f393b91c982beb3cfcc"), + nonce: &hex!("03994d0b244f94d13cedce90"), + plaintext: &hex!("36831744fd1c17a5df65a63d6642502075a0109f0f0c093ff33505140371136c"), + aad: &hex!("d294f939361af1bff5674a5235ba3e79bf30a5341b8634b5dac613e9a567ccce01b0596282ea584e579719206b2313f6675e7834f8a6d941e164169e97648ce77968ab4ecdfb3d639898468a1e8d285a9327dc958093eb33f8b1"), + ciphertext: &hex!("557e78350ebe53d1b7c1652669621db7a71a8fe2c0a84e61badf2dd9f034b91b"), + tag: &hex!("bc6c1f1322064eab75737067973d56a7"), + }, + TestVector { + key: &hex!("f00a034ea2f732863f9030257c8dcbf9"), + nonce: &hex!("2bd288fc2fabba6c44a04705"), + plaintext: &hex!("85472091a37ec5f37d50fc09fb6b9d803577227b4c079ae64a9264e7a784c4fc"), + aad: &hex!("312de02725a53b8a3dca7f02876dd9a4665de7a3f3dab7e4ac37b71d9d02478829ca38d3ec76d7792eb32478b92552e90154cf5608dcad4f33496061161af933d066e146888d1b7fa9b0c5255d59a8fdd88da638d06ee6d16d93"), + ciphertext: &hex!("9aa27810c3761ae175560340144610c7d263ad35234ecc55feed1c5dd3a4dadf"), + tag: &hex!("02724d14a7dcb5ef81ce8aa937f1419d"), + }, + TestVector { + key: &hex!("49dfbd368a541721d6cd5b2513ec6087"), + nonce: &hex!("8b0214ec3a6a6af65be84ceb"), + plaintext: &hex!("ef6cff08cbcb63a72e841340513f4e289ad34e89733731456cbfbc9a87b20f9b"), + aad: &hex!("6d3dc86af4bb9e92af0dec8cea981481341f37be457093d98a818d8cb4b68b9f7197b1fa310147701f047949af41d0b226af4a3b0b92e5342224766dab7830e1687aa3918a89d4d3b50d69595944f492d3d68b3609ca594e7f26"), + ciphertext: &hex!("e0802e60f73aa2fd669cf5870e963b1f33707ad4cc551f658b18bb72fd7cd9e3"), + tag: &hex!("cd6d9a33458ac709385acfbcffa457e5"), + }, + TestVector { + key: &hex!("3c0f57982449fad339c7ac5f6501b9ec"), + nonce: &hex!("4db6301b638bab6a833001eb"), + plaintext: &hex!("d1d5e1f3d8b491b2345d4a020add93e31596a5a204045f75fad53305d6b5aab5"), + aad: &hex!("ea3872b0d48dad649a876a6b3672e9c7ffcd69695a4d2eb1853ed5c26eca0e8f21385563d42dfef2e1430e06561b8e0b73b5f62ba51a4aca78c56c06c479961c3d21c1fa3823cf80145f7b24e4740127e9e9960fa2480e36e4c4"), + ciphertext: &hex!("32c508251494d05ed9413b0011a028a1bb9bf7e18f72de4b750cc7ab96ec034d"), + tag: &hex!("27c994680810f7b538c37b551b2f17df"), + }, + TestVector { + key: &hex!("8bb2aa3219c604544b4187d491586d9f"), + nonce: &hex!("341d76da6e3094fc3570ae78"), + plaintext: &hex!("274a2097708c53fd2a81444e13285691eec192c223b84dc9824c67ed3a050ba9"), + aad: &hex!("69c5e98cad9aa3327444b9625eabcd086367e64170d35c4586fa385a396b159425f8dd3969446529d651ce5a3b6432529487f91d193d05d2e345a28b50dffccc0396f76e418086e1fe2768e340c1fcffdb29e9514829548823f3"), + ciphertext: &hex!("ed8775001f33bafdb1ef577698116e9ae656085fca8b969740c7c697450f9879"), + tag: &hex!("6c8936c42dc46321695d3af2a33ada14"), + }, + TestVector { + key: &hex!("4d8154426d1b12eaf98d09ac05b1f9e4"), + nonce: &hex!("23e3916b9d64f98d122e6be6"), + plaintext: &hex!("d8a69c57969c6551c328675f7d772faad6c2c6843bf4b209e483fbdfc5efcaa4"), + aad: &hex!("2355631b9d487f4a7ec98d497f251cb79acfc58c0517d5e7b92a1abbae6ae7353b874d02faaf6410438539e02710e4d7cdada686871fef7582d562f384a571ce1edc68effdb932462e648c712b4e1d4e2e46718abd3cc5973aa0"), + ciphertext: &hex!("2fa53c6fd1846db81002e9c14da634480b352225e9190ab03d2598ef49a3b2b8"), + tag: &hex!("a4023fd8d0f076eed5992f680b154433"), + }, + TestVector { + key: &hex!("2c14b55dc1f8e3acf85258a12360053f"), + nonce: &hex!("5b5930a7f63b1a8ec445dfa0"), + plaintext: &hex!("41a7569d5f3f39ae06547d0ed681e8922382cfc940bc7e55da200ebf905bf476"), + aad: &hex!("dc8fb70d3afd3c67c9a86b3467ddfa23298c6523ebe7ef17b7bcdb2ef130c61bd5adca2eebc897fd4126470e0a9088e8ee4a60939024b9abc7ed551d0e79214edea566ca4d970198f9b3a20b6822f4e30fc2cbe76596a01817ff"), + ciphertext: &hex!("f64364ee15acf049d8bf90aaa914bffae9ac6073b8d56122276efe04b202d0f9"), + tag: &hex!("fa09390c1ce9ec97fc10c55ef2da2425"), + }, + TestVector { + key: &hex!("594157ec4693202b030f33798b07176d"), + nonce: &hex!("49b12054082660803a1df3df"), + plaintext: &hex!("3feef98a976a1bd634f364ac428bb59cd51fb159ec1789946918dbd50ea6c9d594a3a31a5269b0da6936c29d063a5fa2cc8a1c"), + aad: &hex!(""), + ciphertext: &hex!("c1b7a46a335f23d65b8db4008a49796906e225474f4fe7d39e55bf2efd97fd82d4167de082ae30fa01e465a601235d8d68bc69"), + tag: &hex!("ba92d3661ce8b04687e8788d55417dc2"), + }, + TestVector { + key: &hex!("7e6a5b6d296ac7a7494b72c93bad15ce"), + nonce: &hex!("5225c255bc82949a1cdb86c8"), + plaintext: &hex!("8bd452633f9dae0639fe0e67e36401adf65b3edf6799ff9eec80d85c13c85e0ee09491d4f5acaf8ae920281801a2f5d12c9370"), + aad: &hex!(""), + ciphertext: &hex!("2348f512a3a8501be9eaa41d8a127fcd8f0368d5053981a5626f85405363d218af7ba52a2bdb87a1ff07329f21792f4c64fc39"), + tag: &hex!("8753cee020ac668e9e1a37f63231543e"), + }, + TestVector { + key: &hex!("0d54e78be0eba65446682721368567f2"), + nonce: &hex!("aefce9f80307fbff0965881b"), + plaintext: &hex!("5b335be97a86c8c1a29b7408833f752c8c5d4c912e7f26c73b909239e1222fc851b4e3c0accc5148cc60af2f019f9ee0060131"), + aad: &hex!(""), + ciphertext: &hex!("7277aebd1beb239a3a610587b0d7cd71640291a4e4d6dca73a5d0e05f058e7a0e151a0d087ff256d08876e1fc3e0e5e69c72b0"), + tag: &hex!("bda879404fc226cfad834a3e85e04415"), + }, + TestVector { + key: &hex!("0bdbb7986a6026d17a9ded7700831f59"), + nonce: &hex!("e3bdba2fe3b5cad727071202"), + plaintext: &hex!("77ec68b51f5eb0f2d80d3af696627f365b6e83e69f105c7bad8e4869b228a0c496aa05c96e97a6bfcb33aa172f22c6bf3d5116"), + aad: &hex!(""), + ciphertext: &hex!("e7a5a701e950ca26987e1c40c889b475dba50cea13f09e9d3bc3cf4c84382c15bde4c34ff05eb278b4b745e51cbf4f12c12689"), + tag: &hex!("b794991a8a4a9f3d59d9987e9fb7ac30"), + }, + TestVector { + key: &hex!("823e852ef0b9551b2700bed65edcc808"), + nonce: &hex!("85798ee5fd33ef752a363d85"), + plaintext: &hex!("c1ebd968d861fddffab41857de7049bdee73acfea5564cf44ce40d75b960ca5453cda093a55c5527687f25433bd6dcde443030"), + aad: &hex!(""), + ciphertext: &hex!("e8e976e8175a41ec6a629a225cf277a1a7e2b839b2f581c88698a39300e4a54ef381f7b433e0ea9acffe59801d516cd4c61135"), + tag: &hex!("ccfdc010bd16ddd651d0a189255a7035"), + }, + TestVector { + key: &hex!("99c0001a7c12f331e7b3b164daf4616f"), + nonce: &hex!("383e8df9db398c5e9842257c"), + plaintext: &hex!("9d8ab6774cbf486fc4378a05a7aabba7ba7ff4a0f5eeb51c54c2ae9a5dd829d2735089955d5ae240d28da8b79994cd72234ee6"), + aad: &hex!(""), + ciphertext: &hex!("23c5e30b40b0946cf5b4df15407ff2d973397a10e94a303b71a4a5de074644006a10fcab198f86c4156c59e28900b958efcb8a"), + tag: &hex!("8ecd6196137905263729dafc06860720"), + }, + TestVector { + key: &hex!("6fa5f5b79f6f2fa7c1051d2a374db822"), + nonce: &hex!("d466bfcf72789143eade1e84"), + plaintext: &hex!("d9528856db087849264ac811689420ef2beea9c6767644f3ca8bfc6345a3e2e5c49e7e0fd9b1c2e1671bd1b6275b0bd43306c5"), + aad: &hex!(""), + ciphertext: &hex!("1128b1da86b71d3c0cb9904f2513d2329c033754fc0d40f87cdfc7ee53dbe3ab565719c8d1dc5d3314123bc9e096fc8509b85d"), + tag: &hex!("19092b9776c4a1f6e30354fa5115dc04"), + }, + TestVector { + key: &hex!("bce7d033f24ba8fbc237f06f40c6ae25"), + nonce: &hex!("c0d68906e987fe22344cae52"), + plaintext: &hex!("e533180c0c73d75799025303d660e43d5795ad46b84a05741b441f855eeea299a6484c17f39e884aee28b7d384afb49c134c73"), + aad: &hex!(""), + ciphertext: &hex!("4723daa516b920ec039dd8c0704a37f0bbad9340a7e987888db120459c39cc069554638ab6b32cff585ed58e2d7c1808229776"), + tag: &hex!("1ae612e476f5beb99f65aa9b5f02b3db"), + }, + TestVector { + key: &hex!("f78a05cd2621e9385ca111f3a168fdab"), + nonce: &hex!("a16aef83dbbd5f69c2569103"), + plaintext: &hex!("9e761d4b7bdce2b851e508f77faf447ff83505755494f1bb5169dc23bb02d9ba8fb8b4878c8a47dfd14ea0dcef3e83c688e597"), + aad: &hex!(""), + ciphertext: &hex!("7ead6bde964c35fcf5de23f19725387601f705ac11c5fe1fc531746bf2d871fda54264a623c70e72b5b5ecadc4434f9e696ffc"), + tag: &hex!("2f13e4bd9883c747f0c79c91e661aa8f"), + }, + TestVector { + key: &hex!("dc1b8569a8046e3f294c3cca018f6613"), + nonce: &hex!("5b3cbbe0e948db8efe42062e"), + plaintext: &hex!("6a3a1a9815690106d1908bc7e63e25bfd801900e94a9fbc28b6d52b8f9b4de7003b066bbb18bba33da83c67809e3bcf98b5cbc"), + aad: &hex!(""), + ciphertext: &hex!("b02a253a17fb9248277cae0305473870c19e70b7930a0be9be905423479413dbe3702f42024d69476415290b1422f2c030e99e"), + tag: &hex!("f0fb85e3d6b3a5ddc5da3ec797f758dd"), + }, + TestVector { + key: &hex!("cebef154b3ca2167230daf3b8205f11e"), + nonce: &hex!("e0dc23aa50a52cae644874b0"), + plaintext: &hex!("b8cb070ebf5b27a51f14f22c6b38fc29d04c431c484c117ad250ec4f97fc4df44b0ec847b69a363963d419ce9ad11a321686b0"), + aad: &hex!(""), + ciphertext: &hex!("4c0918e86b152be2c4dfe36c78b8a559c2c7f83fa7776d0341318a065c2a2f1b2678aaaff76cad30ccaa1dcd03a5bb16d00f3f"), + tag: &hex!("79267bdf70e74eaa011e889369f5831d"), + }, + TestVector { + key: &hex!("d7e95109127e83b4d43c81d7ef6d5972"), + nonce: &hex!("43ac0d8895ed785e2cb69d48"), + plaintext: &hex!("b2601f216b5e6f60c518dc817c38be940ac03babf2e6f5ddca0874e819f9aabe046460e3ccf6511566bbde2d9b191fc16ac4b6"), + aad: &hex!(""), + ciphertext: &hex!("957e712dc34ad891cdb3adcce62b0454eae9c792e64eb4e08624de103089cc19499749e8ae6d8c92e2c04c5cb36ef097bb00dd"), + tag: &hex!("f569562cb94828fe71fbddcfd984bae5"), + }, + TestVector { + key: &hex!("39ab7819dbf944cccd2648445337158f"), + nonce: &hex!("4594840e05c33bdbc0187174"), + plaintext: &hex!("834cb05681e9a7876bca891eb7824392c7ac29d4ff4c9a8ad96447d2cc5f0ff218043d3510201452ba5c789ba2a667bcf79b9c"), + aad: &hex!(""), + ciphertext: &hex!("362acf79df28c3c858e92c0c5f0a323b3ea2e81be67cfd903a627ed163c06393287b73fe33a435b96672b9bf1a5a2c2cff4a15"), + tag: &hex!("e58a30e2c91e6d25f423abde987cf2f7"), + }, + TestVector { + key: &hex!("73388f83e409ea236129e46dc9a9b20b"), + nonce: &hex!("a9069b00e1cd29a2b07b8db6"), + plaintext: &hex!("a2e138d5611c5043214f7d9f9c87aab94e0b8e99b311d0cae90829078c3898c8fffa7de9789af0a6c05f375b2f710dd4ba2610"), + aad: &hex!(""), + ciphertext: &hex!("77e0fa6b2765428ae418b57ecf5a392230fa2a9bd1686b91df69845cfa0a2dd9add219229e65ff6a2f887b78ebe8c0c5d1be21"), + tag: &hex!("32385ced195a16dad5eea5a19fd0fa43"), + }, + TestVector { + key: &hex!("d590e53b695315cc0b917d9fa0aac643"), + nonce: &hex!("102de7df461a5578e75c4975"), + plaintext: &hex!("7ee631fb685d4a94563e01480ec5526d04a4035d1f615fdbad6656e2495fe5d7f0d6c40dff659fc85f4ccd78433a192313c3d4"), + aad: &hex!(""), + ciphertext: &hex!("e1322d0c9265cd774d2e9d9b6771799600b79ba38374ee1756aa6871e204e5f6871cd50db15225ded64a9c8899bab37288a792"), + tag: &hex!("13e606a9a4c786b65e2260cdda4b1843"), + }, + TestVector { + key: &hex!("b61553bb854895b929751cd0c5f80384"), + nonce: &hex!("8863f999ae64e55d0bbd7457"), + plaintext: &hex!("9b1b113217d0c4ea7943cf123c69c6ad2e3c97368c51c9754145d155dde1ee8640c8cafff17a5c9737d26a137eee4bf369096d"), + aad: &hex!("d914b5f2d1b08ce53ea59cb310587245"), + ciphertext: &hex!("acfab4632b8a25805112f13d85e082bc89dc49bd92164fa8a2dad242c3a1b2f2696f2fdff579025f3f146ea97da3e47dc34b65"), + tag: &hex!("5d9b5f4a9868c1c69cbd6fd851f01340"), + }, + TestVector { + key: &hex!("4324c97ba8c9f2a1bd447bde5e75938d"), + nonce: &hex!("bcac68106a3fc22048462bc9"), + plaintext: &hex!("789fc14b7d4ec83ec783c0ef38faa6706031ade4e65ae91f0e1c579b8c8652e94e04c4ee5d85d23d0525c133a93a9539448ca1"), + aad: &hex!("2a893eec2eeef4c2e9c305428b9e3293"), + ciphertext: &hex!("2ba721de1aa7afba69cd0fa492fcad5fe639d855c1f280802b9cd5dff37f4bf54a117b8f400cb63906a3c78cdc1ae98b0c30d1"), + tag: &hex!("171df263a72252f2c44f5a63f089adb1"), + }, + TestVector { + key: &hex!("51e42ceb83175d1df09b8385a84fbdef"), + nonce: &hex!("ec6b7f21db6eb16ce87f89b0"), + plaintext: &hex!("4c5a34b0acc8745f45c04d6c82716b83ec6be5146d1272835ea642b49f55353fbc72a3acd16624e5377cbab54e356e3af6be01"), + aad: &hex!("3a081b5734537305222f314ef39a8d20"), + ciphertext: &hex!("1b4bb70f3ed38f378e29edb7e65081f794725a0340daec5708a163a3a81272ac2bd4b3e3db8f8ad57d571b5eb24af652e3c87e"), + tag: &hex!("6a9f2a4b73290fc566f37c286887eded"), + }, + TestVector { + key: &hex!("9280e05a614d452f407aab696afad52f"), + nonce: &hex!("099ef02922592254e44517cd"), + plaintext: &hex!("db91108d47f266dd9371698b194b3a183f2936782be417cf1a048c6504162d37e11a41e3bbfeb98f995ec8e35de94bffe0a363"), + aad: &hex!("12dc4da623d082c767a3f7efe9a6ebc9"), + ciphertext: &hex!("8ac070ab975218af0c22435174abcab01af5db9917095e67140b31feeb78b7d5be3186b4fc41f106303a519b5a32399d2de77b"), + tag: &hex!("7811b48513d9bcf1999b52304492b0ad"), + }, + TestVector { + key: &hex!("89be3c09ae7e2eff5b63f913aa8b575c"), + nonce: &hex!("449d852d65585185bc4298f2"), + plaintext: &hex!("93ccf5d907dea9b0fed5507f8a26400d0a568c0ef53b9fa6bf9d6802b20fe672c9a9536fc75b85f08e4d2c45cf032422f30ea9"), + aad: &hex!("d232713c2b024b5affd4a15050dcba41"), + ciphertext: &hex!("5b38069d695b76a609318e93cde6e239465ac52264017c3e5169bddbda0d2ac76ef0451a3a39d07e8e8da3b0cd2ee808912b4c"), + tag: &hex!("e316e6032fff56e5242caa1b4ef2bb6e"), + }, + TestVector { + key: &hex!("04cbf7dbeba906e1d0e8a98d796e8613"), + nonce: &hex!("b58059139429a6a6a38ccb07"), + plaintext: &hex!("8890c63ab730d9135e19ca3ada35b34a2d5bd9f4968d60e8c65bf43f0d6def7de472c26b89af9e5d6e48c125d84b0fef7d194e"), + aad: &hex!("7532c6237ba1da8b99c4a091c5159eb4"), + ciphertext: &hex!("52bc0be1920a4f1fb3ba3f9fc3e7969c75e40fade163897428f49fc52b6feffb61b65344ab3ac995e07dd5f615c24b447df9a7"), + tag: &hex!("239b60518f3c35b24c2557549179fd36"), + }, + TestVector { + key: &hex!("8f1c70136852dc27ae5162b8743c90ea"), + nonce: &hex!("d372f92b0cf030aab042a6fa"), + plaintext: &hex!("0b6446af88c455d7f1ff5116c7af949803cc50bcf1ecfc81c6627141a42b363f7eb7fc628503bb6f037dae843fd2d319b61118"), + aad: &hex!("7eeff5d17e79f00d68e26cb7e6bee76c"), + ciphertext: &hex!("4f235f6cc2c0474ab50557e2cf612ab09ffc85975de082b9cb9649a522b8a47f24e1b2c48f3cd57dce49542bd3560fe5e44bca"), + tag: &hex!("c541b78244efd2b9e61e75296f164aad"), + }, + TestVector { + key: &hex!("1ac69a35f749c65d5d27ec109b58f336"), + nonce: &hex!("f0b9c6e8cfc7ba4c880d99a8"), + plaintext: &hex!("9695507b944865587f27395c74468af6a845716b34db61e437b77d0107387b3fda581c466b6df40948da35906b77ff8ed09402"), + aad: &hex!("251d75d69ab64f1363efeaa771f3dc01"), + ciphertext: &hex!("f41dc7402768705dbe3bf7cdbeb4fc672d3a6c3d65520dab3082727dff084b6e0bab17f96c2b137a4bd564a13f77ee37347383"), + tag: &hex!("022edf7437b41653db3bf2479a9e74a1"), + }, + TestVector { + key: &hex!("16cbfdc8f9900f6702a430b0d8b624cf"), + nonce: &hex!("28dd5c46e03680f2c01a7bba"), + plaintext: &hex!("e1562d6e6a469cfd9f0a6a15be9a033cd454959ef8b37b2da58164fff1d8dbd3fac2b97bf1b503046fd9cc68bc942d0f727a3c"), + aad: &hex!("b1bcbdd27c0ef4de462fce0be8855a36"), + ciphertext: &hex!("10915ff87b80e42d548950e53ff6642ad44afa695175d24c9b5197f64c15570ebe0bc969c0251be940b42889464cf562c3e1a4"), + tag: &hex!("f9606f7a0e41153a1b45c25f1784cace"), + }, + TestVector { + key: &hex!("4c12a54aa7bb7a0c0c798834f39b3fa8"), + nonce: &hex!("e5854fac9adca3bb1bc549b7"), + plaintext: &hex!("7e7fe58f9f13907a694b47f053c9270c2e4d73b52642a71446943a5c5f3e2fcd554b376dd2f549aa7e0737b62c6414f542bba2"), + aad: &hex!("7f42a7791e705345888f00573be98980"), + ciphertext: &hex!("df46d7519910899b7c3d9e7d0dab82c93b7d8ee03f4f5aa82ecf64cacf3c9fb58f17a021536028744e412770e57562249e5f09"), + tag: &hex!("2823d4b59cf8f8837bebd5efdfb92929"), + }, + TestVector { + key: &hex!("32aced5414e267cf77844c0acbb8872c"), + nonce: &hex!("3d108e912d53b88e0dff9d6c"), + plaintext: &hex!("c7fcf53c93a521c6e244f203cfc40b80bd8ab1e4e54cdb581fc14c31dc6a93805edbba32a729acf1a7c04c8b0366c2035c65b3"), + aad: &hex!("7be4c5df7935453d50f1c6c79ae6c13a"), + ciphertext: &hex!("80beec8c20c7e9514c38ac6e3775de206754433cb1d7c89bbefb33b1b41245e0d1baf7cc870b1f1ec387f2dded3e0f479ef160"), + tag: &hex!("d97f7d82b3ff97f2f6c652194c004748"), + }, + TestVector { + key: &hex!("6275270952263f5f008b16f2456c7ddc"), + nonce: &hex!("1d1837ea4cb3732a6ea6487d"), + plaintext: &hex!("fd4de28a18a3de3b9660acf08eeac40e192b77c5264c80651c28628e61c3916f7ac03d849ae39c981a2808866a8292746a4793"), + aad: &hex!("6ee8ed2ed241f1d7cee55ca67001729b"), + ciphertext: &hex!("d69490708893f1638ad594c3a0ad8eb4f17da3203b18aced930976ee1abf4df1ae8a768ddc9df6ccdca2d579165023e52bb9d7"), + tag: &hex!("aa47cda3928f7a2ea42feae4dfb0800f"), + }, + TestVector { + key: &hex!("7796d479bcb213f19e2ed73ef1069fe6"), + nonce: &hex!("f0ebb6fb1df60069b00a34c7"), + plaintext: &hex!("f72603b6e74bafc20f423bea2a1036ab44461b5e5a5631b013573d953e1fb073b855511860d1782c1f3b146b5c41eb946e2fca"), + aad: &hex!("87563b4d72e2f2c0094bff678e3b7975"), + ciphertext: &hex!("44c4d7ba2af1be22daa6352b58bf8cda28999bc33c420f8881001719fe639a9e9e5c48df120f7cbe73af4c1513a637b9de33e8"), + tag: &hex!("8b7002219f586318150132e0e5cbf2e9"), + }, + TestVector { + key: &hex!("f7c50f29479ff0f9945ab9df56872eaa"), + nonce: &hex!("1bb94d7b399eb7a9a0efaf6e"), + plaintext: &hex!("fa86691b746424b3426dd9ce8cf0f132de5c575e001701324ca7ce474d5813a19904591055fc7f343e20d0f4c92118b14ce774"), + aad: &hex!("88a9f81078d6a0820c56c582a30333b9"), + ciphertext: &hex!("55024fc5e95e5f7c33bf948c167b13382236b2cf187cc09e37dce043f6293fe457a1dde728cf407c702d75a670397ffe28e8ba"), + tag: &hex!("645ca60cfc8046a0253f438e69b8e47c"), + }, + TestVector { + key: &hex!("f3e302a1568a5340b5745ae87f5a5bea"), + nonce: &hex!("ce41f436f2e84643f673603e"), + plaintext: &hex!("e4abaa66875bd8d45b6ed5e7671b03e09423ea41b7d89039da92728151bd690ccdef4fa16392a7f85efc0bc2b1664bd3f15e77"), + aad: &hex!("87ba36d234ec508b308ff258c6bd427b"), + ciphertext: &hex!("123b69b2d0f10934da3fdb5c1b96b4ffc8ffc1446088b634b38e145e6dd98e8fea17214b5c9136f039577d4493b8bcf935ae19"), + tag: &hex!("97ca8cf064a408c7b764cf32d3b79c0a"), + }, + TestVector { + key: &hex!("fe47fcce5fc32665d2ae399e4eec72ba"), + nonce: &hex!("5adb9609dbaeb58cbd6e7275"), + plaintext: &hex!("7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1b840382c4bccaf3bafb4ca8429bea063"), + aad: &hex!("88319d6e1d3ffa5f987199166c8a9b56c2aeba5a"), + ciphertext: &hex!("98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf5393043736365253ddbc5db8778371495da76d269e5db3e"), + tag: &hex!("291ef1982e4defedaa2249f898556b47"), + }, + TestVector { + key: &hex!("ec0c2ba17aa95cd6afffe949da9cc3a8"), + nonce: &hex!("296bce5b50b7d66096d627ef"), + plaintext: &hex!("b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987b764b9611f6c0f8641843d5d58f3a242"), + aad: &hex!("f8d00f05d22bf68599bcdeb131292ad6e2df5d14"), + ciphertext: &hex!("a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a07162995506fde6309ffc19e716eddf1a828c5a"), + tag: &hex!("890147971946b627c40016da1ecf3e77"), + }, + TestVector { + key: &hex!("d441280905a33bcf02ac16f8cabe97cc"), + nonce: &hex!("53294f8b440c82dbd9bd7543"), + plaintext: &hex!("5cd42b150db7d0bd6556e37e386dfafafabe2aefed2823be932f9daf1234aa0402bead485ebda3a0a6e392d5b0e603ae2dfca5"), + aad: &hex!("aecd49cb8890806d47a950c8e92ab294f325961d"), + ciphertext: &hex!("3ae74193c94ebb96fbb1bc5ecd180b2c0efa1ef4a9ecb6959631f8554f0eb237893476cc0d4fb55fa1880989c1616dd32b964f"), + tag: &hex!("0eae01a8473a8f603c6ae6b637e4aeba"), + }, + TestVector { + key: &hex!("4f66f21817d1865c2fb62d4de344e085"), + nonce: &hex!("4c780a2707f56747b24a4aa0"), + plaintext: &hex!("04eade2d68dc3c5d83f2d3f1c44240bf86127c9f6b3966085ef41ef50107d042b18bbe80bd43cdd1585fc5a99df8271b9b8767"), + aad: &hex!("4c0ec2531542bc801b3ddf593c2e1ba4afeb603e"), + ciphertext: &hex!("dcdf8d2b0d388072ce273ad3502dea5122bac0020a7ae3b97705d3a2bb49a5cb4f95e6cbd74183758c2eabc9ea38155c7ef647"), + tag: &hex!("2558c59cc7d71a2fcedd13f1c6659a63"), + }, + TestVector { + key: &hex!("638276070f70a48dfdd3074905f4dd8b"), + nonce: &hex!("08aa05eee9be39f28f61299c"), + plaintext: &hex!("bca63b1fd480b7c682f992b3ac40712cd412e5bd5141126311ea3c5cd91ff8d75b7ad7be0ac7f61d41292e673177e55e148b8c"), + aad: &hex!("7e3ef6f9d9d33a6bc5904b1317d235ce1a99ffb3"), + ciphertext: &hex!("fab16aaf8cce26586b50e794e889839e0edb63f14f927f353569cac1694604de593d72c52977bf7fe2b6fcecb2d8918d0de8e9"), + tag: &hex!("bd97aacdb02b80a01487d690b5e905bb"), + }, + TestVector { + key: &hex!("dc7fa9348b7fe1b3befa5a09b2dc0f7a"), + nonce: &hex!("51e208cfa9b9d990013f50f3"), + plaintext: &hex!("0b65800b4dc2aaafbc837f9ece7a9111f3ba0309196babaa6b63ef0fedab779e0d352933536520e4ff1c7f079505ead882adf0"), + aad: &hex!("b7219b5b1801457d71cfbe342148849622592c40"), + ciphertext: &hex!("2caae5923cad79802d682172f58191349240a24e25891461ae65394b95413b34e03f3551baf1a055d22a53a8a38f8ef78f6d40"), + tag: &hex!("10769ae854f8298cd94c28c3e28e94e3"), + }, + TestVector { + key: &hex!("eaf1659e08d0f22a7042358ab0ee0f0d"), + nonce: &hex!("d6911b68856038ef9dec1215"), + plaintext: &hex!("0e71b3765f17e016c3024be23d0af6cf50ce98d86943b38cbbe8f3dcb540dda64b77bf73c7cda108e1a5c4bdb590a7f747ecfd"), + aad: &hex!("433ae638214c48207fe9cdc76ef99e28913d6a8c"), + ciphertext: &hex!("bf4aff65fb7df0858962474bee9fbf95b0f06637c7d72bb1cbabe46662f455d3813665477b4badfb206a4d8f01346119e559ec"), + tag: &hex!("866f204b04a309d45e65ea890a17ed0d"), + }, + TestVector { + key: &hex!("382697fc2ca220a5d6a700f7fadbaae5"), + nonce: &hex!("3fe9d400d10dc33545d6cc5c"), + plaintext: &hex!("7d187a1fd4d518197c1e843d613797d4a9fa9da6fe9f773b947dcc0023c43e917df575baadea90237d95f88c54692ef8be672e"), + aad: &hex!("a3cd4b0216378918a46252ca16f2ac9775e993f9"), + ciphertext: &hex!("8e640b879d473d7ce6689175808b925b6ba1177ad8b0c53208e1b7c6303844f52c8cae5791d0aeceea028dac107fad5e80866c"), + tag: &hex!("3849e4fefcecb108f83ddc039a21dd91"), + }, + TestVector { + key: &hex!("186f6a73ac82e33f69c5b158c7ee1cbe"), + nonce: &hex!("bad41bfe8b67151131e85b2b"), + plaintext: &hex!("cc4d9dc2df86165343aada60cb5c1d9f991331d530d860dbf9166907d394721b2a22b53a6b070c5cb32ba3788ff55bc6a0d5f3"), + aad: &hex!("dab496ae14125af2fef47ee3b226a6c92e99b9e0"), + ciphertext: &hex!("41a17c3b18e67d84bfab344bff1429a87c3076879ea42383d1e622e710a60612eecf2fae8a56a95a08c958a52f873ecb303785"), + tag: &hex!("335015e14d2cd8eb9813799c5c703a89"), + }, + TestVector { + key: &hex!("14ba3901daf9db40d5dfbd828a361ab8"), + nonce: &hex!("af37192707a3804beb57c836"), + plaintext: &hex!("85f016f83ceba76a068e5def3ed5ebac85e203c69e32676550c6ed864edfd2ccb2c8da415a42cc6ead791e869296091efe7ca0"), + aad: &hex!("1ac4a38e83649004727d2b2b71075264cfcade09"), + ciphertext: &hex!("2a682e5579d7f801fdbdddb2b5f8564c9e91c39cde47c48ac1dffdf7ef1674ed937e77215691110ab730af97349f84128eed56"), + tag: &hex!("b1b50298f48b96e679c3d71f3d17d623"), + }, + TestVector { + key: &hex!("c0552b2f54f4e8292119dbf61285fecd"), + nonce: &hex!("b5a580ec23753690d6c7392f"), + plaintext: &hex!("88c04f3421de415f9ee9b47e033666c0d182d04f38e6faff5fee5ec89d1bd391079e90fb22c537efe4561718588eab313cfd5c"), + aad: &hex!("46cad83fbea4c47b9374bacb072472edcece9acf"), + ciphertext: &hex!("2ca83a4a63de404ad2306a4918420fe3105cf7f9a52d16aa610e3b69a0fed246da41768c801c19d7502ccccd5ba0a1bc0b50f6"), + tag: &hex!("8c03304e8a74dd52d4e3baec89cd397d"), + }, + TestVector { + key: &hex!("c6efbeedca979cb2c4fa5d6454a77dc1"), + nonce: &hex!("4e57df4988d93d13dc512487"), + plaintext: &hex!("a52077491b20ac65eff89bd0bdb6150ca755cf469c42ebbc5c95bbcf3aba91a9002bf386fc9a126fae73dbb2daa7ceb79d0b5f"), + aad: &hex!("9e65d0542711fe57abfda27587ef4161eb3fe32e"), + ciphertext: &hex!("4dd803cf6c99d2ce3ee8a1996f52837e52c3bb386cfc2792318e1ba64c35b638c9508b2e21d1da6e635e59e37c02c0b0a2529d"), + tag: &hex!("af847ce419fa54045a8bf31062f6d349"), + }, + TestVector { + key: &hex!("3d68401d7c5f5c0a2529ede00724be14"), + nonce: &hex!("3f3eaf76e786e8af54baa56f"), + plaintext: &hex!("8bfeae1dadfc55baca191a6a3f54ab721862c51ce684e4aea6e9a3e2f3d2aac14af1cb0252f29a4c8c0984ce867acebc7596c7"), + aad: &hex!("6a6e3ea815e01cda78a76b0fb8bdafb8a25a6b7e"), + ciphertext: &hex!("8a62b81a69e6e104dc075cc32730ffcb419b9f41711e06d7c2d9e891a88dc6e88817cf5bc2b87e95c4678daf0ca4b8f1e03927"), + tag: &hex!("9eebbcee46565fd4c34b8f47bcd94b31"), + }, + TestVector { + key: &hex!("0657bb596cc28eafd51cc09a3e6ec1f6"), + nonce: &hex!("8e11a0625fba51698614f8f9"), + plaintext: &hex!("435f16f56aa71734dc6571e2714207f7ff85c7eeaa1879901f2ffa00ea45038db54329f0a2e78ac58a5d76314788d8351777fa"), + aad: &hex!("cf73715474e49d71f4f5ad08e209ff9774ae9639"), + ciphertext: &hex!("d876339f0db3bff022cb4504fe0a8ae26040102f575ecd4e4583b04959976254d07384141ba5748d3579815e3b5e1d1e8fddaa"), + tag: &hex!("7e6f7096e425911fe739ac90cca05fda"), + }, + TestVector { + key: &hex!("b2c645e0f2dd0d21e9511364f9355919"), + nonce: &hex!("91f6f089f5e828d6fdf12510"), + plaintext: &hex!("3c01159e4787a74a707b4ead3be126b819831296821f1add394762ac97599cc810bd97205d0743548e7150bfbe6d9c1ba5d581"), + aad: &hex!("e6781ff89032df5e5398108f1d569d7f8327b25c"), + ciphertext: &hex!("1a06dec18eb4c9b361f1f2ec6391daf275f15d97a7f1a73fbe1d144bc1e1018200f725d52400c693a438edb595fd4558c4227a"), + tag: &hex!("451783874f9d925328208bc4c56eed33"), + }, + TestVector { + key: &hex!("3c50622868f450aa0928990c15e1eb36"), + nonce: &hex!("811d5290768d57e7d87bb6c7"), + plaintext: &hex!("edd0a8f82833e919740fe2bf9edecf4ac86c72dc89490cef7b6983aaaf99fc856c5cc87d63f98a7c861bf3271fea6da86a15ab"), + aad: &hex!("dae2c7e0a3d3fd2bc04eca19b15178a003b5cf84890c28c2a615f20f8adb427f70698c12b2ef87780c1193fbb8cd1674"), + ciphertext: &hex!("a51425b0608d3b4b46d4ec05ca1ddaf02bdd2089ae0554ecfb2a1c84c63d82dc71ddb9ab1b1f0b49de2ad27c2b5173e7000aa6"), + tag: &hex!("bd9b5efca48008cd973a4f7d2c723844"), + }, + TestVector { + key: &hex!("a7268c7ef7bbc2be4a3ffc282019fba6"), + nonce: &hex!("df2c5bd03f2cc45a07173144"), + plaintext: &hex!("f88beae931a68ed813a35bef54bd9999fd23ce4a1d258e34fac184ba799132a408bde4ced23748db5b35ea9692f4e1561d4cdc"), + aad: &hex!("445b4ec6c505f132d3b012df624fe8f6e9cda0d8ec5e1ef7cde8b89259e167d68c1fb4dc4a78e5c59377f32ef5cea4b9"), + ciphertext: &hex!("ea53e264e1b0f67ee37c81234d3b9c253ab1a94a4ad17779efcbeef0526129b0fd224b5884eb8b38e35ce0bdda222e30f576f3"), + tag: &hex!("38b5ef8d660f856d495db50f702bb462"), + }, + TestVector { + key: &hex!("183dc6bc9a497304011e5aa41dc575b4"), + nonce: &hex!("0f4e2961d8ac4f81f559de7c"), + plaintext: &hex!("aaad38b847c7a6fce801ff4ba62639592c487382e7e3ab0f29d0dde432f31028c0b14c67c15cc3664c660c197b4792433924d4"), + aad: &hex!("8ade36c0d68fa431838beb9f1d6a422365024bd5019979fa9b09b7c44b785e051dded5c9e21f342cf376e72cdae95207"), + ciphertext: &hex!("38e09d7612a536a80d2e32a46b0e1e4ab1e1022e854461aa7e695d7aa4a003e379c0e270face29e19d74d40a60fb2e8c726aca"), + tag: &hex!("4004e9763f4a7d0fcb0ba57c7611f281"), + }, + TestVector { + key: &hex!("047dcb88c16bd0d32d9a6272b079e379"), + nonce: &hex!("d174ed8d60c0d5c814dad4f6"), + plaintext: &hex!("f957104f1fd87e9e1d6d35171a1cbe8fb22cb4ea7aba31e763e77c6f291db81c63c910cf9b8d37bf93fa28fd4e2808480b5836"), + aad: &hex!("c6567022bdb5f2f3a1e3d78e0202a5f6b457c0ebf46a4b0620afa2b5ba706f1a37f932058afdb8cf4eb9a3815ecad445"), + ciphertext: &hex!("b7f83cb77ef93895a6721dfafde8930090d2a9f39a1d605bbb8d7fe0f0fa838fc6d1f0e5e532592d0c688231e24139e635b502"), + tag: &hex!("452368d42f8a1211b4a018ad1acf837d"), + }, + TestVector { + key: &hex!("7286fe98ac0c03252f3ab7eabb8988eb"), + nonce: &hex!("e32e708c6302ce26902bd599"), + plaintext: &hex!("58fad037e6efa65630ca14698725538c686ced497c584afad218fa3b753beaa7a72fab9c4c108ad14bf5f024613f91a1155679"), + aad: &hex!("4b9003a0259ed70aebfabc90abe750b888e9db453d9f95790d752d4ab9f208ee478046abaa9b2bf24564216071613297"), + ciphertext: &hex!("ead0bc4e5902600598f9ca9e91cf4543420cd64e281a710fe890e0cffefa803d8c046390da6f50fd44b7e87861ac4088b5266d"), + tag: &hex!("970659d5170d654b55ca5f79a9e06957"), + }, + TestVector { + key: &hex!("0dc3090d2786eff167b291e895ac2261"), + nonce: &hex!("6ac8f3a8a61448e1fec06d6d"), + plaintext: &hex!("3017261d20002fafdae4252dcc9b1214e9a9ee959533d34aab136249ca4ef52ab205ea69efe6fd21ed3c90f8933593fc63454c"), + aad: &hex!("a85588d465b1ec2d935ce1ba5d6397bd57055915329830b1aa4a934f2080ecf48ab5f6269ccaaed8a10f398be64cdb8b"), + ciphertext: &hex!("1fd7efc41a54374048e5d2a196bbb5b78452639db232c4c106fa8da6b1471ac14aaf2328e959a9c55f201d7271451151bfb48d"), + tag: &hex!("be7ff0322d4d42009dadf48e5aa939d5"), + }, + TestVector { + key: &hex!("d169282809ddae3384a10b908b8526c3"), + nonce: &hex!("c9448a902e05f8ab10ad92e8"), + plaintext: &hex!("490b469f84939d62e00fdef53430232e5b0ef130d586bbfa8a3d3ba30d91614b64e0da092f16b83a46c9386ebed0bf9e863950"), + aad: &hex!("71b1efec4e50041d0446e03b07ffdff05c6259d90aa7b33189e95360bfeba23afe914d0f17db6ba47ea165cc06d501e7"), + ciphertext: &hex!("ca693b2350d23808840870c2371f49eda453f2e189c70b975af2531b9e8b0d8c262829e61f8990804844ac941b2fe47399a88d"), + tag: &hex!("8bc9e25a568987b427cfc5b42e412d7a"), + }, + TestVector { + key: &hex!("93814839da20b560268ad8fe257a9372"), + nonce: &hex!("f157ac4a83a7b73b8085085d"), + plaintext: &hex!("bbad922de6dea7153724a333554e1aaf2e37aecd182b45885d04f3d11c3763fe59c26828d30c9da95adb75fbd5fbd2e6ece12c"), + aad: &hex!("9b422e74f2109925264c1c0dda2b68c979afdac110e42b81afd2c59e2df3ff3f93832552b626b3821212a3e20c401949"), + ciphertext: &hex!("be069b414d93d4f641b053f1ee7a61e23bf287a63b1d06c05393e8faa5856d22724bfc511a306ae4ba12c0a051b479e35c229a"), + tag: &hex!("53a62f9431b8e6124c9bf6298f1b2880"), + }, + TestVector { + key: &hex!("3262f2442b89a3641456cfa3d4d186fc"), + nonce: &hex!("d0fc4f8f7bb74a1763862407"), + plaintext: &hex!("fcdd7cd83a366f94289d8b470345fccea2aff778edd9f60c6d8273b3277a843965f0d4ff8be1e61ee82caae8754b87e747b2d5"), + aad: &hex!("bee1c8ed52bf347431babccac2a64275224045d5c1122eb8c2ac3d8791a5a9c37abf050c406ebeb947428bb60d58d062"), + ciphertext: &hex!("d0e5cecf32ef65035546cf8a99dc7e6f4320376f8e16a51958dc796c9b9a37a0d74e7b9979a0ab5b88ad92988dc184b964a11f"), + tag: &hex!("37c52cd41ee2d519aa8363b186aadcc4"), + }, + TestVector { + key: &hex!("fc937348a4468afaa629f158dcff5a6e"), + nonce: &hex!("783aa881ba0938ed8fe8ea30"), + plaintext: &hex!("0db6285ed23143762d6e9b708f0c84ed3f48d51e8b3da549f1ce130bd434d0c38238d0e2c6e2b7f6a35eba2cd84d28781dff19"), + aad: &hex!("31b2892a669cce974c2b467d84c45189b335a5943d43b2f158d5c173be4fe31f8142f1b697c772f175a65dd87ae5fb52"), + ciphertext: &hex!("29d665791fac09a72dd2178d69de16a5ea3432bf70acfaa174ec4cc93df7efff5f3c057c1ffacc80eb2991b1c79ab565c1f97a"), + tag: &hex!("113a2dd0be60dd45ea4f3d8b90c1122c"), + }, + TestVector { + key: &hex!("a9a33b71eb81d091ac1d15e48a19a067"), + nonce: &hex!("bb86b999753142de6573e863"), + plaintext: &hex!("910246d2435786fdc8f950a0e3a79d081ea1c41eebb875de2eee9daaa8250850f636522cc953419767ad24982bf14427243971"), + aad: &hex!("7a4ba8b30eeee2f457b74699d2ff77d8f9912f09757972bf8e5e8ec37684a8e1523b0afec0aeb5fababdd945fb55eac4"), + ciphertext: &hex!("a4cb039956e398846bac343db72b72ded486f64fc58c8b3c3d8fbf1f91b00f4c7c2a560f88f73b7eda4bf2bcc9d4f7a6c62f9f"), + tag: &hex!("dd594f34a29fa02af3accf567d7c5206"), + }, + TestVector { + key: &hex!("7cb2f97b5609e76040712a95bfe84fad"), + nonce: &hex!("1c2398ea67c1246540c469ab"), + plaintext: &hex!("ede4b5732c8fa7bebc87f72da2e243dd4173ddad700bef65adeeaa0c570392fc477b3d2b7d404bea40074a6d58a00f2466c1bc"), + aad: &hex!("add3e89872e09f64d828463d5df7519de1a9db7639229b67901bd27ac3c3ea61ac1612067d72037adadd2e14475584a8"), + ciphertext: &hex!("6c6dd8a691eb22294818e61e33afea9e49353d1bb6f645e821d7c4c31fb440dd8cc2651450a764a22038978651ffd33d4be108"), + tag: &hex!("ea246bb5e2ab3282c27927cd983a7297"), + }, + TestVector { + key: &hex!("402fc879126ff144792af40975f0a24c"), + nonce: &hex!("bdbf6e81feff5a11df17e205"), + plaintext: &hex!("8c60dce80b0a5ef578d680d1c811967265cc7664c751faf4d1472dac5b96e26e3be439b19e3da83b1a19dc82ba00d435e03342"), + aad: &hex!("de8443df44d93b3734d8820b9a26010d6ce09c1bb9a02260235a40299d38330f67792d0f54c0c0fb35ef9febcbccd02b"), + ciphertext: &hex!("8753e01ee5c088bcae1309b2e4269d9fb15491831a1e17140808f30aee4fa528020a7fc7df8627cda9b7401c44b15aa1e7c644"), + tag: &hex!("0f457c92a99ac1eba1b6105d6d23ce53"), + }, + TestVector { + key: &hex!("ca5549614dc0324564002139fd6a360e"), + nonce: &hex!("8a4de31b0ddc6d2a3570fac0"), + plaintext: &hex!("37610c187d287982e9afc15a9250aeb91933369dedc5910e4de584d70c27b7e4e0a7b02869299100fd8ef75bc66ae4bed2a853"), + aad: &hex!("6b88709627c28825569d60772b6642a9dadbf3ea9904b290dc632a837d579d2e81284bf4350923c1863e0e8d5894a34b"), + ciphertext: &hex!("29505af512768c89d84054cce8f8889e9b4a095098b9cec7e26a6afcf7aee5132fb43caf7edc068fb6aea3570ad9310a5c3329"), + tag: &hex!("d0918033b6db5f999f26bed94d352af6"), + }, + TestVector { + key: &hex!("a68b64267d0d1bc2d94b9f691ff8e9e4"), + nonce: &hex!("a27706bd8eae8bb3dc95a1b9"), + plaintext: &hex!("4a99ab41c604d7210069d9228dd3223b6f7da215ddda16cf93bf6658784cbbfe08ef6a0152cef368415dff9f8d1d05ead043f9"), + aad: &hex!("8734fa3cecb5793b2b7bcb4fcde7808303c27c2c002a27e0dbaa378b3df4909e37c238a24faf49b6cd134419948bdec6"), + ciphertext: &hex!("43aa0432a1b468bec64de45b66b5fb3e8b2bd9277801ef53a1cd6757bfd45aab9c6b23f0a1f4b30fa33fe52fabe7bb86281964"), + tag: &hex!("fd39ef2e94707a1aba57ff2de7c17927"), + }, + TestVector { + key: &hex!("2c1f21cf0f6fb3661943155c3e3d8492"), + nonce: &hex!("23cb5ff362e22426984d1907"), + plaintext: &hex!("42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d68b5615ba7c1220ff6510e259f06655d8"), + aad: &hex!("5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f4488f33cfb5e979e42b6e1cfc0a60238982a7aec"), + ciphertext: &hex!("81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222b6ad57af43e1895df9dca2a5344a62cc"), + tag: &hex!("57a3ee28136e94c74838997ae9823f3a"), + }, + TestVector { + key: &hex!("d9f7d2411091f947b4d6f1e2d1f0fb2e"), + nonce: &hex!("e1934f5db57cc983e6b180e7"), + plaintext: &hex!("73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490c2c6f6166f4a59431e182663fcaea05a"), + aad: &hex!("0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a20115d2e51398344b16bee1ed7c499b353d6c597af8"), + ciphertext: &hex!("aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d573c7891c2a91fbc48db29967ec9542b23"), + tag: &hex!("21b51ca862cb637cdd03b99a0f93b134"), + }, + TestVector { + key: &hex!("b818752aa4452120808c3d211d57c224"), + nonce: &hex!("d679a0be22c2daf619b11463"), + plaintext: &hex!("7ccdecf13130c20f67dd6f47adec33dfb52bc84a7700431b7fd398d652a123f086ae197328cfaed127a91866c95bdfdb4849ce"), + aad: &hex!("bb853b60b5fd8bd24acc9db9dd3de48b775d4a5cb2a879c1dd78bde94cafee06db12a1574eade205dfd3a8c6f68599e120ec73b6b4559cd03d3118b2b1bbe340bb15320c6bf8d8a1c3c1247b4023ba2949ba6a5ab13f2d85b93b"), + ciphertext: &hex!("bc1a886c9e5accc34f0c237f7ed996e940e4b0ec882638e69866ed24d86467f5433aee23448df39565a0ecfff2c40e6857f725"), + tag: &hex!("5ff9c449d0bfa870ebefe78d519a8d12"), + }, + TestVector { + key: &hex!("528b8948b534d5f780ae3f1e23a47a25"), + nonce: &hex!("fec5eaf0a6d6f5c4adec9618"), + plaintext: &hex!("9c5280591311dc212d6ee2ad8b83dedf03b91e244d8a42690c9a5821ab971453c8b4f63e15bb8af96aeb4a3e35515b651bc68d"), + aad: &hex!("d5134d84a96921537a17869c3ed08c55c29e0a67a30943cb248849843794c1c6fefc98659da9b0f505bdefc2e4ebe9523d2a165b63b5e3b2ba9535821d62aaf95b9c7e6ff1f8807a13e79b9fe589c0d9febbabf9372b01ac2051"), + ciphertext: &hex!("bdf0b752160e64b626d5c543954570169e28b033f77b6ef8a37bcbae2a294a9e7060c3235b290f79c69c39a66b0d5ecc81d02a"), + tag: &hex!("f93768c97781ad0486f2f9e8210f2a22"), + }, + TestVector { + key: &hex!("824ca85e2e4b2a6c6e6a65ef8616c57b"), + nonce: &hex!("d2bf92e7dc53676aac4e6d1d"), + plaintext: &hex!("cd4828e5977d7fc5bbf7f6d1870bf6333c204087639a3b494a4037170b73fc6b32c4555d1a02a8837441734d6835a54bf35a44"), + aad: &hex!("465afd08d7260308d8d21025f31570e5dcd6bcbd6520ecb6ff85de58378d5af6eaf7cb2f1242c0c47b759c58dbc6e4b45c8b993514f14b82eda3fcb6a0df2075a0ab76fa0c5b6cb37d1d28f773dac591790887d2d72f03bcc5ae"), + ciphertext: &hex!("4da02474ef189de863d53323ff6737c12efb3d60a890a8d53991de57ffc6cafd44c429a762a2154c5a937120db2161f2cf2ea1"), + tag: &hex!("949d399a7e2567b275c6f842de602605"), + }, + TestVector { + key: &hex!("4f60b753a36b4b1f2e4d8300ddc667a5"), + nonce: &hex!("35fa2551581f8592134bba45"), + plaintext: &hex!("83807c042900611f50fd42557b7cf66315872225143d2cdf8c05ccf688ff21da8f6a2556b0051285b8e7cb8aee05b72816abd5"), + aad: &hex!("9a006b7cea27f3b4a305ffb0c5bec7e3582c6a3be028ebf44bb2496dae1f492f765cc66c82d3a2212abd6142524e0727dab8ae506e6d5b9dd361e3a37df3bec95b14f1174e7f25c656aabb42981b91950755281c5ef8f52e57bf"), + ciphertext: &hex!("cd2291ac182ab6d0f7b6b93e67abc4228ab63a4c1b214caa11698d40d2a8aa10164b48624d39dd967f4c35eebf09acdfe59f45"), + tag: &hex!("b231bb4e63dda90a11700f204dc2b175"), + }, + TestVector { + key: &hex!("07b122a618bb54b8c39d579fe5518a5c"), + nonce: &hex!("26fa33d4c5b37f0c5d07e2d0"), + plaintext: &hex!("06cf2fa1c9057d4974ae9048b4878d75b0b4720ed2d7c340e6d983a7cf08d20013abeef881cc3213fe25b3f6ac1e17fe1c2e11"), + aad: &hex!("20966308f57d3a3e7a4ea149cc1f3edeaef11e8af780a16534472d8df7f706152ee376614426094fd745d77cdca28682d0d2e689d28a50610168d638b23cb4dffa95dd260bc72e0098722cd00126a07fd23ffba1d10a3ce46b85"), + ciphertext: &hex!("61a69d35967c85dd5e0741a9b88152c3b04b1824930cf6c03f1cb44c1258b71fa3f5233d2f4ee256353c0b8f6d470b53d7811a"), + tag: &hex!("e98a7a33748de95e22b520ba2254bce3"), + }, + TestVector { + key: &hex!("288e7efe62b93b990f2398c2460e415d"), + nonce: &hex!("c7ebc0cd756d9501faf71a7d"), + plaintext: &hex!("5fafe873b9d30771f2ef8dad397a8b42af3fc8f7ebbea80d0132e1af14269a463dbd87e3e01a58c2d991eb3badcf156fe8260d"), + aad: &hex!("fcb20124c58b29ef7e39800d1e11c4063774dd2c462dd9e07d140d9f4b5ebe4cba7bb8cc03bf357b22096c9897cdcdf112b7a5f7d1e38d5c74c16924522cbe2443c157cc93146c12bae4da2b2f1df07f334aa1cc99fd7f7e2899"), + ciphertext: &hex!("e5e69100c77d57e05a41b28be74b1c8542fd1f15e73fc589535ea1fac2d263fd92cdaa9908eab6ffd9194586aa3fed5fcd109f"), + tag: &hex!("537516fb827cbf6ce0500c6feff4db34"), + }, + TestVector { + key: &hex!("f66c5b44e7a9dade5765c3f64fb2bab9"), + nonce: &hex!("3482a46c8d4f173e62ce1dc5"), + plaintext: &hex!("80501408e23e2a656720b32b9f41f542fc64e9e8d824af115ece88d551a5f5d5f7fdb67e2339fc263dfdb18a78d423fd868caf"), + aad: &hex!("1e77645efa4419b2c9696b8f989051929ad6a01fe2223ae68325f8176cc467fffbd198e008904b82af6469a3bbb095c4d00cfed143723ed6cf6ba4198c40eabd05c03e0260f8b2f55038e5c382690886280f6989357c50f74fe5"), + ciphertext: &hex!("e778a946529444e2656505e4f5f6519d3ecad5458f8f1a04f31a8af97ca185ff717764bca6e99258a24dc97c322ac1c7f54fba"), + tag: &hex!("c5b2cb532cd05b162b47e94f6d79cb8e"), + }, + TestVector { + key: &hex!("41e8af55426edbe8f0339d0fba400497"), + nonce: &hex!("07eb87d42e90a075d4b34911"), + plaintext: &hex!("adc5504d0a9735d7b73fc53bd0ff60f2c881394fdecfcce3483efe126bf148e48db9c0fd356f82e62d743ec09f8906431eb5e0"), + aad: &hex!("bb2e5c52f2eacc9b7706a2efe4b607858922fd6914a1e22dfbecab2a06464942f769a9c544f046b88a7570e2cf6fd8146c86b2b4decb934f04a81e6d48affbce1f5381ab31a9736b63f5a4e744731726a36357e858c0980d3732"), + ciphertext: &hex!("040d99698b2a5e0169f6f94e61159c135fb19c5917c015aaf8ebb4a451ffd8347428ebfdd80c83841d299318084c779dc91b0c"), + tag: &hex!("a16d6267efaeec13d6bc281316ab8be7"), + }, + TestVector { + key: &hex!("bbf947c0e805ac0641d540b471eb9d26"), + nonce: &hex!("b57daf0004f43821f1ba86de"), + plaintext: &hex!("1211e9224ebb862f2d27de692362324942da12da441176c4742a228d7928d3c1fb3e83c66d68c619a10911fc2ed90226d4ae48"), + aad: &hex!("e18d861dc9bb35a9efa63c7c1deaf53910256809a477f1c3db893b2389f1d137659033a5841b888cd6491bb574b782dec2c840f6350825406387d71340d275e62af3cc070c1389375d81ce98ad37c7afcadcd79f1c520a462e7d"), + ciphertext: &hex!("a6f6aa1750118b402ee1b5f025d29007e3cb162ad9e363efb9ef2d24c850f62db925bbb7e9a83ca6cd6f74251db72622857b29"), + tag: &hex!("a72dcc29d358f794361f84202c9832f9"), + }, + TestVector { + key: &hex!("a56f4de6772b1242f1dff344ec9b512d"), + nonce: &hex!("94d228087e821e301409f305"), + plaintext: &hex!("af537682c419eb7ca3fed65bcc364b01efc2455ff65128dedc88f2224603ef3d7246622269a12b269bbf6ac9d2d3b81abd366f"), + aad: &hex!("6a9c61dbbfaa20a13320a5f1dead28bfbe5dcbe84fe0a3617c348bd702fbe746f439dfcabdad22ac2fa629793f545bc68459f1c0462453b5b31b747c3d29614f0ccd0745fbaa4b204d47d5cc7db35d6bc44bfcecdfae910faa72"), + ciphertext: &hex!("55b60587eb879105ce4a36555d8f799618238bf1f7fd4df622662bd07f450a18375ab7eef02a8036470428c4834f881bf05cd4"), + tag: &hex!("8cbe48d46b5c1296b05b2b6f4b24f7c6"), + }, + TestVector { + key: &hex!("766067fa8f0dc348b77d55ab5317a609"), + nonce: &hex!("8716219953becc2d8918f3aa"), + plaintext: &hex!("ab910f7300ec6bf57d7baf2b4474a26a7d7dfcd6b1044cd0b0b32995029a70627f8d2554429e13d14d78950fb1c79ed1f48c32"), + aad: &hex!("8106f9cacb894dc2f0c93c67cc06cd54af6c6d94193bd0bd9673fc702fc6b995941476f2dc584ff753cdf24517c2153f1e1c6e37fe6d86c1e4fc63bceb25749f9372d62a1932749dd21ef6010b2942bd0464bd64171063a778a0"), + ciphertext: &hex!("8bc822183f9e42f05429e064934d9f84dfe1713d71690e68981f94256fa4a60736607c5864e3b05e3730caed80004a9bb3adb6"), + tag: &hex!("439b0bcdd24a87429a4098fd8a05514c"), + }, + TestVector { + key: &hex!("557ef21e91f108f6ab451980837cf029"), + nonce: &hex!("ac1010f6dcec713cba17cb13"), + plaintext: &hex!("a2ae838532cebfc9ff8fb62242b84df706ad1777a62f54c64d9b1777bdc0819438d34aa4c1906e0fae1e845b32d8fb65763dc6"), + aad: &hex!("5d09aa2a302e3ec2bd71b25d52053463c9c38a3b460f7b980aad6c91d5011570be8c23b4db518701f4c5a157882695ba4ac140f94bda13d9824a8976d436492baaae6c4f8367683199695a1f6bcda2f645b188aa5c286fb91c8a"), + ciphertext: &hex!("94c1941887ff94f34cb96cff2b6a25f660ce9b3ac54963960e70ee49500dae6a20d3307393f37d3a4a35c13b58f7bff0f5de7b"), + tag: &hex!("95e574f70f5efa14b8ee21961972ee3c"), + }, + TestVector { + key: &hex!("55c8bcb0021090e4b2c785c79cb966b8"), + nonce: &hex!("5e9f1313282f73d7ffb92837"), + plaintext: &hex!("2d7c1b689189bbfa2be26ad5c1f296dee4c0f61456ffc94cf8e70aad0f09d0608c4115aa6ed5eba93ed5820b3f3426bbf4d64a"), + aad: &hex!("f7e14a57e3bb6b99866b90573d7bc355baeb7ac347e43d0b65d97ecc2eb9c772401a8e3c7e9e2871c2b79579d44c139e62c33b42a9e0c87686960009d659d5e3874e168c334b6650c6d36168633757a7c20764232ce94a0de1a5"), + ciphertext: &hex!("ba59002df3394c5b80983519dc163eca5c44df80f8c4c4e15d3ff73f13c170c80a59d87a2165a7b450be01031a8e41c505c89f"), + tag: &hex!("28418c564731bddf3d504d8ed32e66ee"), + }, +]; + +tests!(Aes128Gcm, TEST_VECTORS); + +// Test vectors from Wycheproof +aead::new_test!(wycheproof, "wycheproof-128", Aes128Gcm); diff --git a/vendor/aes-gcm/tests/aes256gcm.rs b/vendor/aes-gcm/tests/aes256gcm.rs new file mode 100644 index 00000000..dd701d5f --- /dev/null +++ b/vendor/aes-gcm/tests/aes256gcm.rs @@ -0,0 +1,3022 @@ +//! AES-256-auth tag tests + +#[macro_use] +mod common; + +use self::common::TestVector; +use aes_gcm::aead::{generic_array::GenericArray, Aead, AeadInPlace, KeyInit, Payload}; +use aes_gcm::Aes256Gcm; +use hex_literal::hex; + +/// NIST CAVS vectors +/// +/// +/// +/// From: `gcmEncryptExtIV256.rsp` +const TEST_VECTORS: &[TestVector<[u8; 32]>] = &[ + TestVector { + key: &hex!("b52c505a37d78eda5dd34f20c22540ea1b58963cf8e5bf8ffa85f9f2492505b4"), + nonce: &hex!("516c33929df5a3284ff463d7"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("bdc1ac884d332457a1d2664f168c76f0"), + }, + TestVector { + key: &hex!("5fe0861cdc2690ce69b3658c7f26f8458eec1c9243c5ba0845305d897e96ca0f"), + nonce: &hex!("770ac1a5a3d476d5d96944a1"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("196d691e1047093ca4b3d2ef4baba216"), + }, + TestVector { + key: &hex!("7620b79b17b21b06d97019aa70e1ca105e1c03d2a0cf8b20b5a0ce5c3903e548"), + nonce: &hex!("60f56eb7a4b38d4f03395511"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("f570c38202d94564bab39f75617bc87a"), + }, + TestVector { + key: &hex!("7e2db00321189476d144c5f27e787087302a48b5f7786cd91e93641628c2328b"), + nonce: &hex!("ea9d525bf01de7b2234b606a"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("db9df5f14f6c9f2ae81fd421412ddbbb"), + }, + TestVector { + key: &hex!("a23dfb84b5976b46b1830d93bcf61941cae5e409e4f5551dc684bdcef9876480"), + nonce: &hex!("5aa345908048de10a2bd3d32"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("f28217649230bd7a40a9a4ddabc67c43"), + }, + TestVector { + key: &hex!("dfe928f86430b78add7bb7696023e6153d76977e56103b180253490affb9431c"), + nonce: &hex!("1dd0785af9f58979a10bd62d"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("a55eb09e9edef58d9f671d72207f8b3c"), + }, + TestVector { + key: &hex!("34048db81591ee68224956bd6989e1630fcf068d7ff726ae81e5b29f548cfcfb"), + nonce: &hex!("1621d34cff2a5b250c7b76fc"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("4992ec3d57cccfa58fd8916c59b70b11"), + }, + TestVector { + key: &hex!("a1114f8749c72b8cef62e7503f1ad921d33eeede32b0b5b8e0d6807aa233d0ad"), + nonce: &hex!("a190ed3ff2e238be56f90bd6"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("c8464d95d540fb191156fbbc1608842a"), + }, + TestVector { + key: &hex!("ddbb99dc3102d31102c0e14b238518605766c5b23d9bea52c7c5a771042c85a0"), + nonce: &hex!("95d15ed75c6a109aac1b1d86"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("813d1da3775cacd78e96d86f036cff96"), + }, + TestVector { + key: &hex!("1faa506b8f13a2e6660af78d92915adf333658f748f4e48fa20135a29e9abe5f"), + nonce: &hex!("e50f278d3662c99d750f60d3"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("aec7ece66b7344afd6f6cc7419cf6027"), + }, + TestVector { + key: &hex!("f30b5942faf57d4c13e7a82495aedf1b4e603539b2e1599317cc6e53225a2493"), + nonce: &hex!("336c388e18e6abf92bb739a9"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("ddaf8ef4cb2f8a6d401f3be5ff0baf6a"), + }, + TestVector { + key: &hex!("daf4d9c12c5d29fc3fa936532c96196e56ae842e47063a4b29bfff2a35ed9280"), + nonce: &hex!("5381f21197e093b96cdac4fa"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("7f1832c7f7cd7812a004b79c3d399473"), + }, + TestVector { + key: &hex!("6b524754149c81401d29a4b8a6f4a47833372806b2d4083ff17f2db3bfc17bca"), + nonce: &hex!("ac7d3d618ab690555ec24408"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("db07a885e2bd39da74116d06c316a5c9"), + }, + TestVector { + key: &hex!("cff083303ff40a1f66c4aed1ac7f50628fe7e9311f5d037ebf49f4a4b9f0223f"), + nonce: &hex!("45d46e1baadcfbc8f0e922ff"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("1687c6d459ea481bf88e4b2263227906"), + }, + TestVector { + key: &hex!("3954f60cddbb39d2d8b058adf545d5b82490c8ae9283afa5278689041d415a3a"), + nonce: &hex!("8fb3d98ef24fba03746ac84f"), + plaintext: b"", + aad: b"", + ciphertext: b"", + tag: &hex!("7fb130855dfe7a373313361f33f55237"), + }, + TestVector { + key: &hex!("78dc4e0aaf52d935c3c01eea57428f00ca1fd475f5da86a49c8dd73d68c8e223"), + nonce: &hex!("d79cf22d504cc793c3fb6c8a"), + plaintext: b"", + aad: &hex!("b96baa8c1c75a671bfb2d08d06be5f36"), + ciphertext: b"", + tag: &hex!("3e5d486aa2e30b22e040b85723a06e76"), + }, + TestVector { + key: &hex!("4457ff33683cca6ca493878bdc00373893a9763412eef8cddb54f91318e0da88"), + nonce: &hex!("699d1f29d7b8c55300bb1fd2"), + plaintext: b"", + aad: &hex!("6749daeea367d0e9809e2dc2f309e6e3"), + ciphertext: b"", + tag: &hex!("d60c74d2517fde4a74e0cd4709ed43a9"), + }, + TestVector { + key: &hex!("4d01c96ef9d98d4fb4e9b61be5efa772c9788545b3eac39eb1cacb997a5f0792"), + nonce: &hex!("32124a4d9e576aea2589f238"), + plaintext: b"", + aad: &hex!("d72bad0c38495eda50d55811945ee205"), + ciphertext: b"", + tag: &hex!("6d6397c9e2030f5b8053bfe510f3f2cf"), + }, + TestVector { + key: &hex!("8378193a4ce64180814bd60591d1054a04dbc4da02afde453799cd6888ee0c6c"), + nonce: &hex!("bd8b4e352c7f69878a475435"), + plaintext: b"", + aad: &hex!("1c6b343c4d045cbba562bae3e5ff1b18"), + ciphertext: b"", + tag: &hex!("0833967a6a53ba24e75c0372a6a17bda"), + }, + TestVector { + key: &hex!("22fc82db5b606998ad45099b7978b5b4f9dd4ea6017e57370ac56141caaabd12"), + nonce: &hex!("880d05c5ee599e5f151e302f"), + plaintext: b"", + aad: &hex!("3e3eb5747e390f7bc80e748233484ffc"), + ciphertext: b"", + tag: &hex!("2e122a478e64463286f8b489dcdd09c8"), + }, + TestVector { + key: &hex!("fc00960ddd698d35728c5ac607596b51b3f89741d14c25b8badac91976120d99"), + nonce: &hex!("a424a32a237f0df530f05e30"), + plaintext: b"", + aad: &hex!("cfb7e05e3157f0c90549d5c786506311"), + ciphertext: b"", + tag: &hex!("dcdcb9e4004b852a0da12bdf255b4ddd"), + }, + TestVector { + key: &hex!("69749943092f5605bf971e185c191c618261b2c7cc1693cda1080ca2fd8d5111"), + nonce: &hex!("bd0d62c02ee682069bd1e128"), + plaintext: b"", + aad: &hex!("6967dce878f03b643bf5cdba596a7af3"), + ciphertext: b"", + tag: &hex!("378f796ae543e1b29115cc18acd193f4"), + }, + TestVector { + key: &hex!("fc4875db84819834b1cb43828d2f0ae3473aa380111c2737e82a9ab11fea1f19"), + nonce: &hex!("da6a684d3ff63a2d109decd6"), + plaintext: b"", + aad: &hex!("91b6fa2ab4de44282ffc86c8cde6e7f5"), + ciphertext: b"", + tag: &hex!("504e81d2e7877e4dad6f31cdeb07bdbd"), + }, + TestVector { + key: &hex!("9f9fe7d2a26dcf59d684f1c0945b5ffafe0a4746845ed317d35f3ed76c93044d"), + nonce: &hex!("13b59971cd4dd36b19ac7104"), + plaintext: b"", + aad: &hex!("190a6934f45f89c90067c2f62e04c53b"), + ciphertext: b"", + tag: &hex!("4f636a294bfbf51fc0e131d694d5c222"), + }, + TestVector { + key: &hex!("ab9155d7d81ba6f33193695cf4566a9b6e97a3e409f57159ae6ca49655cca071"), + nonce: &hex!("26a9f8d665d163ddb92d035d"), + plaintext: b"", + aad: &hex!("4a203ac26b951a1f673c6605653ec02d"), + ciphertext: b"", + tag: &hex!("437ea77a3879f010691e288d6269a996"), + }, + TestVector { + key: &hex!("0f1c62dd80b4a6d09ee9d787b1b04327aa361529ffa3407560414ac47b7ef7bc"), + nonce: &hex!("c87613a3b70d2a048f32cb9a"), + plaintext: b"", + aad: &hex!("8f23d404be2d9e888d219f1b40aa29e8"), + ciphertext: b"", + tag: &hex!("36d8a309acbb8716c9c08c7f5de4911e"), + }, + TestVector { + key: &hex!("f3e954a38956df890255f01709e457b33f4bfe7ecb36d0ee50f2500471eebcde"), + nonce: &hex!("9799abd3c52110c704b0f36a"), + plaintext: b"", + aad: &hex!("ddb70173f44157755b6c9b7058f40cb7"), + ciphertext: b"", + tag: &hex!("b323ae3abcb415c7f420876c980f4858"), + }, + TestVector { + key: &hex!("0625316534fbd82fe8fdea50fa573c462022c42f79e8b21360e5a6dce66dde28"), + nonce: &hex!("da64a674907cd6cf248f5fbb"), + plaintext: b"", + aad: &hex!("f24d48e04f5a0d987ba7c745b73b0364"), + ciphertext: b"", + tag: &hex!("df360b810f27e794673a8bb2dc0d68b0"), + }, + TestVector { + key: &hex!("28f045ac7c4fe5d4b01a9dcd5f1ad3efff1c4f170fc8ab8758d97292868d5828"), + nonce: &hex!("5d85de95b0bdc44514143919"), + plaintext: b"", + aad: &hex!("601d2158f17ab3c7b4dcb6950fbdcdde"), + ciphertext: b"", + tag: &hex!("42c3f527418cf2c3f5d5010ccba8f271"), + }, + TestVector { + key: &hex!("19310eed5f5f44eb47075c105eb31e36bbfd1310f741b9baa66a81138d357242"), + nonce: &hex!("a1247120138fa4f0e96c992c"), + plaintext: b"", + aad: &hex!("29d746414333e0f72b4c3f44ec6bfe42"), + ciphertext: b"", + tag: &hex!("d5997e2f956df3fa2c2388e20f30c480"), + }, + TestVector { + key: &hex!("886cff5f3e6b8d0e1ad0a38fcdb26de97e8acbe79f6bed66959a598fa5047d65"), + nonce: &hex!("3a8efa1cd74bbab5448f9945"), + plaintext: b"", + aad: &hex!("519fee519d25c7a304d6c6aa1897ee1eb8c59655"), + ciphertext: b"", + tag: &hex!("f6d47505ec96c98a42dc3ae719877b87"), + }, + TestVector { + key: &hex!("6937a57d35fe6dc3fc420b123bccdce874bd4c18f2e7c01ce2faf33d3944fd9d"), + nonce: &hex!("a87247797b758467b96310f3"), + plaintext: b"", + aad: &hex!("ead961939a33dd578f8e93db8b28a1c85362905f"), + ciphertext: b"", + tag: &hex!("599de3ecf22cb867f03f7f6d9fd7428a"), + }, + TestVector { + key: &hex!("e65a331776c9dcdf5eba6c59e05ec079d97473bcdce84daf836be323456263a0"), + nonce: &hex!("ca731f768da01d02eb8e727e"), + plaintext: b"", + aad: &hex!("d7274586517bf1d8da866f4a47ad0bcf2948a862"), + ciphertext: b"", + tag: &hex!("a8abe7a8085f25130a7206d37a8aaf6d"), + }, + TestVector { + key: &hex!("77bb1b6ef898683c981b2fc899319ffbb6000edca22566b634db3a3c804059e5"), + nonce: &hex!("354a19283769b3b991b05a4c"), + plaintext: b"", + aad: &hex!("b5566251a8a8bec212dc08113229ff8590168800"), + ciphertext: b"", + tag: &hex!("e5c2dccf8fc7f296cac95d7071cb8d7d"), + }, + TestVector { + key: &hex!("2a43308d520a59ed51e47a3a915e1dbf20a91f0886506e481ad3de65d50975b4"), + nonce: &hex!("bcbf99733d8ec90cb23e6ce6"), + plaintext: b"", + aad: &hex!("eb88288729289d26fe0e757a99ad8eec96106053"), + ciphertext: b"", + tag: &hex!("01b0196933aa49123eab4e1571250383"), + }, + TestVector { + key: &hex!("2379b35f85102db4e7aecc52b705bc695d4768d412e2d7bebe999236783972ff"), + nonce: &hex!("918998c4801037b1cd102faa"), + plaintext: b"", + aad: &hex!("b3722309e0f066225e8d1659084ebb07a93b435d"), + ciphertext: b"", + tag: &hex!("dfb18aee99d1f67f5748d4b4843cb649"), + }, + TestVector { + key: &hex!("98b3cb7537167e6d14a2a8b2310fe94b715c729fdf85216568150b556d0797ba"), + nonce: &hex!("bca5e2e5a6b30f18d263c6b2"), + plaintext: b"", + aad: &hex!("260d3d72db70d677a4e3e1f3e11431217a2e4713"), + ciphertext: b"", + tag: &hex!("d6b7560f8ac2f0a90bad42a6a07204bc"), + }, + TestVector { + key: &hex!("30341ae0f199b10a15175d00913d5029526ab7f761c0b936a7dd5f1b1583429d"), + nonce: &hex!("dbe109a8ce5f7b241e99f7af"), + plaintext: b"", + aad: &hex!("fe4bdee5ca9c4806fa024715fbf66ab845285fa7"), + ciphertext: b"", + tag: &hex!("ae91daed658e26c0d126575147af9899"), + }, + TestVector { + key: &hex!("8232b6a1d2e367e9ce1ea8d42fcfc83a4bc8bdec465c6ba326e353ad9255f207"), + nonce: &hex!("cd2fb5ff9cf0f39868ad8685"), + plaintext: b"", + aad: &hex!("02418b3dde54924a9628de06004c0882ae4ec3bb"), + ciphertext: b"", + tag: &hex!("d5308f63708675ced19b2710afd2db49"), + }, + TestVector { + key: &hex!("f9a132a50a508145ffd8294e68944ea436ce0f9a97e181f5e0d6c5d272311fc1"), + nonce: &hex!("892991b54e94b9d57442ccaf"), + plaintext: b"", + aad: &hex!("4e0fbd3799da250fa27911b7e68d7623bfe60a53"), + ciphertext: b"", + tag: &hex!("89881d5f786e6d53e0d19c3b4e6887d8"), + }, + TestVector { + key: &hex!("0e3746e5064633ea9311b2b8427c536af92717de20eeb6260db1333c3d8a8114"), + nonce: &hex!("f84c3a1c94533f7f25cec0ac"), + plaintext: b"", + aad: &hex!("8c0d41e6135338c8d3e63e2a5fa0a9667ec9a580"), + ciphertext: b"", + tag: &hex!("479ccfe9241de2c474f2edebbb385c09"), + }, + TestVector { + key: &hex!("b997e9b0746abaaed6e64b63bdf64882526ad92e24a2f5649df055c9ec0f1daa"), + nonce: &hex!("f141d8d71b033755022f0a7d"), + plaintext: b"", + aad: &hex!("681d6583f527b1a92f66caae9b1d4d028e2e631e"), + ciphertext: b"", + tag: &hex!("b30442a6395ec13246c48b21ffc65509"), + }, + TestVector { + key: &hex!("87660ec1700d4e9f88a323a49f0b871e6aaf434a2d8448d04d4a22f6561028e0"), + nonce: &hex!("2a07b42593cd24f0a6fe406c"), + plaintext: b"", + aad: &hex!("1dd239b57185b7e457ced73ebba043057f049edd"), + ciphertext: b"", + tag: &hex!("df7a501049b37a534098cb45cb9c21b7"), + }, + TestVector { + key: &hex!("ea4792e1f1717b77a00de4d109e627549b165c82af35f33ca7e1a6b8ed62f14f"), + nonce: &hex!("7453cc8b46fe4b93bcc48381"), + plaintext: b"", + aad: &hex!("46d98970a636e7cd7b76fc362ae88298436f834f"), + ciphertext: b"", + tag: &hex!("518dbacd36be6fba5c12871678a55516"), + }, + TestVector { + key: &hex!("34892cdd1d48ca166f7ba73182cb97336c2c754ac160a3e37183d6fb5078cec3"), + nonce: &hex!("ed3198c5861b78c71a6a4eec"), + plaintext: b"", + aad: &hex!("a6fa6d0dd1e0b95b4609951bbbe714de0ae0ccfa"), + ciphertext: b"", + tag: &hex!("c6387795096b348ecf1d1f6caaa3c813"), + }, + TestVector { + key: &hex!("f4069bb739d07d0cafdcbc609ca01597f985c43db63bbaaa0debbb04d384e49c"), + nonce: &hex!("d25ff30fdc3d464fe173e805"), + plaintext: b"", + aad: &hex!("3e1449c4837f0892f9d55127c75c4b25d69be334baf5f19394d2d8bb460cbf2120e14736d0f634aa792feca20e455f11"), + ciphertext: b"", + tag: &hex!("805ec2931c2181e5bfb74fa0a975f0cf"), + }, + TestVector { + key: &hex!("62189dcc4beb97462d6c0927d8a270d39a1b07d72d0ad28840badd4f68cf9c8b"), + nonce: &hex!("859fda5247c888823a4b8032"), + plaintext: b"", + aad: &hex!("b28d1621ee110f4c9d709fad764bba2dd6d291bc003748faac6d901937120d41c1b7ce67633763e99e05c71363fceca8"), + ciphertext: b"", + tag: &hex!("27330907d0002880bbb4c1a1d23c0be2"), + }, + TestVector { + key: &hex!("59012d85a1b90aeb0359e6384c9991e7be219319f5b891c92c384ade2f371816"), + nonce: &hex!("3c9cde00c23912cff9689c7c"), + plaintext: b"", + aad: &hex!("e5daf473a470860b55210a483c0d1a978d8add843c2c097f73a3cda49ac4a614c8e887d94e6692309d2ed97ebe1eaf5d"), + ciphertext: b"", + tag: &hex!("048239e4e5c2c8b33890a7c950cda852"), + }, + TestVector { + key: &hex!("4be09b408ad68b890f94be5efa7fe9c917362712a3480c57cd3844935f35acb7"), + nonce: &hex!("8f350bd3b8eea173fc7370bc"), + plaintext: b"", + aad: &hex!("2819d65aec942198ca97d4435efd9dd4d4393b96cf5ba44f09bce4ba135fc8636e8275dcb515414b8befd32f91fc4822"), + ciphertext: b"", + tag: &hex!("a133cb7a7d0471dbac61fb41589a2efe"), + }, + TestVector { + key: &hex!("13cb965a4d9d1a36efad9f6ca1ba76386a5bb160d80b0917277102357ac7afc8"), + nonce: &hex!("f313adec42a66d13c3958180"), + plaintext: b"", + aad: &hex!("717b48358898e5ccfea4289049adcc1bb0db3b3ebd1767ac24fb2b7d37dc80ea2316c17f14fb51b5e18cd5bb09afe414"), + ciphertext: b"", + tag: &hex!("81b4ef7a84dc4a0b1fddbefe37f53852"), + }, + TestVector { + key: &hex!("d27f1bebbbdef0edca393a6261b0338abbc491262eab0737f55246458f6668cc"), + nonce: &hex!("fc062f857886e278f3a567d2"), + plaintext: b"", + aad: &hex!("2bae92dea64aa99189de8ea4c046745306002e02cfb46a41444ce8bfcc329bd4205963d9ab5357b026a4a34b1a861771"), + ciphertext: b"", + tag: &hex!("5c5a6c4613f1e522596330d45f243fdd"), + }, + TestVector { + key: &hex!("7b4d19cd3569f74c7b5df61ab78379ee6bfa15105d21b10bf6096699539006d0"), + nonce: &hex!("fbed5695c4a739eded97b1e3"), + plaintext: b"", + aad: &hex!("c6f2e5d663bfaf668d014550ef2e66bf89978799a785f1f2c79a2cb3eb3f2fd4076207d5f7e1c284b4af5cffc4e46198"), + ciphertext: b"", + tag: &hex!("7101b434fb90c7f95b9b7a0deeeb5c81"), + }, + TestVector { + key: &hex!("d3431488d8f048590bd76ec66e71421ef09f655d7cf8043bf32f75b4b2e7efcc"), + nonce: &hex!("cc766e98b40a81519fa46392"), + plaintext: b"", + aad: &hex!("93320179fdb40cbc1ccf00b872a3b4a5f6c70b56e43a84fcac5eb454a0a19a747d452042611bf3bbaafd925e806ffe8e"), + ciphertext: b"", + tag: &hex!("3afcc336ce8b7191eab04ad679163c2a"), + }, + TestVector { + key: &hex!("a440948c0378561c3956813c031f81573208c7ffa815114ef2eee1eb642e74c6"), + nonce: &hex!("c1f4ffe54b8680832eed8819"), + plaintext: b"", + aad: &hex!("253438f132b18e8483074561898c5652b43a82cc941e8b4ae37e792a8ed6ec5ce2bcec9f1ffcf4216e46696307bb774a"), + ciphertext: b"", + tag: &hex!("129445f0a3c979a112a3afb10a24e245"), + }, + TestVector { + key: &hex!("798706b651033d9e9bf2ce064fb12be7df7308cf45df44776588cd391c49ff85"), + nonce: &hex!("5a43368a39e7ffb775edfaf4"), + plaintext: b"", + aad: &hex!("926b74fe6381ebd35757e42e8e557601f2287bfc133a13fd86d61c01aa84f39713bf99a8dc07b812f0274c9d3280a138"), + ciphertext: b"", + tag: &hex!("89fe481a3d95c03a0a9d4ee3e3f0ed4a"), + }, + TestVector { + key: &hex!("c3aa2a39a9fef4a466618d1288bb62f8da7b1cb760ccc8f1be3e99e076f08eff"), + nonce: &hex!("9965ba5e23d9453d7267ca5b"), + plaintext: b"", + aad: &hex!("93efb6a2affc304cb25dfd49aa3e3ccdb25ceac3d3cea90dd99e38976978217ad5f2b990d10b91725c7fd2035ecc6a30"), + ciphertext: b"", + tag: &hex!("00a94c18a4572dcf4f9e2226a03d4c07"), + }, + TestVector { + key: &hex!("14e06858008f7e77186a2b3a7928a0c7fcee22136bc36f53553f20fa5c37edcd"), + nonce: &hex!("32ebe0dc9ada849b5eda7b48"), + plaintext: b"", + aad: &hex!("6c0152abfa485b8cd67c154a5f0411f22121379774d745f40ee577b028fd0e188297581561ae972223d75a24b488aed7"), + ciphertext: b"", + tag: &hex!("2625b0ba6ee02b58bc529e43e2eb471b"), + }, + TestVector { + key: &hex!("fbb56b11c51a093ce169a6990399c4d741f62b3cc61f9e8a609a1b6ae8e7e965"), + nonce: &hex!("9c5a953247e91aceceb9defb"), + plaintext: b"", + aad: &hex!("46cb5c4f617916a9b1b2e03272cb0590ce716498533047d73c81e4cbe9278a3686116f5632753ea2df52efb3551aea2d"), + ciphertext: b"", + tag: &hex!("4f3b82e6be4f08756071f2c46c31fedf"), + }, + TestVector { + key: &hex!("b303bf02f6a8dbb5bc4baccab0800db5ee06de648e2fae299b95f135c9b107cc"), + nonce: &hex!("906495b67ef4ce00b44422fa"), + plaintext: b"", + aad: &hex!("872c6c370926535c3fa1baec031e31e7c6c82808c8a060742dbef114961c314f1986b2131a9d91f30f53067ec012c6b7"), + ciphertext: b"", + tag: &hex!("64dde37169082d181a69107f60c5c6bb"), + }, + TestVector { + key: &hex!("29f5f8075903063cb6d7050669b1f74e08a3f79ef566292dfdef1c06a408e1ab"), + nonce: &hex!("35f25c48b4b5355e78b9fb3a"), + plaintext: b"", + aad: &hex!("107e2e23159fc5c0748ca7a077e5cc053fa5c682ff5269d350ee817f8b5de4d3972041d107b1e2f2e54ca93b72cd0408"), + ciphertext: b"", + tag: &hex!("fee5a9baebb5be0165deaa867e967a9e"), + }, + TestVector { + key: &hex!("03ccb7dbc7b8425465c2c3fc39ed0593929ffd02a45ff583bd89b79c6f646fe9"), + nonce: &hex!("fd119985533bd5520b301d12"), + plaintext: b"", + aad: &hex!("98e68c10bf4b5ae62d434928fc6405147c6301417303ef3a703dcfd2c0c339a4d0a89bd29fe61fecf1066ab06d7a5c31a48ffbfed22f749b17e9bd0dc1c6f8fbd6fd4587184db964d5456132106d782338c3f117ec05229b0899"), + ciphertext: b"", + tag: &hex!("cf54e7141349b66f248154427810c87a"), + }, + TestVector { + key: &hex!("57e112cd45f2c57ddb819ea651c206763163ef016ceead5c4eae40f2bbe0e4b4"), + nonce: &hex!("188022c2125d2b1fcf9e4769"), + plaintext: b"", + aad: &hex!("09c8f445ce5b71465695f838c4bb2b00624a1c9185a3d552546d9d2ee4870007aaf3007008f8ae9affb7588b88d09a90e58b457f88f1e3752e3fb949ce378670b67a95f8cf7f5c7ceb650efd735dbc652cae06e546a5dbd861bd"), + ciphertext: b"", + tag: &hex!("9efcddfa0be21582a05749f4050d29fe"), + }, + TestVector { + key: &hex!("a4ddf3cab7453aaefad616fd65d63d13005e9459c17d3173cd6ed7f2a86c921f"), + nonce: &hex!("06177b24c58f3be4f3dd4920"), + plaintext: b"", + aad: &hex!("f95b046d80485e411c56b834209d3abd5a8a9ddf72b1b916679adfdde893044315a5f4967fd0405ec297aa332f676ff0fa5bd795eb609b2e4f088db1cdf37ccff0735a5e53c4c12173a0026aea42388a7d7153a8830b8a901cf9"), + ciphertext: b"", + tag: &hex!("9d1bd8ecb3276906138d0b03fcb8c1bb"), + }, + TestVector { + key: &hex!("24a92b24e85903cd4aaabfe07c310df5a4f8f459e03a63cbd1b47855b09c0be8"), + nonce: &hex!("22e756dc898d4cf122080612"), + plaintext: b"", + aad: &hex!("2e01b2536dbe376be144296f5c38fb099e008f962b9f0e896334b6408393bff1020a0e442477abfdb1727213b6ccc577f5e16cb057c8945a07e307264b65979aed96b5995f40250ffbaaa1a1f0eccf394015f6290f5e64dfe5ca"), + ciphertext: b"", + tag: &hex!("0d7f1aed4708a03b0c80b2a18785c96d"), + }, + TestVector { + key: &hex!("15276fc64438578e0ec53366b90a0e23d93910fec10dc3003d9b3f3fa72db702"), + nonce: &hex!("c5e931946d5caebc227656d2"), + plaintext: b"", + aad: &hex!("3f967c83ba02e77c14e9d41185eb87f172250e93edb0f82b6742c124298ab69418358eddefa39fedc3cade9d80f036d864a59ead37c87727c56c701a8cd9634469ff31c704f5ee39354157e6558467b92824da36b1c071bedfe9"), + ciphertext: b"", + tag: &hex!("a0ffa19adcf31d061cd0dd46d24015ef"), + }, + TestVector { + key: &hex!("ec09804a048bb854c71618b5a3a1c590910fc8a68455139b719486d2280ea59a"), + nonce: &hex!("d0b1247e7121a9276ac18ca3"), + plaintext: b"", + aad: &hex!("66b1d39d414596308e866b04476e053b71acd1cd07ce80939577ebbeace0430f7e4c0c185fe1d97ac7569950c83db40bbed0f1d173e1aa0dc28b4773705032d97551f7fcef7f55e4b69f88df650032dfc5232c156641104b5397"), + ciphertext: b"", + tag: &hex!("8440e6d864ab778f9be478f203162d86"), + }, + TestVector { + key: &hex!("4adf86bfa547725e4b80365a5a327c107040facfff007dc35102066bd6a995c4"), + nonce: &hex!("b1018cc331911255a55a0795"), + plaintext: b"", + aad: &hex!("053ca4428c990b4456d3c1895d5d52deff675896de9faa53d8cf241255f4a31dc3399f15d83be380256616e5af043abfb37552655adf4f2e68dda24bc3736951134f359d9c0e288bb798b6c3ea46239231a3cb280066db9862e7"), + ciphertext: b"", + tag: &hex!("c7424f38084930bfc5edc1fcf1e7608d"), + }, + TestVector { + key: &hex!("3c92e0d1e39a3c766573c4646c768c402ccff48a56682a93433512abf0456e00"), + nonce: &hex!("d57f319e590191841d2b98bd"), + plaintext: b"", + aad: &hex!("840d9394aa240e52ba152151c12acd1cd44881e8549dc832b71a45da7efcc74fb7e844d9fec25e5d497b8fb8f47f328c8d99045a19e366e6ce5e19dc26f67a81a94fa6c97c314d886e7b56eff144c09f6fa519db6308bc73422e"), + ciphertext: b"", + tag: &hex!("cb4ef72dbda4914d7434f9686f823e2f"), + }, + TestVector { + key: &hex!("b66ba39733888a9e0a2e30452844161dc33cb383c02ce16c4efad5452509b5b5"), + nonce: &hex!("937cb665e37059b2e40359f2"), + plaintext: b"", + aad: &hex!("dbcd9694a8834860034e8ede3a5bd419fcf91c005ad99f488aa623f581622093f9d41e6a68e20fd202f302bcfc4417ca89090bfcd4d5224e8ff4eb5bbae4ecb27baa239f59c2f99cd47c0a269c497906b41a8f320a3dd2dc2de2"), + ciphertext: b"", + tag: &hex!("bdc8249302d9d666cf7168317c118743"), + }, + TestVector { + key: &hex!("2f9fcd1043455695638c991a1b1d35ad57c18ef0727322747b7991abc3d787f3"), + nonce: &hex!("d06cf548f62869f4bed7a318"), + plaintext: b"", + aad: &hex!("432023c12cf1f614e1005112a17dbe6c5d54022a95cf6335a5bc55004c75f09a5699739ecf928e1c78d03dad5096a17a084afe1cc22041bbdfb5985bd08b0dcc59d2b08cd86b7aad597c4cd7b4ba6d6a7370b83995a6511a1f9e"), + ciphertext: b"", + tag: &hex!("322eb84fb6884f10cfb766c2e3ec779e"), + }, + TestVector { + key: &hex!("21c5839a63e1230c06b086341c96ab74585e69bced94332caeb1fa77d510c24f"), + nonce: &hex!("5ab6e5ed6ee733be7250858c"), + plaintext: b"", + aad: &hex!("c92f08e30f67d42516133c48e97b65cc9e124365e110aba5e7b2cbe83debcc99edf4eb0007af052bda22d85900271b1897af4fd9ace6a2d09d984ac3de79d05de0b105a81b12542b2c48e27d409fd6992dd062d6055d6fc66842"), + ciphertext: b"", + tag: &hex!("53b0e450309d146459f2a1e46c9d9e23"), + }, + TestVector { + key: &hex!("25a144f0fdba184125d81a87e7ed82fad33c701a094a67a81fe4692dc69afa31"), + nonce: &hex!("8bf575c5c2b45b4efc6746e4"), + plaintext: b"", + aad: &hex!("2a367cb0d3b7c5b8320b3cf95e82b6ba0bba1d09a2055885dedd9ef5641623682212103238b8f775cce42ddfd4f66382f2c3a5e8d6dff9163ced83580a75705574026b55db90f75f8abb3014c9a707021dedc075da38bebbf0a0"), + ciphertext: b"", + tag: &hex!("0e2ce9cac8dfcedb0572ec6cab621efd"), + }, + TestVector { + key: &hex!("42bc841b3b03a807cd366a35ecec8a6aebef7c4cba0ec8cb8da0da41df8ccef1"), + nonce: &hex!("1bd46f85df5f4b3a126ee315"), + plaintext: b"", + aad: &hex!("ede3dcddbdc7d8e5d034c01661332ec349cb4e7a9fbaaf7abe2c647587db86cd427ce66908e070bc49ef838747e06b45ac486dfbea6f8698b4625e21e69db8327ec05cfd74accbe67ab644948cdb554af179a1e264e08fe16641"), + ciphertext: b"", + tag: &hex!("633ab6aaf5b32b53a794f6be6262fc5f"), + }, + TestVector { + key: &hex!("c25b8500be73210596fc4a9fb4d84d1a3379a91e3f0a6cc4177d996046627679"), + nonce: &hex!("b56c48c0c4cd318b20437002"), + plaintext: b"", + aad: &hex!("bcd14dd043fdc8c327957e1c1428698543ec8602521a7c74788d296d37d4828f10f90656883d2531c702ebda2dc0a68dab00154577454455fad986ff8e0973098dbf370ff703ed98222b945726ed9be7909210ddbc672e99fdd9"), + ciphertext: b"", + tag: &hex!("8171d4ff60fe7ef6de0288326aa73223"), + }, + TestVector { + key: &hex!("dd95259bc8eefa3e493cb1a6ba1d8ee2b341d5230d50363094a2cc3433b3d9b9"), + nonce: &hex!("a1a6ced084f4f13990750a9e"), + plaintext: b"", + aad: &hex!("d46db90e13684b26149cb3b7f776e228a0538fa1892c418aaad07aa08d3076f4a52bee8f130ff560db2b8d1009e9260fa6233fc22733e050c9e4f7cc699062765e261dffff1159e9060b26c8065dfab04055b58c82c340d987c9"), + ciphertext: b"", + tag: &hex!("9e120b01899fe2cb3e3a0b0c05045940"), + }, + TestVector { + key: &hex!("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22"), + nonce: &hex!("0d18e06c7c725ac9e362e1ce"), + plaintext: &hex!("2db5168e932556f8089a0622981d017d"), + aad: b"", + ciphertext: &hex!("fa4362189661d163fcd6a56d8bf0405a"), + tag: &hex!("d636ac1bbedd5cc3ee727dc2ab4a9489"), + }, + TestVector { + key: &hex!("460fc864972261c2560e1eb88761ff1c992b982497bd2ac36c04071cbb8e5d99"), + nonce: &hex!("8a4a16b9e210eb68bcb6f58d"), + plaintext: &hex!("99e4e926ffe927f691893fb79a96b067"), + aad: b"", + ciphertext: &hex!("133fc15751621b5f325c7ff71ce08324"), + tag: &hex!("ec4e87e0cf74a13618d0b68636ba9fa7"), + }, + TestVector { + key: &hex!("f78a2ba3c5bd164de134a030ca09e99463ea7e967b92c4b0a0870796480297e5"), + nonce: &hex!("2bb92fcb726c278a2fa35a88"), + plaintext: &hex!("f562509ed139a6bbe7ab545ac616250c"), + aad: b"", + ciphertext: &hex!("e2f787996e37d3b47294bf7ebba5ee25"), + tag: &hex!("00f613eee9bdad6c9ee7765db1cb45c0"), + }, + TestVector { + key: &hex!("48e6af212da1386500454c94a201640c2151b28079240e40d72d2a5fd7d54234"), + nonce: &hex!("ef0ff062220eb817dc2ece94"), + plaintext: &hex!("c7afeecec1408ad155b177c2dc7138b0"), + aad: b"", + ciphertext: &hex!("9432a620e6a22307e06a321d66846fd4"), + tag: &hex!("e3ea499192f2cd8d3ab3edfc55897415"), + }, + TestVector { + key: &hex!("79cd8d750fc8ea62a2714edcd9b32867c7c4da906c56e23a644552f5b812e75a"), + nonce: &hex!("9bbfdb81015d2b57dead2de5"), + plaintext: &hex!("f980ad8c55ebd31ee6f98f44e92bff55"), + aad: b"", + ciphertext: &hex!("41a34d1e759c859e91b8cf5d3ded1970"), + tag: &hex!("68cd98406d5b322571e750c30aa49834"), + }, + TestVector { + key: &hex!("130ae450c18efb851057aaa79575a0a090194be8b2c95469a0e8e380a8f48f42"), + nonce: &hex!("b269115396f81b39e0c38f47"), + plaintext: &hex!("036cf36280dee8355c82abc4c1fdb778"), + aad: b"", + ciphertext: &hex!("09f7568fd8181652e556f0dda5a49ed5"), + tag: &hex!("d10b61947cae275b7034f5259ba6fc28"), + }, + TestVector { + key: &hex!("9c7121289aefc67090cabed53ad11658be72a5372761b9d735e81d2bfc0e3267"), + nonce: &hex!("ade1702d2051b8dd203b5419"), + plaintext: &hex!("b95bcaa2b31403d76859a4c301c50b56"), + aad: b"", + ciphertext: &hex!("628285e6489090dde1b9a60674785003"), + tag: &hex!("9f516af3f3b93d610edbc5ba6e2d115f"), + }, + TestVector { + key: &hex!("0400b42897011fc20fd2280a52ef905d6ebf1b055b48c97067bd786d678ec4ea"), + nonce: &hex!("0abfb0a41496b453358409d9"), + plaintext: &hex!("20c8230191e35f4e9b269d59cf5521f6"), + aad: b"", + ciphertext: &hex!("dd8c38087daffbbb3ebb57ebf5ee5f78"), + tag: &hex!("bfb07aa5049ee350ec6fb1397f37087b"), + }, + TestVector { + key: &hex!("56690798978c154ff250ba78e463765f2f0ce69709a4551bd8cb3addeda087b6"), + nonce: &hex!("cf37c286c18ad4ea3d0ba6a0"), + plaintext: &hex!("2d328124a8d58d56d0775eed93de1a88"), + aad: b"", + ciphertext: &hex!("3b0a0267f6ecde3a78b30903ebd4ca6e"), + tag: &hex!("1fd2006409fc636379f3d4067eca0988"), + }, + TestVector { + key: &hex!("8a02a33bdf87e7845d7a8ae3c8727e704f4fd08c1f2083282d8cb3a5d3cedee9"), + nonce: &hex!("599f5896851c968ed808323b"), + plaintext: &hex!("4ade8b32d56723fb8f65ce40825e27c9"), + aad: b"", + ciphertext: &hex!("cb9133796b9075657840421a46022b63"), + tag: &hex!("a79e453c6fad8a5a4c2a8e87821c7f88"), + }, + TestVector { + key: &hex!("23aaa78a5915b14f00cf285f38ee275a2db97cb4ab14d1aac8b9a73ff1e66467"), + nonce: &hex!("4a675ec9be1aab9632dd9f59"), + plaintext: &hex!("56659c06a00a2e8ed1ac60572eee3ef7"), + aad: b"", + ciphertext: &hex!("e6c01723bfbfa398d9c9aac8c683bb12"), + tag: &hex!("4a2f78a9975d4a1b5f503a4a2cb71553"), + }, + TestVector { + key: &hex!("fe647f72e95c469027f4d7778429a2e8e90d090268d4fa7df44f65c0af84190a"), + nonce: &hex!("4f40ae2a83a9b480e4686c90"), + plaintext: &hex!("31fd6cce3f0d2b0d18e0af01c4b5609e"), + aad: b"", + ciphertext: &hex!("54c769fd542f0d3022f1335a7c410b61"), + tag: &hex!("106cb7cbcd967da6cad646039c753474"), + }, + TestVector { + key: &hex!("fce205515f0551b1797128a2132d8e002ea5ab1beb99c5e7e8329398cf478e10"), + nonce: &hex!("20209a0d4a3b9bfddeef39a0"), + plaintext: &hex!("7d663e31a2f6ffef17e536684dae2e87"), + aad: b"", + ciphertext: &hex!("6529712030fb659dc11ab719f6a4c402"), + tag: &hex!("58699464d062aba505508c576c4e07dd"), + }, + TestVector { + key: &hex!("cd33003ff18f6f3369dd9a35381261ba660ce0a769864475152e677066540337"), + nonce: &hex!("20bffe9064ce76d275204138"), + plaintext: &hex!("acaf53d4dd2fe12cd44450b0d9adcc92"), + aad: b"", + ciphertext: &hex!("a669fda0444b180165f90815dc992b33"), + tag: &hex!("6e31f5a56c4790cedcc2368c51d0639b"), + }, + TestVector { + key: &hex!("381873b5f9579d8241f0c61f0d9e327bb9f678691714aaa48ea7d92678d43fe7"), + nonce: &hex!("3fc8bec23603158e012d65e5"), + plaintext: &hex!("7b622e9b408fe91f6fa800ecef838d36"), + aad: b"", + ciphertext: &hex!("8ca4de5b4e2ab22431a009f3ddd01bae"), + tag: &hex!("b3a7f80e3edf322622731550164cd747"), + }, + TestVector { + key: &hex!("92e11dcdaa866f5ce790fd24501f92509aacf4cb8b1339d50c9c1240935dd08b"), + nonce: &hex!("ac93a1a6145299bde902f21a"), + plaintext: &hex!("2d71bcfa914e4ac045b2aa60955fad24"), + aad: &hex!("1e0889016f67601c8ebea4943bc23ad6"), + ciphertext: &hex!("8995ae2e6df3dbf96fac7b7137bae67f"), + tag: &hex!("eca5aa77d51d4a0a14d9c51e1da474ab"), + }, + TestVector { + key: &hex!("7da3bccaffb3464178ca7c722379836db50ce0bfb47640b9572163865332e486"), + nonce: &hex!("c04fd2e701c3dc62b68738b3"), + plaintext: &hex!("fd671cab1ee21f0df6bb610bf94f0e69"), + aad: &hex!("fec0311013202e4ffdc4204926ae0ddf"), + ciphertext: &hex!("6be61b17b7f7d494a7cdf270562f37ba"), + tag: &hex!("5e702a38323fe1160b780d17adad3e96"), + }, + TestVector { + key: &hex!("a359b9584beec189527f8842dda6b6d4c6a5db2f889635715fa3bcd7967c0a71"), + nonce: &hex!("8616c4cde11b34a944caba32"), + plaintext: &hex!("33a46b7539d64c6e1bdb91ba221e3007"), + aad: &hex!("e1796fca20cb3d3ab0ade69b2a18891e"), + ciphertext: &hex!("b0d316e95f3f3390ba10d0274965c62b"), + tag: &hex!("aeaedcf8a012cc32ef25a62790e9334c"), + }, + TestVector { + key: &hex!("8c83238e7b3b58278200b54940d779d0a0750673aab0bf2f5808dd15dc1a8c49"), + nonce: &hex!("70f8f4ebe408f61a35077956"), + plaintext: &hex!("6e57f8572dd5b2247410f0d4c7424186"), + aad: &hex!("e1cbf83924f1b8d1014b97db56c25a15"), + ciphertext: &hex!("4a11acb9611251df01f79f16f8201ffb"), + tag: &hex!("9732be4ad0569586753d90fabb06f62c"), + }, + TestVector { + key: &hex!("fe21919bb320af8744c9e862b5b7cf8b81ad3ad1fb0e7d7d710a688d3eed154b"), + nonce: &hex!("38bc3917aa1925f40850c082"), + plaintext: &hex!("aea53b1ea79a71c3a4b83c92a0c979f1"), + aad: &hex!("f24102fa7e6b819bb3ff47f90844db9c"), + ciphertext: &hex!("2fb8b697bf8f7a2eea25fe702a3ae0a9"), + tag: &hex!("5be77e827737ad7c4f79e0e343fe010d"), + }, + TestVector { + key: &hex!("499e8a3f39ac4abc62dd4e1a6133042e74785972b6b501bfaffefc8bb29fd312"), + nonce: &hex!("5c728dbbef9dcc0ff483e891"), + plaintext: &hex!("b44014c7fc6b3f15d126a881fbe2bd2b"), + aad: &hex!("82300dab592f840ae991efa3623a6203"), + ciphertext: &hex!("578fe5e1aef7619f392c027c838a239e"), + tag: &hex!("49fdc724f05eb56ea9e3fd14b61ad567"), + }, + TestVector { + key: &hex!("2775d3e7a8fc665bb9a59edc22eb136add194824ed8f2adb449177404c739716"), + nonce: &hex!("73f16c054e166696df679a2e"), + plaintext: &hex!("c9f3bce40310b6c0a3fd62742e4f3617"), + aad: &hex!("23199a1c9b7244913952ca4f7e7444f4"), + ciphertext: &hex!("72c85c10756266d00a9a4340b2cb3137"), + tag: &hex!("5881e4565b42394e62d5daf0d1ebc593"), + }, + TestVector { + key: &hex!("425a341c67e6d873870f54e2cc5a2984c734e81729c0dbaaeee050309f1ce674"), + nonce: &hex!("0c09b7b4e9e097317b791433"), + plaintext: &hex!("76dda644b3faca509b37def0319f30cc"), + aad: &hex!("4300a721547846761e4bf8df2b6ec1d6"), + ciphertext: &hex!("1dd80daa0fc9e47e43897c64a6663f5e"), + tag: &hex!("5d69b34d8c3b12f783faaea7e93685db"), + }, + TestVector { + key: &hex!("dd5c48988a6e9f9f60be801ba5c090f224a1b53d6601ec5858eab7b7784a8d5e"), + nonce: &hex!("43562d48cd4110a66d9ca64e"), + plaintext: &hex!("2cda2761fd0be2b03f9714fce8d0e303"), + aad: &hex!("55e568309fc6cb0fb0e0e7d2511d4116"), + ciphertext: &hex!("f2cfb6f5446e7aa172adfcd66b92a98d"), + tag: &hex!("e099c64d2966e780ce7d2eaae97f47d8"), + }, + TestVector { + key: &hex!("2bdad9c3e5de6e4e101b7f16e727c690db95eacf4b0ccbdec7aab6fb9fc80486"), + nonce: &hex!("a5cf3967d244074d2153c576"), + plaintext: &hex!("84c867ec36cc6fe3487f5192fdfd390b"), + aad: &hex!("6bdae72b5ed0e4d1f10064ebd02cf85c"), + ciphertext: &hex!("53c8fa437c1b5fa91abbd6508b3878ce"), + tag: &hex!("7859593d127324be8b9cf1d43ead4d82"), + }, + TestVector { + key: &hex!("01e92afdb5d956be12d38b09252966c5728d26f3c72e54bb62bbc55ae590e716"), + nonce: &hex!("886e55364eeb90e87ac79bbe"), + plaintext: &hex!("6c6570385f3d6d937e54a3a2e95bc9eb"), + aad: &hex!("c76aabb7f44b942a81feb50249d2131a"), + ciphertext: &hex!("423b749a507f437b431114962180d352"), + tag: &hex!("54d859320a49281368297da7d4e37326"), + }, + TestVector { + key: &hex!("46921319217598cb64256fe49abca1f18a9d1dbca360f8630afb5c6137cb42b5"), + nonce: &hex!("290827cf981415760ec3b37a"), + plaintext: &hex!("480d32b191c2e201aed03680f93ea2da"), + aad: &hex!("535ee80b12f581baaf8027e6e3900e31"), + ciphertext: &hex!("89ace4f73583fb1ac260dea99b54055e"), + tag: &hex!("7b8b8358363c175a66e6fb48d1bc2222"), + }, + TestVector { + key: &hex!("e18cd9b01b59bc0de1502efb74c3642997fe7dfb8d80c8a73caffe7726807d33"), + nonce: &hex!("bd087b384c40841b3839ba02"), + plaintext: &hex!("62f7f3a12b8c5f6747fcfe192d850b19"), + aad: &hex!("fe69f837961b1d83f27fbf68e6791a1c"), + ciphertext: &hex!("bacfccf6397424e96caf761e71dd3e3a"), + tag: &hex!("9c9a5b65420f83e766c7c051680e8e58"), + }, + TestVector { + key: &hex!("68ee463b3153d9a042e5e3685def6f90f7659a203441de337fb94831cbeae9b2"), + nonce: &hex!("9c4a9254c485236cf838de7e"), + plaintext: &hex!("73731054514f3fb0102c7a1df809f212"), + aad: &hex!("d55820e7acbb27d23c7df32938cf7d42"), + ciphertext: &hex!("13b7823cac37f40eb811e3c966d16a67"), + tag: &hex!("76288c33a66ff6451e2cec6c4ba4935e"), + }, + TestVector { + key: &hex!("64bd594daf279e3172f9aa713b35b7fce8f43083792bc7d1f10919131f400a7b"), + nonce: &hex!("339a2c40e9d9507c34228649"), + plaintext: &hex!("2b794cb4c98450463a3e225ab33f3f30"), + aad: &hex!("2b9544807b362ebfd88146e2b02c9270"), + ciphertext: &hex!("434d703b8d1069ad8036288b7c2d1ae6"), + tag: &hex!("7d31e397c0c943cbb16cfb9539a6a17d"), + }, + TestVector { + key: &hex!("83688deb4af8007f9b713b47cfa6c73e35ea7a3aa4ecdb414dded03bf7a0fd3a"), + nonce: &hex!("0b459724904e010a46901cf3"), + plaintext: &hex!("33d893a2114ce06fc15d55e454cf90c3"), + aad: &hex!("794a14ccd178c8ebfd1379dc704c5e208f9d8424"), + ciphertext: &hex!("cc66bee423e3fcd4c0865715e9586696"), + tag: &hex!("0fb291bd3dba94a1dfd8b286cfb97ac5"), + }, + TestVector { + key: &hex!("013f549af9ecc2ee0259d5fc2311059cb6f10f6cd6ced3b543babe7438a88251"), + nonce: &hex!("e45e759a3bfe4b652dc66d5b"), + plaintext: &hex!("79490d4d233ba594ece1142e310a9857"), + aad: &hex!("b5fe530a5bafce7ae79b3c15471fa68334ab378e"), + ciphertext: &hex!("619443034e4437b893a45a4c89fad851"), + tag: &hex!("6da8a991b690ff6a442087a356f8e9e3"), + }, + TestVector { + key: &hex!("4b2815c531d2fceab303ec8bca739a97abca9373b7d415ad9d6c6fa9782518cc"), + nonce: &hex!("47d647a72b3b5fe19f5d80f7"), + plaintext: &hex!("d3f6a645779e07517bd0688872e0a49b"), + aad: &hex!("20fd79bd0ee538f42b7264a5d098af9a30959bf5"), + ciphertext: &hex!("00be3b295899c455110a0ae833140c4d"), + tag: &hex!("d054e3997c0085e87055b79829ec3629"), + }, + TestVector { + key: &hex!("2503b909a569f618f7eb186e4c4b81dbfe974c553e2a16a29aea6846293e1a51"), + nonce: &hex!("e4fa3dc131a910c75f61a38b"), + plaintext: &hex!("188d542f8a815695c48c3a882158958c"), + aad: &hex!("f80edf9b51f8fd66f57ce9af5967ec028245eb6e"), + ciphertext: &hex!("4d39b5494ca12b770099a8eb0c178aca"), + tag: &hex!("adda54ad0c7f848c1c72758406b49355"), + }, + TestVector { + key: &hex!("6c8f34f14569f625aad7b232f59fa8b187ab24fadcdbaf7d8eb45da8f914e673"), + nonce: &hex!("6e2f886dd97be0e4c5bd488b"), + plaintext: &hex!("ac8aa71cfbf1e968ef5515531576e314"), + aad: &hex!("772ec23e49dbe1d923b1018fc2bef4b579e46241"), + ciphertext: &hex!("cb0ce70345e950b429e710c47d9c8d9b"), + tag: &hex!("9dceea98c438b1d9c154e5386180966d"), + }, + TestVector { + key: &hex!("182fe560614e1c6adfd1566ac44856df723dcb7e171a7c5796b6d3f83ef3d233"), + nonce: &hex!("8484abca6877a8622bfd2e3c"), + plaintext: &hex!("92ca46b40f2c75755a28943a68a8d81c"), + aad: &hex!("2618c0f7fe97772a0c97638cca238a967987c5e5"), + ciphertext: &hex!("ed1941b330f4275d05899f8677d73637"), + tag: &hex!("3fe93f1f5ffa4844963de1dc964d1996"), + }, + TestVector { + key: &hex!("65a290b2fabe7cd5fb2f6d627e9f1f79c2c714bffb4fb86e9df3e5eab28320ed"), + nonce: &hex!("5a5ed4d5592a189f0737cf47"), + plaintext: &hex!("662dda0f9c8f92bc906e90288100501c"), + aad: &hex!("ad1c7f7a7fb7f8fef4819c1dd1a67e007c99a87b"), + ciphertext: &hex!("8eb7cb5f0418da43f7e051c588776186"), + tag: &hex!("2b15399ee23690bbf5252fb26a01ae34"), + }, + TestVector { + key: &hex!("7b720d31cd62966dd4d002c9ea41bcfc419e6d285dfab0023ba21b34e754cb2f"), + nonce: &hex!("e1fb1f9229b451b72f89c333"), + plaintext: &hex!("1aa2948ed804f24e5d783b1bc959e086"), + aad: &hex!("7fdae42d0cf6a13873d3092c41dd3a19a9ea90f9"), + ciphertext: &hex!("8631d3c6b6647866b868421b6a3a548a"), + tag: &hex!("a31febbe169d8d6f391a5e60ef6243a0"), + }, + TestVector { + key: &hex!("a2aec8f3438ab4d6d9ae566a2cf9101ad3a3cc20f83674c2e208e8ca5abac2bb"), + nonce: &hex!("815c020686c52ae5ddc81680"), + plaintext: &hex!("a5ccf8b4eac22f0e1aac10b8d62cdc69"), + aad: &hex!("86120ce3aa81445a86d971fdb7b3b33c07b25bd6"), + ciphertext: &hex!("364c9ade7097e75f99187e5571ec2e52"), + tag: &hex!("64c322ae7a8dbf3d2407b12601e50942"), + }, + TestVector { + key: &hex!("e5104cfcbfa30e56915d9cf79efcf064a1d4ce1919b8c20de47eab0c106d67c1"), + nonce: &hex!("d1a5ec793597745c7a31b605"), + plaintext: &hex!("7b6b303381441f3fdf9a0cf79ee2e9e0"), + aad: &hex!("9931678430ff3aa765b871b703dfcc43fb1b8594"), + ciphertext: &hex!("425d48a76001bed9da270636be1f770b"), + tag: &hex!("76ff43a157a6748250a3fdee7446ed22"), + }, + TestVector { + key: &hex!("f461d1b75a72d942aa096384dc20cf8514a9ad9a9720660add3f318284ca3014"), + nonce: &hex!("d0495f25874e5714a1149e94"), + plaintext: &hex!("d9e4b967fdca8c8bae838a5da95d7cce"), + aad: &hex!("1133f372e3db22456e7ea92f29dff7f1d92864d3"), + ciphertext: &hex!("1df711e6fbcba22b0564c6e36051a3f7"), + tag: &hex!("f0563b7494d5159289b644afc4e8e397"), + }, + TestVector { + key: &hex!("a9a98ef5076ceb45c4b60a93aeba102507f977bc9b70ded1ad7d422108cdaa65"), + nonce: &hex!("54a1bc67e3a8a3e44deec232"), + plaintext: &hex!("ede93dd1eaa7c9859a0f709f86a48776"), + aad: &hex!("10cfef05e2cd1edd30db5c028bd936a03df03bdc"), + ciphertext: &hex!("3d3b61f553ab59a9f093cac45afa5ac0"), + tag: &hex!("7814cfc873b3398d997d8bb38ead58ef"), + }, + TestVector { + key: &hex!("d9e17c9882600dd4d2edbeae9a224d8588ff5aa210bd902d1080a6911010c5c5"), + nonce: &hex!("817f3501e977a45a9e110fd4"), + plaintext: &hex!("d74d968ea80121aea0d7a2a45cd5388c"), + aad: &hex!("d216284811321b7591528f0af5a3f2768429e4e8"), + ciphertext: &hex!("1587c8b00e2c197f32a21019feeee99a"), + tag: &hex!("63ea43c03d00f8ae5724589cb6f64480"), + }, + TestVector { + key: &hex!("ec251b45cb70259846db530aff11b63be00a951827020e9d746659bef2b1fd6f"), + nonce: &hex!("e41652e57b624abd84fe173a"), + plaintext: &hex!("75023f51ba81b680b44ea352c43f700c"), + aad: &hex!("92dd2b00b9dc6c613011e5dee477e10a6e52389c"), + ciphertext: &hex!("29274599a95d63f054ae0c9b9df3e68d"), + tag: &hex!("eb19983b9f90a0e9f556213d7c4df0f9"), + }, + TestVector { + key: &hex!("61f71fdbe29f56bb0fdf8a9da80cef695c969a2776a88e62cb3d39fca47b18e3"), + nonce: &hex!("77f1d75ab0e3a0ed9bf2b981"), + plaintext: &hex!("110a5c09703482ef1343396d0c3852d3"), + aad: &hex!("c882691811d3de6c927d1c9f2a0f15f782d55c21"), + ciphertext: &hex!("7e9daa4983283facd29a93037eb70bb0"), + tag: &hex!("244930965913ebe0fa7a0eb547b159fb"), + }, + TestVector { + key: &hex!("e4fed339c7b0cd267305d11ab0d5c3273632e8872d35bdc367a1363438239a35"), + nonce: &hex!("0365882cf75432cfd23cbd42"), + plaintext: &hex!("fff39a087de39a03919fbd2f2fa5f513"), + aad: &hex!("8a97d2af5d41160ac2ff7dd8ba098e7aa4d618f0f455957d6a6d0801796747ba57c32dfbaaaf15176528fe3a0e4550c9"), + ciphertext: &hex!("8d9e68f03f7e5f4a0ffaa7650d026d08"), + tag: &hex!("3554542c478c0635285a61d1b51f6afa"), + }, + TestVector { + key: &hex!("bd93c7bfc850b33c86484e04859ed374beaee9d613bdca6f072d1d182aeebd04"), + nonce: &hex!("6414c7749effb9af7e5c4762"), + plaintext: &hex!("b6de1699931f2252efc98d491d22ee12"), + aad: &hex!("76f43d5664c7ac1b4de43f2e2c4bc71f6918e0762f40e5dd5597ef4ff215855a4fd26d3ea6ccbd4e10789948fa692433"), + ciphertext: &hex!("a6c7e52f2018b823506e48064ffe6ee4"), + tag: &hex!("175e653c9036f66835f10cf1c82d1741"), + }, + TestVector { + key: &hex!("df0125a826c7fe49243d89cbdd7562aafd2103fa2783cf901976b5f5d481cdcb"), + nonce: &hex!("f63c1461b2964929d035d9bf"), + plaintext: &hex!("cc27ff68f981e4d6fb1918427c3d6b9e"), + aad: &hex!("0bf602ec47593e44ac1b88244455fa04359e338057b0a0ba057cb506d546d4d6d8538640fe7dd3d5864bd33b5a33d768"), + ciphertext: &hex!("b8fa150af93078574ac7c4615f88647d"), + tag: &hex!("4584553ac3ccdf8b0efae517652d3a18"), + }, + TestVector { + key: &hex!("d33ea320cec0e43dfc1e3d1d8ccca2dd7e30ad3ea18ad7141cc83645d18771ae"), + nonce: &hex!("540009f321f41d00202e473b"), + plaintext: &hex!("e56cdd522d526d8d0cd18131a19ee4fd"), + aad: &hex!("a41162e1fe875a81fbb5667f73c5d4cbbb9c3956002f7867047edec15bdcac1206e519ee9c238c371a38a485c710da60"), + ciphertext: &hex!("8b624b6f5483f42f36c85dc7cf3e9609"), + tag: &hex!("2651e978d9eaa6c5f4db52391ac9bc7c"), + }, + TestVector { + key: &hex!("7f35f5979b23321e6449f0f5ef99f2e7b796d52d560cc77aabfb621dbf3a6530"), + nonce: &hex!("cf0f6f3eed4cf374da714c77"), + plaintext: &hex!("4e9f53affdb5b1e91bf423d29c54401a"), + aad: &hex!("a676d35d93e12bfe0603f6aef2c3dd892a9b1ad22d476c3509d313256d4e98e4dda4e46e93b54cf59c2b90608a8fb3ad"), + ciphertext: &hex!("1714d55ef83df2927ee95ff22f1d90e6"), + tag: &hex!("4962a91d1071dd2c05934968d21eb43c"), + }, + TestVector { + key: &hex!("06ecc134993506cf539b1e797a519fe1d9f34321fe6a0b05f1936285c35c93a4"), + nonce: &hex!("f2190861d1140bd080d79906"), + plaintext: &hex!("519c1fc45a628ec16c515427796711f7"), + aad: &hex!("a04f2723c2521181437ad63f7910481d5de98f3e2561cec3a177bdbcb5048619738852e0fb212a3caa741a353e4e89a8"), + ciphertext: &hex!("b36c793224ce3bb1b54144398fbdedb6"), + tag: &hex!("0030e6e84f6f8eb474ce8e071c2953dd"), + }, + TestVector { + key: &hex!("734fa8b423b91e0ecccc7f554480eef57a82423a9f92b28d464320fba405a71c"), + nonce: &hex!("a6b5c78bb5791f4d121390ce"), + plaintext: &hex!("b496a99b39e0e94bb5829cfc3d7b3856"), + aad: &hex!("9ce25ff9b55dfa04e4271999a47cba8af8e83a390b090d1c4306b40ce8882624b662ff5867896396789295c19ec80d07"), + ciphertext: &hex!("904081a40484bb6454fc52cb6674e737"), + tag: &hex!("6a0787cf3921a71c35b5054954527823"), + }, + TestVector { + key: &hex!("d106280b84f25b294f71c261f66a65c2efd9680e19f50316d237975052796392"), + nonce: &hex!("cfc6aa2aeba468c66bf4553f"), + plaintext: &hex!("57e937f8b9b814e965bb569fcf63aaac"), + aad: &hex!("012a43f9903a3808bf34fd6f77d831d9154205ded589964cae60d2e49c856b7a4100a55c8cd02f5e476f62e988dcbd2b"), + ciphertext: &hex!("c835f5d4fd30fe9b2edb4aff24803c60"), + tag: &hex!("e88426bb4619807f18a9cc9839754777"), + }, + TestVector { + key: &hex!("81eb63bc47aba313d964a5335cfb039051520b3112fa54cab368e5243947d450"), + nonce: &hex!("18cc5dd875753ff51cc6f441"), + plaintext: &hex!("45f51399dff6a0dcd43f35256616d6be"), + aad: &hex!("24f766c56777312494245a4e6c7dbebbae4026e0907eadbc20a488982678161de7b924473c0a81ee59a0fa6905952b33"), + ciphertext: &hex!("a2fc7b0784ec4233142f9cde12ab9e98"), + tag: &hex!("4e60b8561cacfe7133740cd2bddefaa0"), + }, + TestVector { + key: &hex!("0a997863786a4e97332224ed484ffca508b166f0603687200d99fd6accd45d83"), + nonce: &hex!("7a9acabd4b8d3e1036293a07"), + plaintext: &hex!("9d2c9ff39f57c96ecce287c68c5cd6eb"), + aad: &hex!("525fc5ac7fe93c183a3ef7c75e3fbd52dce956855aff385966f4d79966bdb3ec2019c466584d21bfee74511a77d82adb"), + ciphertext: &hex!("238441c65b2a1c41b302da0f52d40770"), + tag: &hex!("c351d93ab9491cdfb7fa15e7a251de22"), + }, + TestVector { + key: &hex!("acbfeb7c595b704960c1097e93d3906534c23444c8acc1f8e969ce6c3fe8a46b"), + nonce: &hex!("28922ecac3013806c11660e6"), + plaintext: &hex!("e0d8c52d60c6ed6980abd4348f3f96f1"), + aad: &hex!("b1fe886107013ebdeb19315a9d096ed81803951a508f56f68202a7df00bebae0742dd1128c200952a049ef0cd7cfe4e6"), + ciphertext: &hex!("56fe1cf2c1d193b9b33badbf846f52cc"), + tag: &hex!("1cb4c14f50a54a64813ffc810f31f9f8"), + }, + TestVector { + key: &hex!("f6e768475c33269596da1f5a5a38547a885006bebb9134e21274d8456e9f5529"), + nonce: &hex!("3579e5ac51d1f1b82ea352ca"), + plaintext: &hex!("0aa481f856f8b96547672e5ae5370f9e"), + aad: &hex!("6929b6053ba148304366164f79b1b9f592c9cb9bce65094cec5cb8b0fc63e20d86b17c8bf5a7b089a63c5eac1824ee93"), + ciphertext: &hex!("b2f4edf5f0b0bfc590fead6239b0f2fb"), + tag: &hex!("2540ceb5ef247c95d63df84c46468533"), + }, + TestVector { + key: &hex!("2ca76112300bed65b87ba6ec887cd514f4633c1c96565fec8e3e69ae2ba88401"), + nonce: &hex!("964864510a8c957dcfb97d2f"), + plaintext: &hex!("0aff24b4c5aa45b81ce08ec2439be446"), + aad: &hex!("5aebdfd153a18763f36ecc9e8e9a01cb7b3f21e435b35b0da937c67e87c9ec058d08060a95e1eda0a5ab6546cca45094"), + ciphertext: &hex!("03da1f5a1403dbdd9f75a26113608ec0"), + tag: &hex!("a1c215d0c552a6061aa2b60afc3667a6"), + }, + TestVector { + key: &hex!("c0ff018b6c337dde685c8279cf6de59d7ce4b288032b819e074b671e72abbc91"), + nonce: &hex!("f12e6b1e85f87ef4c9ccbb7b"), + plaintext: &hex!("f7512bbfa2d40d14be71b70f70701c99"), + aad: &hex!("0577e8d28c0e9e5cde3c8b2a1a2aa8e2fc3ec8e96768405fcfbd623be7fc4e2e395c59b5b3a8ea117ef211320bc1f857"), + ciphertext: &hex!("0187b4c2d52486b4417e5a013d553e5e"), + tag: &hex!("dba451e7339be8ebed3ea9683d1b4552"), + }, + TestVector { + key: &hex!("d90c6948ac2353867e943069196a2c4d0c4d51e34e2505661b1d76f3e5f17ac5"), + nonce: &hex!("07e5623f474e2f0fe9f4c7d2"), + plaintext: &hex!("8a9fb1b384c0d1728099a4f7cb002f07"), + aad: &hex!("0de97574ae1bc6d3ef06c6ce03513ca47dff4728803e0aacc50564ee32b775fd535f5c8c30186550d99bff6f384af2dd"), + ciphertext: &hex!("4234a3a9fb199c3b293357983e8ac30b"), + tag: &hex!("d51e6f071dbab126f5fc9732967108ef"), + }, + TestVector { + key: &hex!("80d755e24d129e68a5259ec2cf618e39317074a83c8961d3768ceb2ed8d5c3d7"), + nonce: &hex!("7598c07ba7b16cd12cf50813"), + plaintext: &hex!("5e7fd1298c4f15aa0f1c1e47217aa7a9"), + aad: &hex!("0e94f4c48fd0c9690c853ad2a5e197c5de262137b69ed0cdfa28d8d12413e4ffff15374e1cccb0423e8ed829a954a335ed705a272ad7f9abd1057c849bb0d54b768e9d79879ec552461cc04adb6ca0040c5dd5bc733d21a93702"), + ciphertext: &hex!("5762a38cf3f2fdf3645d2f6696a7eead"), + tag: &hex!("8a6708e69468915c5367573924fe1ae3"), + }, + TestVector { + key: &hex!("dda7977efa1be95a0e41ed8bcd2aa648621945c95a9e28b63919e1d92d269fc3"), + nonce: &hex!("053f6e1be42af8894a6e86a0"), + plaintext: &hex!("6fa9b08176e9963927afba1e5f969a42"), + aad: &hex!("cb5114a001989339657427eb88329d6ce9c69694dc91a69b7557d62184e57832ec76d162fc9c47490bb3d78e5899445cecf85d36cb1f07fed5a3d82aaf7e9590f3ed74ad13b13c8adbfc7f29d7b151448d6f29d11d0bd3d03b76"), + ciphertext: &hex!("d4adbff3ec8edade29b9a1b748c31b54"), + tag: &hex!("3b331733c753858c22d309ceb0f9488c"), + }, + TestVector { + key: &hex!("d7da934ad057dc06bd1ec234fcc4efdc5119037a440b5827de25915f22dd47e5"), + nonce: &hex!("1b54c4ea37d2395ef70dcc72"), + plaintext: &hex!("86d5567658361198348207ede7a46da6"), + aad: &hex!("735de4596a80e64e38a12ab24ef73881d6ed3b533cb2c101025c3615acd2114150feeca84ade4e563bc4a300eb4a0cd97a184a293f0ac063e4f3c61e7fcdb331bcc6459fafaf0e2dda881f34eb717f4ee8c4b6890d3ef59721f3"), + ciphertext: &hex!("70a1c1d7c200ba5ae1b6f29917bb19f2"), + tag: &hex!("a25d51cccb198bed33de0b98df249c2d"), + }, + TestVector { + key: &hex!("930ebb4b9b9c35094be374cc0b700c437b3c46b45d489a716c30f93cd5f986c9"), + nonce: &hex!("7a21e5febd82ec9b97bfbe83"), + plaintext: &hex!("980086665d08a365f6bbe20ae51116f7"), + aad: &hex!("9f2ed5f6cf9e2d6505d3c99a8f81a7dfc5658dd085eba966c8b3206230973a086ec36fe948573baee108fca941bce53dad73180877cd497976209c1adf8a9861f0215560df064caf0ef2f99445c11816f5b8deeafedd682b5fb2"), + ciphertext: &hex!("05baaefdeb0c33674a8064a2e9951aaf"), + tag: &hex!("2ec7efd2564d4e09a6ab852f3af49939"), + }, + TestVector { + key: &hex!("70213d8949a65f463d13206071fab1b4c6b614fd3cee0d340d2d806de6714a93"), + nonce: &hex!("f8529d3e4f155cbb1ffb3d0a"), + plaintext: &hex!("47d47a5fd32a2a416f921cc7f00c0f81"), + aad: &hex!("112360db39b867dabaaa1d777bd881df2104b69fba15a4f37a832f5da38ad8a8c7c46db93e5b4eadf8b9a5a75508ad1457994c133c5ac85509eedfb13b90a2cf6c56a3c778582939362008608b08f9c4866a0e38744572114598"), + ciphertext: &hex!("b220b69bd851a17fbc5b725fb912f11e"), + tag: &hex!("4c3436943d58501c0826ae5827bc063e"), + }, + TestVector { + key: &hex!("7a5834230ebbbf616630f2edb3ad4320182433c0546ac1e34bc9fd046e4a0ed9"), + nonce: &hex!("d27dd6212b6defdcbbc701bb"), + plaintext: &hex!("b4def1251427ade064a9614e353dda3f"), + aad: &hex!("3bc12f3bb88ea4f8a2184959bb9cd68911a78458b27e9b528ccecafe7f13f303dc714722875f26b136d18a3acfe82b53ad5e13c71f3f6db4b0fd59fffd9cd4422c73f2c31ac97010e5edf5950dc908e8df3d7e1cbf7c34a8521e"), + ciphertext: &hex!("88f94965b4350750e11a2dc139ccaef1"), + tag: &hex!("8a61f0166e70c9bfdd198403e53a68a5"), + }, + TestVector { + key: &hex!("c3f10586f246aacadcce3701441770c03cfec940afe1908c4c537df4e01c50a0"), + nonce: &hex!("4f52faa1fa67a0e5f4196452"), + plaintext: &hex!("79d97ea3a2edd65045821ea745a44742"), + aad: &hex!("46f9a22b4e52e1526513a952dbee3b91f69595501e0177d50ff364638588c08d92fab8c58a969bdcc84c468d8498c4f06392b99ed5e0c484507fc48dc18d87c40e2ed848b43150be9d36f14cf2cef1310ba4a745adcc7bdc41f6"), + ciphertext: &hex!("560cf716e56190e9397c2f103629eb1f"), + tag: &hex!("ff7c9124879644e80555687d273c55d8"), + }, + TestVector { + key: &hex!("ad70ebcf889e88b867ded0e4838ca66d6991499046a5671d99e91ed463ae78b1"), + nonce: &hex!("561e13b335718fcbee364100"), + plaintext: &hex!("82d5568872a4cef12238c0feb14f0fb4"), + aad: &hex!("e037bd7306eec185b9cb4e3bf295232da19005957086d62e6fb342284f05feaa0e81d6c95071e7e4d7b6aad7b00f7e7863dd0fc16303a8304bb8855305f28067f4be71eed95ff90e046382116229f0fd3d2c3ef2e87e0d0e7950"), + ciphertext: &hex!("771c6d091f8190ddbdb8886d9ce2ebd5"), + tag: &hex!("5009abd1ebeb26dab852346ea6d8aee3"), + }, + TestVector { + key: &hex!("a452fa24b381e7165ee90f3371c2b0db2176f848a0354c78e92f2f1f89bbc511"), + nonce: &hex!("4bd904dfe18241eb5455d912"), + plaintext: &hex!("3f43df23ea940f3680a4b679b56db579"), + aad: &hex!("64f1a9d21deb183cff84f1aef5be83dbfc72e275f229eb5d59ace143605e8901dfa8f4724be24c86b5429bc84b629971fe1f9663b7537427b45dfb67d5f04506df4ee2c33d7f15af9f6e86058b131b7e6042b43a55bf6915f048"), + ciphertext: &hex!("c054974c4562f8536aef2734f10e09fc"), + tag: &hex!("2c5cafaf7b1f7581c5ec13080994e33c"), + }, + TestVector { + key: &hex!("209ea3c4dd0420a4d63dbb72099a0202c9b0709f3b1221565f890511eef8005b"), + nonce: &hex!("43775083e4008816129f5d40"), + plaintext: &hex!("b4967f8c4fb1b34b6ff43a22d34fae5c"), + aad: &hex!("9abc653a2347fc6e5a8cb9bdc251dff7c56109797c387494c0ed55570330961eb5b11087603e08ad293d0dd55571008e62d1163f67cf829e28d27beba65553bd11d8838f8a7a5f1fe05500befbaf97839801e99ecf998882c707"), + ciphertext: &hex!("a8d22a6e25232938d3f8600a66be80da"), + tag: &hex!("2ef93cc03c17bbfb6626144697fd2422"), + }, + TestVector { + key: &hex!("dabd63ac5274b26842c2695c9850d7accc1693ee2aeee1e2e1338bbbc5b80f87"), + nonce: &hex!("fd6790d620f12870b1d99b31"), + plaintext: &hex!("4a28048f5683679a557630a661f030e2"), + aad: &hex!("e4a06b9b205a7faadb21dc7fea8a0de0e013d717b61b24ec42f81afc8cdbc055573e971375da2fa5103a091317eab13b6a110ea211af257feabf52abafec23fd5b114b013d5c052199020573f8b7b7ae6958f733e87efa0426c2"), + ciphertext: &hex!("196d0345df259b47665bc233b798ebba"), + tag: &hex!("b0729d8b427ad048a7396cedf2257338"), + }, + TestVector { + key: &hex!("b238df5e52e649d4b0a05e53020ac59e7d5bf49b8d04f8c30c356ed62dba9ed1"), + nonce: &hex!("f153f093c9a3479f999eda04"), + plaintext: &hex!("d48e779766afa73d7e04fc6fc3fa825e"), + aad: &hex!("45b5df0c15140e5ce7a19f4e02834e6027971e3e0e719626c29081a6301e95c71214345afac1908bb75ff2d3281261e6c5f41dc4e4796f054174a64f8e177f3f33321edfbd263e204135699428a09f34eb344211bfb9fac9afba"), + ciphertext: &hex!("b1989eb510843d8f35205dc3f949522f"), + tag: &hex!("616089990729228f673099514824d9b4"), + }, + TestVector { + key: &hex!("f3dc2456d3b8947591a2d82b7319226b0f346cd4361bcc13b56da43e072a2774"), + nonce: &hex!("7a8acb5a84d7d01e3c00499e"), + plaintext: &hex!("ad075da908231ff9aae30daa6b847143"), + aad: &hex!("5e6be069effee27d34a8087c0d193f9f13e6440dc9fabfe24f6c867f831d06789d0dce92b2e3ff3ab9fe14202a8b42f384c25e3f3753dd503ec907a9b877f1707d64e4ac42909a7dee00c87c4a09d04de331515460ed101f5187"), + ciphertext: &hex!("9f224f2a1a1fbaade8b87b748971c0ac"), + tag: &hex!("cb5089d9dfaebf98e4b36ebc5f9a1a50"), + }, + TestVector { + key: &hex!("f5a56b69a1562c77e8edebc327a20295c2eba7d406d899a622c53539626c9d72"), + nonce: &hex!("a395b8aca4508a6a5f3cb4d8"), + plaintext: &hex!("7de4638701bd2b600d7f8d26da7a75bc"), + aad: &hex!("2e4fca2b163e4403971716015386cd81bdd1e57f00f2936da408098341011f2644a38ddad799f70eaa54f6e430d4853ff2b9c44a35123670879a83120bd555c76b95b70de0c8054f9d08539a5795e70a2446d7b9fab3f7887c6b"), + ciphertext: &hex!("6508be2698ba9889b4e445b99190a5c5"), + tag: &hex!("3394106f257c2e15c815430f60bc24ba"), + }, + TestVector { + key: &hex!("376371a780947256c52f07d80bb25a4d7e919ca8bd693b1a0ccbca748d2ce620"), + nonce: &hex!("27d7170f6f70f2fc40dfca78"), + plaintext: &hex!("7a279f9f8568b7c307490549b259226c"), + aad: &hex!("272c3559398ad774fa4b6895afc92870b2b92d310fa0debf0b7960e1fe38bfda64acd2fef26d6b177d8ab11d8afceee77374c6c18ad405d5ae323ad65fb6b04f0c809319133712f47636c5e042f15ed02f37ee7a10c643d7b178"), + ciphertext: &hex!("32284379d8c40ec18ee5774085d7d870"), + tag: &hex!("dcdee1a757f9758c944d296b1dabe7b2"), + }, + TestVector { + key: &hex!("82c4f12eeec3b2d3d157b0f992d292b237478d2cecc1d5f161389b97f999057a"), + nonce: &hex!("7b40b20f5f397177990ef2d1"), + plaintext: &hex!("982a296ee1cd7086afad976945"), + aad: b"", + ciphertext: &hex!("ec8e05a0471d6b43a59ca5335f"), + tag: &hex!("113ddeafc62373cac2f5951bb9165249"), + }, + TestVector { + key: &hex!("db4340af2f835a6c6d7ea0ca9d83ca81ba02c29b7410f221cb6071114e393240"), + nonce: &hex!("40e438357dd80a85cac3349e"), + plaintext: &hex!("8ddb3397bd42853193cb0f80c9"), + aad: b"", + ciphertext: &hex!("b694118c85c41abf69e229cb0f"), + tag: &hex!("c07f1b8aafbd152f697eb67f2a85fe45"), + }, + TestVector { + key: &hex!("acad4a3588a7c5ec67832baee242b007c8f42ed7425d5a7e57b1070b7be2677e"), + nonce: &hex!("b11704ba368abadf8b0c2b98"), + plaintext: &hex!("2656b5fbec8a3666cad5f460b7"), + aad: b"", + ciphertext: &hex!("35c7114cabe39203df19413a99"), + tag: &hex!("16f4c7e5becf00db1223476a14c43ebc"), + }, + TestVector { + key: &hex!("e5a0eb92cc2b064e1bc80891faf1fab5e9a17a9c3a984e25416720e30e6c2b21"), + nonce: &hex!("4742357c335913153ff0eb0f"), + plaintext: &hex!("8499893e16b0ba8b007d54665a"), + aad: b"", + ciphertext: &hex!("eb8e6175f1fe38eb1acf95fd51"), + tag: &hex!("88a8b74bb74fda553e91020a23deed45"), + }, + TestVector { + key: &hex!("e78c477053f5dae5c02941061d397bc38dda5de3c9c8660a19de66c56c57fd22"), + nonce: &hex!("4f52c67c2bb748d192a5a4e2"), + plaintext: &hex!("91593e21e1f883af5c32d9be07"), + aad: b"", + ciphertext: &hex!("e37fbc56b0af200a7aa1bbe34e"), + tag: &hex!("29fe54eaaccf5e382601a15603c9f28c"), + }, + TestVector { + key: &hex!("d0b13482037639aa797471a52b60f353b42e0ed271daa4f38a9293191cb78b72"), + nonce: &hex!("40fb7cae46adf3771bf3756a"), + plaintext: &hex!("938f40ac8e0e3b956aac5e9184"), + aad: b"", + ciphertext: &hex!("7dca05a1abe81928ccfb2164dd"), + tag: &hex!("5ea53ee170d9ab5f6cc047854e47cf60"), + }, + TestVector { + key: &hex!("46da5ec688feead76a1ddcd60befb45074a2ef2254d7be26abdfd84629dbbc32"), + nonce: &hex!("9fb3b2b03925f476fc9a35f3"), + plaintext: &hex!("a41adc9fb4e25a8adef1180ec8"), + aad: b"", + ciphertext: &hex!("f55d4cbe9b14cea051fe7a2477"), + tag: &hex!("824753da0113d21186699dbb366c0589"), + }, + TestVector { + key: &hex!("de3adf89f2fe246c07b0ce035f4af73cf2f65e5034dcfecfe9d7690ae1bdbd96"), + nonce: &hex!("a94aa4df0d8451644a5056c0"), + plaintext: &hex!("96825f6d6301db14a8d78fc2f4"), + aad: b"", + ciphertext: &hex!("784c6c3c24a022637cbc907c48"), + tag: &hex!("1eeaeddcdb4c72c4e8966950a319a4ef"), + }, + TestVector { + key: &hex!("03c362288883327f6289bc1824e1c329ce485e0ce0e8d3405245283cf0f2eae2"), + nonce: &hex!("5de9f882c915c72729b2245c"), + plaintext: &hex!("f5c1c8d41de01d9c08d9f47ece"), + aad: b"", + ciphertext: &hex!("61af621953a126a2d1de559e92"), + tag: &hex!("fbdeb761238f2b70c5fb3dde0a7978f3"), + }, + TestVector { + key: &hex!("e9ead7c59100b768aa6367d80c04a49bcd19fa8cc2e158dc8edeec3ea39b657d"), + nonce: &hex!("e81854665d2e0a97150fbab3"), + plaintext: &hex!("f8ccf69c52a873695367a42940"), + aad: b"", + ciphertext: &hex!("af2a7199602ee9ed2020c7b4cd"), + tag: &hex!("29715945ab1c034ecfcd91a466fc822e"), + }, + TestVector { + key: &hex!("bc3e5b0fe423205904c32f870b9adec9d736a1616624043e819533fa97ed9b79"), + nonce: &hex!("335fe5180135673ce1a75144"), + plaintext: &hex!("295df9665eef999204f92acf24"), + aad: b"", + ciphertext: &hex!("3ac2a8a1b505a84677adfdb396"), + tag: &hex!("21f20aa0bb77d46d7290bc9c97a7a7bd"), + }, + TestVector { + key: &hex!("ce889c73e0d64e272aba4bf9777afc7ee6457ddc9626ad931708ed7530d71b99"), + nonce: &hex!("fe61a6cda62fecd4e3b0c562"), + plaintext: &hex!("e2ae40ba5b4103b1a3066c1b57"), + aad: b"", + ciphertext: &hex!("185aa3508a37e6712b28191ec2"), + tag: &hex!("9ec1d567585aa467730cce92e536728e"), + }, + TestVector { + key: &hex!("41e0cb1aed2fe53e0b688acb042a0c710a3c3ae3205b07c0af5191073abdfba9"), + nonce: &hex!("2f56e35216d88d34d08f6872"), + plaintext: &hex!("6482df0e4150e73dac51dc3220"), + aad: b"", + ciphertext: &hex!("9cb09b9927dfbe0f228e0a4307"), + tag: &hex!("fe7e87a596d63e2ab2aae46b64d466e8"), + }, + TestVector { + key: &hex!("52a7662954d525cb00602b1ff5e937d41065ac4b921e284ffac73c04cfd462a0"), + nonce: &hex!("baffe73856ab1a47fb1feebf"), + plaintext: &hex!("9d0b5ca712f97caa1875d3ad87"), + aad: b"", + ciphertext: &hex!("fd01165380aedd6be226a66af3"), + tag: &hex!("35a492e39952c26456850b0172d723d1"), + }, + TestVector { + key: &hex!("c4badb9766986faeb888b1db33060a9cd1f02e1afe7aaaea072d905750cb7352"), + nonce: &hex!("cc6966e9d81a298a561416d4"), + plaintext: &hex!("de68fb51731b45e7c2c5063923"), + aad: b"", + ciphertext: &hex!("f5be41f2c8c32e01098d433057"), + tag: &hex!("c82b1b012916ab6ed851d59829dad8ab"), + }, + TestVector { + key: &hex!("dad89d9be9bba138cdcf8752c45b579d7e27c3dbb40f53e771dd8cfd500aa2d5"), + nonce: &hex!("cfb2aec82cfa6c7d89ee72ff"), + plaintext: &hex!("b526ba1050177d05b0f72f8d67"), + aad: &hex!("6e43784a91851a77667a02198e28dc32"), + ciphertext: &hex!("8b29e66e924ecae84f6d8f7d68"), + tag: &hex!("1e365805c8f28b2ed8a5cadfd9079158"), + }, + TestVector { + key: &hex!("0d35d3dbd99cd5e088caf686b1cead9defe0c6001463e92e6d9fcdc2b0dcbaf6"), + nonce: &hex!("f9139eb9368d69ac48479d1f"), + plaintext: &hex!("5e2103eb3e739298c9f5c6ba0e"), + aad: &hex!("825cc713bb41c789c1ace0f2d0dd3377"), + ciphertext: &hex!("8ff3870eec0176d9f0c6c1b1a2"), + tag: &hex!("344234475538dc78c01f249f673e0862"), + }, + TestVector { + key: &hex!("d35d64f1872bdcb422228f0d63f8e48977ed68d143f648ae2cd852f944b0e6dd"), + nonce: &hex!("0b2184aadbe8b515924dda5e"), + plaintext: &hex!("c8f999aa1a08871d74db490cf3"), + aad: &hex!("888f328d9e9eebbb9cb2704b5b880d66"), + ciphertext: &hex!("ad0d5e7c1065a34b27a256d144"), + tag: &hex!("8c8e7076950f7f2aeba62e1e761650d5"), + }, + TestVector { + key: &hex!("9484b7ce3c118a8a2d556c2f7ba41fca34f60c9ea1070171459c9e7487c9537e"), + nonce: &hex!("87bc033522ae84d2abe863c5"), + plaintext: &hex!("14d8004793190563825e273dda"), + aad: &hex!("07ee18737b9bf8223979a01c59a90eb4"), + ciphertext: &hex!("43034a2c57ccacc367796d766a"), + tag: &hex!("4c981ca8b6e9e52092f5435e7ef55fbb"), + }, + TestVector { + key: &hex!("4f4539e4a80ec01a14d6bb1bae0010f8a8b3f2cd0ac01adf239a9b2b755f0614"), + nonce: &hex!("2b6f00ce1570432bf52fdcac"), + plaintext: &hex!("820cc9389e7e74ca1cbb5a5fe6"), + aad: &hex!("0d72a13effe40544c57cc18005b998cb"), + ciphertext: &hex!("99553fdf3e777e2a4b3b6a5538"), + tag: &hex!("3cbf51640a3a93c3662c738e98fb36a2"), + }, + TestVector { + key: &hex!("2f5e93ee24a8cd2fc6d3765f12d2179ddb8397783e136af9e0ac75f16fca451e"), + nonce: &hex!("0dc3c70a191f3722641fd701"), + plaintext: &hex!("4e96463793cdeda403668c4aee"), + aad: &hex!("ebab30cbcc99905354e4ee6f07c7db87"), + ciphertext: &hex!("ab03f8ca7b1b150bdc26d4e691"), + tag: &hex!("020546afff4290c4c8ef7fc38035ebfd"), + }, + TestVector { + key: &hex!("a902e15d06ef5ad334d0ec6502e936ee53ef3f3608f7708848b11cefa92983d1"), + nonce: &hex!("b9f3e966efa43ab4aca1f2d8"), + plaintext: &hex!("393ff3dfe51cd43543e4e29fcc"), + aad: &hex!("2eaa35c00bf1cf8a81919bd04b43fd97"), + ciphertext: &hex!("7e8928b450c622ac8efe29d5a0"), + tag: &hex!("5a285de95990aef171629350bbcaf46e"), + }, + TestVector { + key: &hex!("96657976da7692004e271b594e8304f77db9c9e77859246bb30a16239ba76a53"), + nonce: &hex!("79226100afea30644876e79a"), + plaintext: &hex!("2b0833a065c3853ee27c8968d0"), + aad: &hex!("ede7a9072a0086b9a1e55d900747cf76"), + ciphertext: &hex!("19373168f1a4052a57c6b8146f"), + tag: &hex!("debbf044325384b90a0c442d95455fb9"), + }, + TestVector { + key: &hex!("630ea13eb5f52378b976ba2662f824dc622920759a15d2e341c446b03ea7bd5c"), + nonce: &hex!("0f9ebe47682f93d44c4db314"), + plaintext: &hex!("5c734964878a4250a3bf61fdd6"), + aad: &hex!("5ad8e9cffe622e9f35bdb185473868e5"), + ciphertext: &hex!("67cb6d943340d002d3323fcc4e"), + tag: &hex!("f5dc0f88f236560c4e2a6d6c15d3c0de"), + }, + TestVector { + key: &hex!("c64f8a3ac230dce61b53d7b584f2309384274d4b32d404bc0c491f129781e52d"), + nonce: &hex!("7f4b3bcf763f9e2d08516a6d"), + plaintext: &hex!("fe581128ae9832d27ec58bd7ac"), + aad: &hex!("89ed6945547ee5998de1bb2d2f0bef1e"), + ciphertext: &hex!("81d7a8fdaf42b5716b892199c9"), + tag: &hex!("8183aaff4c0973fe56c02c2e0c7e4457"), + }, + TestVector { + key: &hex!("dd73670fb221f7ee185f5818065e22dda3780fc900fc02ef00232c661d7bffce"), + nonce: &hex!("c33de65344cfbf228e1652bd"), + plaintext: &hex!("ada4d98147b30e5a901229952a"), + aad: &hex!("e1a5e52427f1c5b887575a6f2c445429"), + ciphertext: &hex!("6ed4e4bd1f953d47c5288c48f4"), + tag: &hex!("404e3a9b9f5ddab9ee169a7c7c2cf7af"), + }, + TestVector { + key: &hex!("f6c5d9562b7dbdd0bf628ddc9d660c27841b06a638f56601f408f23aa2f66f4e"), + nonce: &hex!("67280bcb945ba6eda1c6c80a"), + plaintext: &hex!("f4caead242d180fbd2e6d32d0c"), + aad: &hex!("5b33716567b6c67b78ea5cd9349bcaaf"), + ciphertext: &hex!("fdfa39517d89ea47e6ccb0f831"), + tag: &hex!("91f9b540ca90e310a1f5c12c03d8c25e"), + }, + TestVector { + key: &hex!("ce1d242f13de7638b870e0aa85843ea43a9255a4fa4d32057347f38e0267daeb"), + nonce: &hex!("86562be4621b4d5eb1983075"), + plaintext: &hex!("d20e59a8ef1a7de9096c3e6746"), + aad: &hex!("d48a9490a0b7deb023460608b7db79ce"), + ciphertext: &hex!("35ce69fb15d01159c52266537c"), + tag: &hex!("dc48f7b8d3feeeb26fcf63c0d2a889ec"), + }, + TestVector { + key: &hex!("512753cea7c8a6165f2ebbd3768cc7b951029bd527b126233cf0841aff7568c7"), + nonce: &hex!("b79221802d8d97978041fe84"), + plaintext: &hex!("c63d6c1006b615275c085730b1"), + aad: &hex!("22fa0605b955a33468f3e60160b907f2"), + ciphertext: &hex!("bdb5d7f24732bdba1d2a429108"), + tag: &hex!("fca923d2941a6fd9d596b86c3afb0ad9"), + }, + TestVector { + key: &hex!("e7b18429e3edded2d992ca27afab99e438b8aff25fc8460201fabe08e7d48ec2"), + nonce: &hex!("9db9b7320aaac68538e37bf7"), + plaintext: &hex!("c4713bc67a59928eee50039901"), + aad: &hex!("283e12a26e1646087b5b9d8c123dde1f"), + ciphertext: &hex!("a5932f92bda107d28f2a8aaa74"), + tag: &hex!("9a1357fd8ed21fe14d1ca2e597c3ef17"), + }, + TestVector { + key: &hex!("69b458f2644af9020463b40ee503cdf083d693815e2659051ae0d039e606a970"), + nonce: &hex!("8d1da8ab5f91ccd09205944b"), + plaintext: &hex!("f3e0e09224256bf21a83a5de8d"), + aad: &hex!("036ad5e5494ef817a8af2f5828784a4bfedd1653"), + ciphertext: &hex!("c0a62d77e6031bfdc6b13ae217"), + tag: &hex!("a794a9aaee48cd92e47761bf1baff0af"), + }, + TestVector { + key: &hex!("97431e565e8370a4879de962746a2fd67eca868b1c8e51eece2c1f94f74af407"), + nonce: &hex!("17fb63066e2726d282ecc610"), + plaintext: &hex!("e21629cc973fbe40176e621d9d"), + aad: &hex!("78e7374da7c77be5938de8dd76cf0308618306a9"), + ciphertext: &hex!("80dbd469de480389ba6c2fca52"), + tag: &hex!("4e284abb8b4f9f13c7497ae56df05fa5"), + }, + TestVector { + key: &hex!("2b14ad68f442f7f92a72c7ba909bcf995c827b439d39a02f77c9bf8f84ab04dc"), + nonce: &hex!("4c847ea59f83d82b0ac0bc37"), + plaintext: &hex!("b3c4b26ebbfc717f51e874587d"), + aad: &hex!("8eb650f662be23191e88f1cd0422e57453090e21"), + ciphertext: &hex!("3e288478688e60178920090814"), + tag: &hex!("a928dc026986823062f37ec825c67b95"), + }, + TestVector { + key: &hex!("11f41bf7d4b9ac7b0035ce54481ed1502ff05cfae02ffba9e502f61bfe785351"), + nonce: &hex!("06f5cf8c12c236e094c32014"), + plaintext: &hex!("bee374a32293cad5e1b28419b3"), + aad: &hex!("d15cbde6290b7723625c99ffa82a9c4c03ed214d"), + ciphertext: &hex!("3f8122deb6dbe0ff596441203d"), + tag: &hex!("60ef7f3723710b9ab744f8eea00267f7"), + }, + TestVector { + key: &hex!("18ca572da055a2ebb479be6d6d7164e78f592b159cdea76e9fe208062d7b3fa1"), + nonce: &hex!("1b041e534ae20748262f3929"), + plaintext: &hex!("cda2fa0015361ecf684c6ba7d1"), + aad: &hex!("e8a925d7ce18dd456b071cb4c46655940efbe991"), + ciphertext: &hex!("740d8d578e2e7522c31019f471"), + tag: &hex!("f2eeb5af1bfedd10570a137fe2566c3f"), + }, + TestVector { + key: &hex!("0de2ac5bfec9e8a859c3b6b86dde0537029cdca2d0844bf3e1d98f370e199be1"), + nonce: &hex!("1778e308e0221288f1eb4c5a"), + plaintext: &hex!("575d93a3416763cbd371b5a671"), + aad: &hex!("1362264f5655f71986aa788efd48f6fc13bb6ab4"), + ciphertext: &hex!("8f8df7ca83bf876b63c78e2c9a"), + tag: &hex!("16c74e315aab97efafbe95c9dcaa2d0c"), + }, + TestVector { + key: &hex!("b381535a085bc4808fa7a139c7204e8a87c7145dfc8f3900df1fa9a9844fab35"), + nonce: &hex!("21ddc54d3c633f4a344a0e42"), + plaintext: &hex!("e4d958cee583010bbfd3a53021"), + aad: &hex!("7ac3ba600e08363ddb57c45a8670bb4abb869db0"), + ciphertext: &hex!("c42c81a312759cdb032aafe852"), + tag: &hex!("0c472591db3df8a7c67164591542dcc9"), + }, + TestVector { + key: &hex!("29f21e5029ea4964b96dc6f4c34b2df4cce02f2fcf0f168ffd470e7858e0a0ad"), + nonce: &hex!("63a1c1ccc328280a90ff96fe"), + plaintext: &hex!("dc12113764c13c21432ca1ba33"), + aad: &hex!("454f447433f0948581956c4be1b19d932e89b492"), + ciphertext: &hex!("1cb45aac5def93daef806b781e"), + tag: &hex!("f4b0723c89607b66c392049ba042db63"), + }, + TestVector { + key: &hex!("2733d3aa52a9d70a9fbd6ce2364bb5f9004902aa5eeb17446e08f2bdcc41db15"), + nonce: &hex!("196c4addb84a58beb3674a7a"), + plaintext: &hex!("cbc50cafda2544bcd291e8a025"), + aad: &hex!("c9826fe31f29b55b9d0f9da9795869a1a98befe5"), + ciphertext: &hex!("7a89cc58ccb97ad3e54ca4a9c8"), + tag: &hex!("3990d9aba210182996fdbd91c2ae4801"), + }, + TestVector { + key: &hex!("0c4b9005b407415c19672bcd0ebe169f66fe404f22529baf55568e0901e94922"), + nonce: &hex!("e51381e959a1f5688c938576"), + plaintext: &hex!("c6179bd3451d9299b727e8bd0a"), + aad: &hex!("0b512faeb4da740dcc1e30d3c7ea61035e8570b7"), + ciphertext: &hex!("4d3fe086c990f16020b4c5eed6"), + tag: &hex!("9ff2297845814719f851ab0943117efb"), + }, + TestVector { + key: &hex!("fee442ba37c351ec094a48794216a51d208c6a5ba0e5bdb8f3c0f0dfc1e4ed63"), + nonce: &hex!("a666f2f0d42214dbaa6a2658"), + plaintext: &hex!("a2cf3ea0e43e435261cb663a3b"), + aad: &hex!("7198c12810345403862c5374092cc79b669baecc"), + ciphertext: &hex!("713d4050f8c7fd63c0c1bf2ad9"), + tag: &hex!("250a35e2b45ba6b0fe24512f8213d8cb"), + }, + TestVector { + key: &hex!("77f754d0cf7dbdaf75cfe965ab131e8cd39087ee6d986dec4ad2ff08ebd7f14b"), + nonce: &hex!("e28a14f3107ca190d824ed5f"), + plaintext: &hex!("54a97a74889e55d8043451c796"), + aad: &hex!("1decf0cbc50a9da6dad4a785a941e4b95ce5aaa8"), + ciphertext: &hex!("eedbf8dd81eb19184589dcb157"), + tag: &hex!("7749edd752fab7e50dbc3b0b47678bf6"), + }, + TestVector { + key: &hex!("0523f232001e68bd65a79837bbaf70ec2e20851301d8e12fddb5926acb2100cb"), + nonce: &hex!("2bb8d5cb3ceb15107582e1fa"), + plaintext: &hex!("6b4cdc9f9c5082d86a1d2e68fe"), + aad: &hex!("1f55bba71cb63df431ef8832c77499ee3c502067"), + ciphertext: &hex!("079fe90ef517ed2f614a3cd8ce"), + tag: &hex!("539c30590a2527f1d52dfae92920794c"), + }, + TestVector { + key: &hex!("54c56ee869ebb112a408717eb40af6937fe51eb061b42277a10537e7db346b6a"), + nonce: &hex!("5bfb63e2f3e5b2e1b4343480"), + plaintext: &hex!("75f9496b8d0ca96ed3af02dcab"), + aad: &hex!("740ab07b9c5de2afa37f0788ae5230535c18203d"), + ciphertext: &hex!("827902e58c4c8b7af976f61842"), + tag: &hex!("036ee6473c2138f2a2c2841438cb0edc"), + }, + TestVector { + key: &hex!("d968ffdbed6ffc259b4310e2e97e42d877ef5d86d2169928c51031983779a485"), + nonce: &hex!("633d0d8d3613c83b40df99dd"), + plaintext: &hex!("08cfc65fea9b07f0c01d29dfdf"), + aad: &hex!("9aadc8d8975ec0a3f5c960ce72aaec8ef0b42034"), + ciphertext: &hex!("7b450f162bdedc301b96a3ac36"), + tag: &hex!("970d97344b1451f3f969aeb972d352e6"), + }, + TestVector { + key: &hex!("5f671466378f470ba5f5160e2209f3d95a48b7e560625d5a08654414de23aee2"), + nonce: &hex!("6b3c08a663d04132243dd96c"), + plaintext: &hex!("c428592d9f8a7f107ec4d0df05"), + aad: &hex!("12965559c31d538f937bda6eee9c93b0387318dc5d9496fb1c3a0b9b978dbfebff2a5823974ee9d679834dbe59f7ec51"), + ciphertext: &hex!("1d8d7fe4357080c817303ce19c"), + tag: &hex!("e88d6b566fdc7b4fd62106bd2eb806ec"), + }, + TestVector { + key: &hex!("fbcc2e7faa4295080e40b141bef829ba9d34e0691231ad6c62b5109009d74b5e"), + nonce: &hex!("7f35d9ec651c5b0966573e2f"), + plaintext: &hex!("cdd251d449551fec080425d565"), + aad: &hex!("6330d16002a8fd51762043f2df06ecc9c535c96ebe33526d8faf767c2c2af3cd01f4e02fa102f15ce0236d9c9cef26de"), + ciphertext: &hex!("514c5523024dd4c7d59bd73b15"), + tag: &hex!("d3a399843e5776aa348e3e5e56482fff"), + }, + TestVector { + key: &hex!("04ef660ec041f5c0c24209f959ccf1a2a7cdb0dba22b134ea9f75e6f1efdae4a"), + nonce: &hex!("0f5f6fbca29358217c8a6b67"), + plaintext: &hex!("0835b312191f30f931e65aa05f"), + aad: &hex!("505e205d13ec945391c7d6516af86255e82f38433f40404d4f1e42d23b33eb9e6dea5820dad60622d3a825fc8f01a5d2"), + ciphertext: &hex!("5ddc0f5963f0290c1a0fb65be7"), + tag: &hex!("106d1f8d26abe4b4b1e590cd5d85e737"), + }, + TestVector { + key: &hex!("42d3ff74284395fb9db9b8c7a444fa400f7fc6b985a7fec2478667c7f17cf3ba"), + nonce: &hex!("89230fbed59d1226a093ad28"), + plaintext: &hex!("d8339e3618ba57a243a27c85d6"), + aad: &hex!("60342f97310446266b2e47b18e008979d07fc181151ac0939b495e7f31de1d0e74042532840ab91686efd7a402d27a94"), + ciphertext: &hex!("9bb6fa36fa167016109d521ac0"), + tag: &hex!("600909ef32ca62951ecbdc811caa7778"), + }, + TestVector { + key: &hex!("e115c6468606a5f9b8e9a7c220d7d7684d686c9210a669770b6e4bf24447cd17"), + nonce: &hex!("029c7c9ee2d3ab26843e8b41"), + plaintext: &hex!("7abf84842f9867cfc5eabc7032"), + aad: &hex!("1befd9f97f99fc096deafde5e158ac86716c0ba32454988fe48ba4737684361849a221c03fc0948cb25b5f29d6a0cb2a"), + ciphertext: &hex!("851c7047fb09646fbddb824531"), + tag: &hex!("d0ac4110c8d768f0a804ecda387cfa30"), + }, + TestVector { + key: &hex!("56552f0cef34673a4c958ff55ad0b32c6ababa06cb3ae90178ab1c9a1f29c0e5"), + nonce: &hex!("b34d24935407e8592247ffff"), + plaintext: &hex!("dbd6cc358b28ab66a69f5238d4"), + aad: &hex!("b199437da189486a8fd1c2fa1fe3ebbb116f0ef41415bb7c8065272fb0b2fe8edca9cd0d4255d467e77f2834be557474"), + ciphertext: &hex!("76dc8d035e5ca4001e4e3fcb18"), + tag: &hex!("49c01f735da1131cd42b01b746fd38de"), + }, + TestVector { + key: &hex!("d4f405ba556e6fe74b7e6dbdd7a8eae36376d1ca7a98d567d108729aeae5c326"), + nonce: &hex!("df6637c98a6592843e0b81ef"), + plaintext: &hex!("abe87641e9a5169f90179d3099"), + aad: &hex!("a5328cbabdfe6c3c1d4f5152189072dade71e2bacd857d3ce37ee9e3161eb0f20de5a29b7999fd9c7c60cdc03751bd1b"), + ciphertext: &hex!("06f9cf9677745e78c6c02bf06b"), + tag: &hex!("5a3a76da0703c24a9588afb2ac1a9e13"), + }, + TestVector { + key: &hex!("4f667f65ea4569264456e25de498579036d6a604c18baf770bb626d8a1c68e4f"), + nonce: &hex!("43e27d275abefdd45137c8ff"), + plaintext: &hex!("eaa2498ce27e5658489381b6ec"), + aad: &hex!("264b807b4631d7c87ee9f1507082f5af9218f531b4630141f3c94939aa7cf81c71ea540783995560bf7e6e02d196227f"), + ciphertext: &hex!("bac018bf2e7090e7f217ab3365"), + tag: &hex!("13e5a16a9ce7a88cda640de2c4fdc07e"), + }, + TestVector { + key: &hex!("f5624a166759ef0b8168af6565649f7797fa92476e008c407458101e75831312"), + nonce: &hex!("521ca79ffc8930349abfc052"), + plaintext: &hex!("1fab3def2ea13e815f8746093b"), + aad: &hex!("6e2771ecd637361cb6b947148910f7d9206d6af176c510bb5dd5bc9b97ac015fb05537affbc1756625715374172fb456"), + ciphertext: &hex!("ca72ff15a7eb62a2839bcf0c43"), + tag: &hex!("475fff6d9e2382583c9614020844b92a"), + }, + TestVector { + key: &hex!("ac1383a3c783d3d0667e944cbe1a6159647b96afa922557eb1cb6407546b98ca"), + nonce: &hex!("70366112dbe1bd905b900e3a"), + plaintext: &hex!("b8dd871f9d866867efbe551c3b"), + aad: &hex!("b7c1865927737bee802415277cf1a25b7380774a9d27b6a3253f077d36e9c4142df2bbbf3c03414ac09161626ce9367c"), + ciphertext: &hex!("ba181874380841791f64881534"), + tag: &hex!("c5641edf42c446873372bbbde1146642"), + }, + TestVector { + key: &hex!("f37499d9b6ad2e7618e30a23082673008f3ae1938b9397c02a4da2453fb7e403"), + nonce: &hex!("18e112ea6a998d6f9705f7e0"), + plaintext: &hex!("31560b2114a248ffe0696fa130"), + aad: &hex!("736f1a71fb259f46c6519bb87451f238f47d80c74a016604499b02568f1c7bedf70f9597d7b62c1698c4f2631f4e9706"), + ciphertext: &hex!("0163f558be0142ebabde29a7bc"), + tag: &hex!("45579ce07ee64cdac3a7a42109ff44e7"), + }, + TestVector { + key: &hex!("50b7f5118ef7ee22b107d93ceab9881ef9658931e80385d1ae92501b95e47d62"), + nonce: &hex!("d5113665039169978b7dc4db"), + plaintext: &hex!("9ba4cd5e600277f4c786ce827e"), + aad: &hex!("68ff6c63e94cb7dd2b8413662a56c88dc130b79b8b2e2388c1089b61fa51ea37819109b5ef64da1250f5d6b5d74cc392"), + ciphertext: &hex!("67842199482b28be56f7570d11"), + tag: &hex!("79e03841843fe32337b7c7409a2153bc"), + }, + TestVector { + key: &hex!("d396941c9c59e6a7bc7d71bd56daf6eabe4bfb943151cdb9895103384b8f38b4"), + nonce: &hex!("f408f8c21f3825d7a87643ed"), + plaintext: &hex!("dc8ad6a50812b25f1b0af70bee"), + aad: &hex!("947bd9a904e03fdd2c91d038d26d48ac6e32afcad908eacd42a25f6240964656d5a493242d3f8a19119a4cd9957d9c42"), + ciphertext: &hex!("57e6d821079bb8a79027f30e25"), + tag: &hex!("de8c26d5a3da6be24b3f6ea1e2a0f0c6"), + }, + TestVector { + key: &hex!("eca22b3a29761fd40031b5c27d60adbcfac3a8e87feb9380c429cfbcda27bd06"), + nonce: &hex!("4e6fe3d1f989d2efb8293168"), + plaintext: &hex!("44d6a6af7d90be17aac02049a4"), + aad: &hex!("29beb1f0bb6b568268b9c7383991a09fd03da7e1639488169e4f58ec6451cad6d4c62086eee59df64e52a36527733d8c"), + ciphertext: &hex!("9aaa295bb3db7f6335a4c8cf2f"), + tag: &hex!("55f7577163a130c0dbcde243ef216885"), + }, + TestVector { + key: &hex!("fa3ce8b099f3a392624bc433b5265235b65c0952cfc54817be2a8003d057903c"), + nonce: &hex!("3168b4e50efe96b3d3aed600"), + plaintext: &hex!("84ed3ccd428d3783ecea180b3b"), + aad: &hex!("d451fa64d73b7d7eee8f8143c40bab8e3f7a58ee018acda23224974f64ac7e1e389f5058ec08664bf56492b932d15f42"), + ciphertext: &hex!("ee2bd527568a4e7537c8f939b6"), + tag: &hex!("f4615f7dfdffec8a2d52c992456210ad"), + }, + TestVector { + key: &hex!("ff9506b4d46ba54128876fadfcc673a4c927c618ea7d95cfcaa508cbc8f7fc66"), + nonce: &hex!("3742ad2208a0484345eee1be"), + plaintext: &hex!("7fd0d6cadc92cad27bb2d7d8c8"), + aad: &hex!("f1360a27fdc244be8739d85af6491c762a693aafe668c449515fdeeedb6a90aeee3891bbc8b69adc6a6426cb12fcdebc32c9f58c5259d128b91efa28620a3a9a0168b0ff5e76951cb41647ba4aa1f87fac0d97ac580e42cffc7e"), + ciphertext: &hex!("bdb8346b28eb4d7226493611a6"), + tag: &hex!("7484d827b767647f44c7f94a39f8175c"), + }, + TestVector { + key: &hex!("b65b7e27d552395f5f444f031d5118fb4fb226deb0ac4e82784b901accd43c51"), + nonce: &hex!("2493026855dd1c1da3af7b7e"), + plaintext: &hex!("8adb36d2c2358e505b5d214ad0"), + aad: &hex!("b78e31b1793c2b758494e9c8ae7d3cee6e3697d40ffba04d3c6cbe25e12eeea365d5a2e7b46c4245771b7b2eb2062a640e6090d9f81caf63207865bb4f2c4cf6af81898560e3aeaa521dcd2c336e0ec57faffef58683a72710b9"), + ciphertext: &hex!("e9f19548d66ef3c16b711b89e2"), + tag: &hex!("e7efc91bbf2026c3519010d65628e85f"), + }, + TestVector { + key: &hex!("8e4f8859bc838f6a2e7deb1849c27b78878285e00caad67507d5e79105669674"), + nonce: &hex!("e71d0ebb691a4c31fdd9879c"), + plaintext: &hex!("bd1713d8d276df4367bf3cbb81"), + aad: &hex!("47ca6cef3ca77997ef1b04e3721469be440ad6812aa3674ae92ca016b391d202e29932edfa83029eccae90bd8dbe4b434e7304b28fe249b380b2c3c49324fd5b3e469e3e135abc1c9fd77828b409c7482e6a63461c0597b14e5c"), + ciphertext: &hex!("eecbfb74e314628b0e3f827881"), + tag: &hex!("c9ea890294d7e10f38b88e7c7493c5f8"), + }, + TestVector { + key: &hex!("2530cdcb2a789000822588a31bdc87c09234838da2d6ae1259c7049186525f11"), + nonce: &hex!("0c509faa257dbb0e743a53ac"), + plaintext: &hex!("a8edc524930ce4c20897c66f75"), + aad: &hex!("92a92cb8c1984ede806028cc45ac95574167ee83f03a707cc4b0fb8ad70907e0016e38b650f4a75bc83a625e3c670701d43bfb0326d1c4fe7c68410733c0c874c920389d164bf67a9032e2e837f5e9e324b97932d1f917ba7dca"), + ciphertext: &hex!("1f658c7a1f41152b22999ed1b7"), + tag: &hex!("cf3e4fef775d9c6ff3695be2602a90d8"), + }, + TestVector { + key: &hex!("54c31fb2fb4aab6a82ce188e6afa71a3354811099d1203fe1f991746f7342f90"), + nonce: &hex!("f0fe974bdbe1694dc3b06cc6"), + plaintext: &hex!("fbb7b3730f0cd7b1052a5298ee"), + aad: &hex!("2879e05e0f8dd4402425eabb0dc184dcd07d46d54d775d7c2b76b0f76b3eed5f7ca93c6ae71bf509c270490269ea869ed6603fdf7113aa625648ab8ed88210f8b30ec9c94bca5757ca3d77491f64109101165636b068e3095cb4"), + ciphertext: &hex!("3a5a2a8aa93c462cfb80f1f728"), + tag: &hex!("59ef9d54ee01fb6cd54bd0e08f74096f"), + }, + TestVector { + key: &hex!("8084061d0f7858a65c3a3557215ed46f1590278ca97a45dcb095d2a0979f2e3f"), + nonce: &hex!("6973898b1a8f72856415675b"), + plaintext: &hex!("200d0445cb09eb52f54d2f74c6"), + aad: &hex!("8b543e294546848c3308ccea302f0238b7dffc1706d03657c190ea745cc75bcd5a437993e787828ea7fe42fea1d5c6f7229a72ea65f0d0c190989a590ab49c54726633282c689eef8cf852af263b5edf63e449fd5440730003ca"), + ciphertext: &hex!("ec242c358193ca6187c89aa7a5"), + tag: &hex!("967428ac6956525ba81d5901ed259407"), + }, + TestVector { + key: &hex!("2aad7db82df4a0d2ec85218da9d61ade98f65feeb8532d8eb728ef8aac220da6"), + nonce: &hex!("029ac2e9f5dc3d76b0d1f9df"), + plaintext: &hex!("ba363912f6207c54aecd26b627"), + aad: &hex!("d6f4b6232d17b1bc307912a15f39ccd185a465ee860279e98eb9551498d7b078271ebabdda7211e6b4ab187043171bc5e4bf9ffcf89a778430e735df29410a45ca354b0003433c6bc8593ee82e7c096a32eac76d11daa7d64150"), + ciphertext: &hex!("bfcad32611da275a0f0821517c"), + tag: &hex!("9ea37bdcaafad69caf06d67fb18dd001"), + }, + TestVector { + key: &hex!("f70bb950ab56f12f1efc2376d32a59d16ef3ef5969e0106ab40cc314c9b0c7e8"), + nonce: &hex!("3b3b29ba422c2bacafeeb8b3"), + plaintext: &hex!("029929277043dc0379f152a484"), + aad: &hex!("464ac0c84b9ff17a0e7c39a65f89682a89b8787553a6275f0d55effaabef2114072c739f9831a5d5a5133ae4de14eb51346b318b255a1bff57e50c433e1e69a00fe1a8b6f6b621d515d670d89e148f6b65d6eb4c54878cb819ce"), + ciphertext: &hex!("c0b97d6d1a95d708d6dc7d2b95"), + tag: &hex!("322eb4395bf4d4dd070b8f9f6195f8ee"), + }, + TestVector { + key: &hex!("f4950f01cb11fdd9afb297f7aa852facfac354ff96557befa5f657678de6cefb"), + nonce: &hex!("aba7d864f29cbc449cd93e33"), + plaintext: &hex!("e6daf59ef54ac7405984fc4c4e"), + aad: &hex!("852f624cea7a8c20e189e0c79f578c0d770c4bf7c4e691649eba992f6de89d7bf2078aff94803a3dc62628e02a80a01957722e2a931fc56283d84ab68ce11ae867835c2d9700df130048ea8eaaca41f1a9059be2acaea6e0f7f2"), + ciphertext: &hex!("d01d36ff8009b4082279abb906"), + tag: &hex!("d9a36c8008493bd95c09049299cbd075"), + }, + TestVector { + key: &hex!("714261ef4f02fb4efb0e6b5aed96d7b3ceac6551a57cf679da179c01aac5ee0e"), + nonce: &hex!("3b7d15c7fd877461a789255a"), + plaintext: &hex!("815de8b0382fe60cb0d3782ee9"), + aad: &hex!("7621e58152336ee415f037f2e11581fe4da545c18d6e80177d5ab5dda89a25e8057d6fccec3757759a6e86e631080c0b17baa8be0b8fe579d3bfa97937ee242b6faacfc09425853df4dc26bc263ed1083a73ffc978c9265f8069"), + ciphertext: &hex!("29c566ea47752a31a380fd0e7c"), + tag: &hex!("b279340a384dbbae721c54e9183b3966"), + }, + TestVector { + key: &hex!("53459ba5a2e49d1a7c2fb6ad9e6961b4dbe5158cb9266eff425d6dcccaaf8073"), + nonce: &hex!("3c97dc635a75fbe2c33c9a41"), + plaintext: &hex!("03fbfe5842ed781990ca8be728"), + aad: &hex!("7fe308afe58a927680bee3368301f4dc7c47811fc09f1b9922a092a497b9c6b67c857fdcc32da1011acb110b3c1475bef303f1a609479485cc400ee8f38381c45d078708ad49f226f95dd9c81478d1ee2b53c3b906d96f8ddd76"), + ciphertext: &hex!("5865e5a1ec711732a4ee871bff"), + tag: &hex!("856a653ec214178096bed423e30a36e9"), + }, + TestVector { + key: &hex!("f0501583c226d2519ed23fcc6f2cffd2f013eb91aa07b3a5a2073d6e2bd10cef"), + nonce: &hex!("29a922ad9bdeddc2e298b99f"), + plaintext: &hex!("035eb6922345c02a81435d9e77"), + aad: &hex!("d84f54bac09ea92afe0a7335cb0bb5f68425490fd2fb6c3b99218f49856ed427ec902e510b899d54951fe84cdbfd112608d1e999f64ecc9cd4be3a0114c1c34875dbf35a1b0be421659f99d69b32e968cebfca6f95837e3edeb4"), + ciphertext: &hex!("095971f99af467805a62bfb882"), + tag: &hex!("d5ff2b7beac260e517ea3eca13ff1e77"), + }, + TestVector { + key: &hex!("78e6789b596c71cb3becc833cf823d2ebb18ca2e26c27e26a55ef95df7353971"), + nonce: &hex!("65da9c7a9f17b11246bcf8db"), + plaintext: &hex!("003e82a147df3c953400f87ab5"), + aad: &hex!("d49aee7ffd31e7c8d831d97ae894a00473adbc5071f6099d567caaef85c295d5143a1316ff82753cc35d3efc60f7e5101ddd811336b404d598f6c439cce6b47fcbebb15d1c342e4151b355025a03b4397260b4a7e6444fa57b5b"), + ciphertext: &hex!("abcceced40209fc30a5590fee8"), + tag: &hex!("0a203973b81375949ebd932597efd495"), + }, + TestVector { + key: &hex!("816b3e6ca31d59688c20bcd1fa4285197735d8734289ca19a4730e56f1631ccf"), + nonce: &hex!("4c191ac994f86985c180ccd4"), + plaintext: &hex!("b2060dd86bc307133b7d365830"), + aad: &hex!("b3dcd643c68ccce186570c63288c8722b8a13dfaf9e71f44f1eeb454a44dddf5f955540cd46c9f3b6f820588f71936d7a8c54c7b7bc43f58bb48e6416149feae7a3f8d8198a970811627489266a871e8cb87878cdb3a48be65f5"), + ciphertext: &hex!("53e65880ad0012a75f1188996f"), + tag: &hex!("9ca8a71a45eb4402a6b03106bae330d1"), + }, + TestVector { + key: &hex!("a07ba57478061bd7abddd762971cf2e47141891f76c3d1c150b53eee5704557d"), + nonce: &hex!("5adfb85b2d9e239c5146501d"), + plaintext: &hex!("67c8824c1837cfdec6edcd719c"), + aad: &hex!("937b3ed73e67ca0b02f9eb736a668362d4d0447c15f6083099a7f90c7c49318dd72f6baa74da22ff53b56c24fb9a1b1d6c4e29f4ac4d917220ebe3c8d760999da7be9e1e8f6a171133640c9196f9ee3cdb76a5a342a95a05c8c4"), + ciphertext: &hex!("1eb85c6682850e849eb37927e5"), + tag: &hex!("8079f705cf551a5484132cd0f0c5297c"), + }, + TestVector { + key: &hex!("268ed1b5d7c9c7304f9cae5fc437b4cd3aebe2ec65f0d85c3918d3d3b5bba89b"), + nonce: &hex!("9ed9d8180564e0e945f5e5d4"), + plaintext: &hex!("fe29a40d8ebf57262bdb87191d01843f4ca4b2de97d88273154a0b7d9e2fdb80"), + aad: b"", + ciphertext: &hex!("791a4a026f16f3a5ea06274bf02baab469860abde5e645f3dd473a5acddeecfc"), + tag: &hex!("05b2b74db0662550435ef1900e136b15"), + }, + TestVector { + key: &hex!("c772a8d5e9f3384f16be2c34bf9afd9ebf86b69e6f610cd195a9db169e9be17e"), + nonce: &hex!("9b8e079f9971d7352e6810a3"), + plaintext: &hex!("7f13fcaf0db79d792823a9271b1213a98d116eff7e8e3c86ddeb6a0a03f13afa"), + aad: b"", + ciphertext: &hex!("d29e2bf3518668a14f17a3e4e76e1b43685734b801118d33a23238f34d18aa40"), + tag: &hex!("8e02b0b7d172cf5e2578f5b30fac2e7a"), + }, + TestVector { + key: &hex!("d5924b31676e2354fe7dafffaf529749598ea1bf5e4c44f5b60240e09d8036aa"), + nonce: &hex!("5d847784f0bcd79cb84fcf1d"), + plaintext: &hex!("6fd80c8f0d4de081a93c16b84dec697a1e4f9d80a6af497c561572645eac0d63"), + aad: b"", + ciphertext: &hex!("282cc9d2308a443019cfdc4d79854accc7731ee36902bafe3ffaca6484327b82"), + tag: &hex!("4dc5e0f2ab91bdfd31f2bdcf06af9667"), + }, + TestVector { + key: &hex!("b328c6d7946221a08c4f0509b52992a139890cdd8eae1956851f110c49602cb5"), + nonce: &hex!("1a433c33ca12ce26cf3dffff"), + plaintext: &hex!("217bdc314a4d335c72b5267b424fc8e31f4bb118e6cfaeacf5548f4ba8f51980"), + aad: b"", + ciphertext: &hex!("a322944e07bf84ab424ffa75fd0309e8691c9036b08f344ba76ce0774f43b351"), + tag: &hex!("14dd6b1c2b224533ccc9fee8d2881358"), + }, + TestVector { + key: &hex!("c2080965d21d229c0d0d6c56cbce83880120c21a48172a64560b90dc4ce1ffbe"), + nonce: &hex!("928d6c0195f5f0974f38730b"), + plaintext: &hex!("864397271e1b242aa1dff38e78aa89353e1554ba907318a0aaad44f26fcd567d"), + aad: b"", + ciphertext: &hex!("7de4f941f44bd0f268b2a47b9c4927cc10537bbed739d52ab099fde4033041d1"), + tag: &hex!("b51a59931817257619e7be1091128c49"), + }, + TestVector { + key: &hex!("dd6b7e2584edf1f1e6c2c0dd1f72161a92d2cba99856554f820de1256d48c099"), + nonce: &hex!("fe9d553c75067e8dbae1ab67"), + plaintext: &hex!("f9f86f7762859f11d6e7ef56178657ddcded532843446f86a23eac35aa2dd3c0"), + aad: b"", + ciphertext: &hex!("f7aaa1711c8092783b05b4e5e6c9c6944e991bd59c94b9d0356df00a66e2db5b"), + tag: &hex!("c61edd176c8322a01d8c5f3df09252e9"), + }, + TestVector { + key: &hex!("37f39137416bafde6f75022a7a527cc593b6000a83ff51ec04871a0ff5360e4e"), + nonce: &hex!("a291484c3de8bec6b47f525f"), + plaintext: &hex!("fafd94cede8b5a0730394bec68a8e77dba288d6ccaa8e1563a81d6e7ccc7fc97"), + aad: b"", + ciphertext: &hex!("44dc868006b21d49284016565ffb3979cc4271d967628bf7cdaf86db888e92e5"), + tag: &hex!("01a2b578aa2f41ec6379a44a31cc019c"), + }, + TestVector { + key: &hex!("a2ef619054164073c06a191b6431c4c0bc2690508dcb6e88a8396a1391291483"), + nonce: &hex!("16c6d20224b556a8ad7e6007"), + plaintext: &hex!("949a9f85966f4a317cf592e70c5fb59c4cacbd08140c8169ba10b2e8791ae57b"), + aad: b"", + ciphertext: &hex!("b5054a392e5f0672e7922ac243b93b432e8c58274ff4a6d3aa8cb654e494e2f2"), + tag: &hex!("cf2bbdb740369c140e93e251e6f5c875"), + }, + TestVector { + key: &hex!("76f386bc8b93831903901b5eda1f7795af8adcecffa8aef004b754a353c62d8e"), + nonce: &hex!("96618b357c41f41a2c48343b"), + plaintext: &hex!("36108edad5de3bfb0258df7709fbbb1a157c36321f8de72eb8320e9aa1794933"), + aad: b"", + ciphertext: &hex!("b2093a4fc8ff0daefc1c786b6b04324a80d77941a88e0a7a6ef0a62beb8ed283"), + tag: &hex!("e55ea0456af9cdff2cad4eebbf00da1b"), + }, + TestVector { + key: &hex!("6fb2d130bbad1924cab37d071553b12169e978a805bf74cb4c23d5ccd393d7bb"), + nonce: &hex!("76826741225a391fdce4d3b6"), + plaintext: &hex!("c49b80080e2efeb5724b9e5b53ba0c302e97bd16f1a6bbec01e1ca6c35a42a3c"), + aad: b"", + ciphertext: &hex!("62fbe5466a7ff83ff719f4927e00e9319e1bb7e835c5d6b4e9d4bc5a8d6e2beb"), + tag: &hex!("df72da7a66cb5257836f3c19ecadcd55"), + }, + TestVector { + key: &hex!("402e8113970257d9437807620098370243536a105cca4fbc81a1ff2d48874f48"), + nonce: &hex!("c924c19c4d14905a2bdf63bf"), + plaintext: &hex!("917b9585f65e59bf4d242bb0802966045dd29fbc66911277baecdfcc818c3c35"), + aad: b"", + ciphertext: &hex!("5b6594edcddbb338f4e813687f4f23a75a64c21e3cf5d2e7c9af0f7e3ee3e616"), + tag: &hex!("f1cccd93a4411247c8b6830addd72c6f"), + }, + TestVector { + key: &hex!("2aac499cb0eb72b4598acff4330df6cd764978997d5ace51da88e0c18671bde9"), + nonce: &hex!("fd16cdc39d7f0b92e1f95c97"), + plaintext: &hex!("e7b75bfa35c9a004d0b68265623a9b06b6d4493ea0ad4f6c777ba5add8c7bbbb"), + aad: b"", + ciphertext: &hex!("c3d0a0f7ce9720c95aac86151aad634884ddfa62df58f18394537f6504d9a8aa"), + tag: &hex!("76749a1ec70236b267fc340d5fbb6da3"), + }, + TestVector { + key: &hex!("a2a502d6bb19089351e228d5cbff203e54fc31f2772253df08557875d964c231"), + nonce: &hex!("0ebb5af4a462a1e6ded7164a"), + plaintext: &hex!("bbecc89450c07b8de631155e5d7cc7a9d26376bb57d7458d49b4c36e140490f3"), + aad: b"", + ciphertext: &hex!("fd09c950890441fcaaa8809a8998079abb88741c6672abae12383ffd724f8299"), + tag: &hex!("22fac246058bf142c5f26812a635b480"), + }, + TestVector { + key: &hex!("ce2d289e20c76f75c135c8118d5cbf5f2828026f0b639588a3eb4ad752cea548"), + nonce: &hex!("bb08526dd8bd1c3bb58d0999"), + plaintext: &hex!("56f5db1e796a0c4633a8d570182c39e3c8451e7ba485b98d38a2c926a1b92a46"), + aad: b"", + ciphertext: &hex!("a41005df18734d4f3f99f19ef8fc43b16ef431207cb0466341bf164b58e23533"), + tag: &hex!("a45c2a1ef6aec75cc22d71807dab3c27"), + }, + TestVector { + key: &hex!("66e418d0ec97b420b1b5365d1b6d5cd7c5ac1a5653739120d4aec3c94c93c287"), + nonce: &hex!("989f94480266e3652488184e"), + plaintext: &hex!("e5052b19d7f827fd60f45c8925809fd2217ec4d16aa89bbf95c86a1c1e42bd36"), + aad: b"", + ciphertext: &hex!("f341630574ee92942cf4c5ecd3721ae74b32c557379dfe8351bd1c6661a240da"), + tag: &hex!("e85fb655ef432e19580e0426dd405a3e"), + }, + TestVector { + key: &hex!("37ccdba1d929d6436c16bba5b5ff34deec88ed7df3d15d0f4ddf80c0c731ee1f"), + nonce: &hex!("5c1b21c8998ed6299006d3f9"), + plaintext: &hex!("ad4260e3cdc76bcc10c7b2c06b80b3be948258e5ef20c508a81f51e96a518388"), + aad: &hex!("22ed235946235a85a45bc5fad7140bfa"), + ciphertext: &hex!("3b335f8b08d33ccdcad228a74700f1007542a4d1e7fc1ebe3f447fe71af29816"), + tag: &hex!("1fbf49cc46f458bf6e88f6370975e6d4"), + }, + TestVector { + key: &hex!("2c11470e6f136bec73351619288f819fb2bbba451857aadfb78384074612778a"), + nonce: &hex!("4e6cc2bcc15a46d51e88958d"), + plaintext: &hex!("3b3186a02475f536d80d8bd326ecc8b33dd04f66f8ba1d20917952410b05c2ed"), + aad: &hex!("05d29369922fdac1a7b37f07953fe175"), + ciphertext: &hex!("6380945a08977e87b294b9e412a26aebeeb8960c512439bac36636763cd91c0c"), + tag: &hex!("1029a3c4be1d90123c1b404513efde53"), + }, + TestVector { + key: &hex!("df25ea377c784d743846555a10cfaa044936535649e94da21811bad9cea957b5"), + nonce: &hex!("35f5f8e950c1f57ad3dfb1fa"), + plaintext: &hex!("98941a807ac8f16eef0b3d3c7bbdfd55d01736c5b3360d92b4358a5a8919380b"), + aad: &hex!("28eb4677110ccb6edc8d2013dc8f46ec"), + ciphertext: &hex!("24a07532e981aaf3106eab8dfbb2d2078342e2eaee027e148f06aca68f6a1c50"), + tag: &hex!("131373ed4a0e3f584ae978d42daa6f3a"), + }, + TestVector { + key: &hex!("106168ea651f22c54196a06f1a10bcf4e620d93e4dc0824d798f44f9219c6177"), + nonce: &hex!("4064dcbd631cf20b05ae22de"), + plaintext: &hex!("b0d3da2b96b8889c92e445abbea4c6d0d5d44d7fbcc7dade4c92f6bcddbf06e1"), + aad: &hex!("a36e2fb9cd96a8ca9ae2b193aa498efd"), + ciphertext: &hex!("f55a6d8a6965ea451637bec7548cfb1ffe59fc0ce6ea6a937cb5dd32b3d45d5f"), + tag: &hex!("8d1bf2715041f817f11631fc9910c629"), + }, + TestVector { + key: &hex!("272d1649a3dd804de0962d3e07064a7054c00a6234ab1b0cdcf685ab394837e5"), + nonce: &hex!("955b5897f6b9806bbec5c33e"), + plaintext: &hex!("36e57c29c08c51ad7fa91c0416f976cfd011780eb44cc5abd34c7b431b093b8d"), + aad: &hex!("33e618ecbbe5eb0566df21c3c34b7e25"), + ciphertext: &hex!("cd6aeb345081dc0bb2c8b4d19b280658fb87c0f2bd0f4c9da694dc1feeb32f4e"), + tag: &hex!("dd37eac6bd6a4d3618241738779735d7"), + }, + TestVector { + key: &hex!("3dab6a51bb7af334dd4b79a7d139550c88f0778d43c21fc4ad33f983a13515cb"), + nonce: &hex!("362eaa67cab3d1ed48e9f388"), + plaintext: &hex!("3eb7f5f0a4ca9aa7000497602c6124433a60a8fcd91b20175b4ee87e6b10a2d7"), + aad: &hex!("52852150786e6547a2618e15c77110b6"), + ciphertext: &hex!("cc3316041b88733839249b756ffa00bbec6211942f604f26c4a35ed32e6eeaff"), + tag: &hex!("5936c5500240d50c0da0fcdc248f176e"), + }, + TestVector { + key: &hex!("0ea606521b935d5b4b66df89fb372d35c4d6d2c03767367e38de0d4c27761d56"), + nonce: &hex!("0d3168318a4f76392699640b"), + plaintext: &hex!("f450b36d6c49411897bce39001d73ff01b5e8566179e36dacac7064cab5c6270"), + aad: &hex!("3bd8849070cf034c4298f40f33b0b839"), + ciphertext: &hex!("3b15fad18726c4eaa70502b3f3b32c5092d1d92835e6460665fc50dda953a191"), + tag: &hex!("11fd3fddf61e010c17fbedd4bd5fb012"), + }, + TestVector { + key: &hex!("c8c4f9e0bd289ef1bd16104a8074fb073dd9035ab937ab076fb5801e2295aa2f"), + nonce: &hex!("be699d9d98ec1f724da8bd0f"), + plaintext: &hex!("49fe9407a719d41e658587809cfed7a5b49941c2d6378f3c0afe612f54f058a1"), + aad: &hex!("a985c7489732038c3190cb52be23737c"), + ciphertext: &hex!("17a9aaa6a3c68ba1f6cb26fdd6536c207e3c9ce58f43e4ecfd38d3387a798a0f"), + tag: &hex!("d832cb4814142562fedfe45b36126cb8"), + }, + TestVector { + key: &hex!("52d0f20b0ca7a6f9e5c5b8549d5910f1b5b344fc6852392f983558e3c593be24"), + nonce: &hex!("d5c618a940a5a5d9cc813f27"), + plaintext: &hex!("a9fed8a29355685321f978e59c40135309306cd41b25349fe671dc7990951c68"), + aad: &hex!("61823f7e39ed76143ca7249d149bdf57"), + ciphertext: &hex!("509c540e558d0bf0a3b776cddfbfddc15486748a7f9952b17c1cbd6869c263f4"), + tag: &hex!("42e35ee3f7119f87fb52b5d75b8ab8ec"), + }, + TestVector { + key: &hex!("5d291a8f1a6433a41076702d9d8a8c196e464550ed900ce8c2a36f4d10483954"), + nonce: &hex!("c4ba743ee692e5d00b5ae2c6"), + plaintext: &hex!("605d519b26182458fea68dddd86033390fc545f843ae817850a2a4574add015d"), + aad: &hex!("878fa6720ab30e0287f6903acd2dca19"), + ciphertext: &hex!("1c2f153f2374d3945cca9757dc18d9a15a93276526285a6e316ee32a72092c34"), + tag: &hex!("e7905e856c88c6ece4bb47781becf923"), + }, + TestVector { + key: &hex!("09e2724d4017cd57e967000e4da2cd5c5c18ccfb06c33b7ce62a7641e4bb0b73"), + nonce: &hex!("9ea18b420a10177289ab370b"), + plaintext: &hex!("6f5dfa86d5df4febd752265c56390049e7cda60c2644c84ab413932faad15b15"), + aad: &hex!("a8e77939423d5894d307fd60278d162a"), + ciphertext: &hex!("35e37a9b913eb58b72262e92d7584d44bf9a8442f1b2f3da3a5d05ec6a2a31e2"), + tag: &hex!("1a95023b1a4a3e885520ec79e1a3aef9"), + }, + TestVector { + key: &hex!("8544a9f4f6c0efdff3da90cfa3ee53fbe1f8de159d29537c803e1651da153718"), + nonce: &hex!("be406029a1d0c25d09af94cf"), + plaintext: &hex!("7e88a65646ed138b7c749366d16e41dbafd9987ad2373bb9d0b6ce0c1a4d6661"), + aad: &hex!("599dbb73897d045a1bd87385e60323a2"), + ciphertext: &hex!("38ffbf9ffff8d6a92090584e6dace1c6a47d3d5709a25e470557d5c8f5dd1851"), + tag: &hex!("d5b2e83c47df404de9a7cd95d3cbe7ab"), + }, + TestVector { + key: &hex!("35b9d2a5db3b06e7720cec794dae615029a491c417f235498e0496cd8183d1bf"), + nonce: &hex!("b382987916e19752dd9ecc0c"), + plaintext: &hex!("76b290496901c5824ad167433dbb6d6b5856d41913ee97ec81e70cf6a170e35c"), + aad: &hex!("e0aa3a1f1df601366c59a390f4f06c3b"), + ciphertext: &hex!("78347400d6799e77e11e76c0ecfd311becf31f74f14b3a71e6d526ce57015c8b"), + tag: &hex!("bf8dec2feac7cfe9f330bdfc92737b33"), + }, + TestVector { + key: &hex!("d707eab3c167b73efeb08c50e12b1569a275487ea136f52736c0f3ce66b69fa3"), + nonce: &hex!("11116f34182e52428642e747"), + plaintext: &hex!("a0c4818362035b16b50de445d558ea5cf8844bf5c84b96232999a2279806cc45"), + aad: &hex!("ae9f90331800c358716c92667f79f748"), + ciphertext: &hex!("91c77404b20028ef0fd4dd7f8b65b6594af94a1e7fc79cfbdb108265354fc71b"), + tag: &hex!("6c3410d4b915dbad745715202c04e9a4"), + }, + TestVector { + key: &hex!("405d13ee48d3b9fc26bcfca776b2af6c745d8fc34171622f8c6c4be5a54b8b65"), + nonce: &hex!("add1524abb1b846f0f6577da"), + plaintext: &hex!("e06475990d6e3990266de1bd025c3b1910c0736c81050885f2bfc13ec78e9d96"), + aad: &hex!("0b1c4c3ba877bca5846b2c1f2b0e2105"), + ciphertext: &hex!("6399f7e6d6c680fc41bac8bee3836b9a4241403d5a19e4919f396ce37b238d38"), + tag: &hex!("e754f400d76c76e03c63ea88cf64ccba"), + }, + TestVector { + key: &hex!("5853c020946b35f2c58ec427152b840420c40029636adcbb027471378cfdde0f"), + nonce: &hex!("eec313dd07cc1b3e6b068a47"), + plaintext: &hex!("ce7458e56aef9061cb0c42ec2315565e6168f5a6249ffd31610b6d17ab64935e"), + aad: &hex!("1389b522c24a774181700553f0246bbabdd38d6f"), + ciphertext: &hex!("eadc3b8766a77ded1a58cb727eca2a9790496c298654cda78febf0da16b6903b"), + tag: &hex!("3d49a5b32fde7eafcce90079217ffb57"), + }, + TestVector { + key: &hex!("5019ac0617fea10517a2a2714e6cd369c681be340c2a24611306edcd9d5c3928"), + nonce: &hex!("fd1fa6b5cab9aa8d56418abb"), + plaintext: &hex!("4349221f6647a906a47e64b5a7a1deb2f7caf5c3fef16f0b968d625bca363dca"), + aad: &hex!("953bcbd731a139c5de3a2b75e9ffa4f48018266a"), + ciphertext: &hex!("dbce650508dab5f499767651ee734692f7b157341977692d2ca879799e8f54aa"), + tag: &hex!("20239e97e2db4985f07e271ba545bbbf"), + }, + TestVector { + key: &hex!("c8cee90a8b9ad6094d469e5d1edc30d667608e89b26200cac77efd7e52af36fd"), + nonce: &hex!("5a1aa9c8e635281ee1fb9df7"), + plaintext: &hex!("728d9221891bd75c8e60b7dd6f53edcfd1ab1cebc63a6ce54be220b5b362233b"), + aad: &hex!("0538b3b64da72aac591bc59991a140eff206b3f7"), + ciphertext: &hex!("b753eb6b87f0c8778c3ea3a74fba3b31ced6d2da94d43d482ab0431806a80d75"), + tag: &hex!("b21d29cf6fd04571ffcaf317d384df11"), + }, + TestVector { + key: &hex!("b4b77710f86ffd463fc14bb9eaa4424b2b3a581778e5511a094a08fb204cab59"), + nonce: &hex!("3e4b12bf55633bf48d104620"), + plaintext: &hex!("6f44a8df11dce27df075ea10ddeb7566ca6c988a334cf56e8540f71166d7c0d1"), + aad: &hex!("3e3b4c9369266266098326217b5677a40297cb87"), + ciphertext: &hex!("31f82f5cb1cd5c4b4819b61aa9377abebe8fca76978b1199178462c7c1c4e2b2"), + tag: &hex!("1b3a535768e8480d75ec91b2e7b55efd"), + }, + TestVector { + key: &hex!("0a8fb75498a139223c763d52bbe3d42f813de370fa36b81edc4553d4219d2d5d"), + nonce: &hex!("7d6cb675fded3efef908a11a"), + plaintext: &hex!("81b69ca354de3b04d76ee62334cb981e55f0210f1174d391655d0f6712921a0e"), + aad: &hex!("2314ad86b248f1ed2878e7c562b533bf2dda5a29"), + ciphertext: &hex!("6a23d30737f4a72b1e07ba23d17fde43a4498e2e60d3e1b0c8e6ea26a2bb331a"), + tag: &hex!("7fcac442fb657910c62a74b1d0638902"), + }, + TestVector { + key: &hex!("a84315058849690c2b88062aef81134d338526baa7090e865fcaad94bbf51ca5"), + nonce: &hex!("a487cfa701447b495aab41e0"), + plaintext: &hex!("18074e14dc0a14d4439f1d710927ed8c200154c8492f77f10f653e0bf6070ca6"), + aad: &hex!("7c4416b0cf13ac76bec6687a6840dc703e91bb86"), + ciphertext: &hex!("80f40b7e335d40fc5859e87f385e14798a253818e8ad73b1799c1419638246a4"), + tag: &hex!("b4c7c76d8863e784eb6029cd160ef6de"), + }, + TestVector { + key: &hex!("82833bcaaec56f6abbb3378f7d65daf6e6f6f2a0d1e858c7219f53a7840f4e00"), + nonce: &hex!("4bc9b028a00be8feb5232978"), + plaintext: &hex!("d9b2383123a27a93bce85add8392b938093b40e82f182e484bf4f84fa3bfb3f0"), + aad: &hex!("76fc8ed57154cd8a9b3d02c87061edd2a8157811"), + ciphertext: &hex!("383efe971438cd2b2cbb399d74a3fb3eedd394f1862addc58e9fdd4c421402d2"), + tag: &hex!("fd803c4fa917f7ff649a6aac013a96b1"), + }, + TestVector { + key: &hex!("ee4634c49c5672c660968a42862698f6c1b2c7b79efd1605c24af8ff9ff8366c"), + nonce: &hex!("877912b2f35888d2810612cc"), + plaintext: &hex!("9512a5268a0cb3fbd916ddb820dce77f1e0dbb52c8ffc7a74be077119e9245e4"), + aad: &hex!("93bd669db4f1354ef6c8addb0cf729e46d5c3846"), + ciphertext: &hex!("69af0ac954e0d69043851d89f1538ebcb42769857eba27dbe4ad4fd60fd75537"), + tag: &hex!("3ee443873e2f7f7ea601fe3d7e5211e2"), + }, + TestVector { + key: &hex!("442f4bbc468433411e49486a15c5eed577f5007380ff126d9974f3bd3fe4e3c4"), + nonce: &hex!("1e7133aaa8af826dc646ec62"), + plaintext: &hex!("7f8069e5c356ece135d98bb563c8b411ea90ea3b673dfd92e1ba9c459efae61f"), + aad: &hex!("577662f611446b5b31814930029edb949a30dcb9"), + ciphertext: &hex!("b962952750eb2bce313e1a85a72e3c9cc2ea7e58c353ea37df2c9f0723995ca7"), + tag: &hex!("e633fe9f10cedf0f0d02aa2ddcf47d86"), + }, + TestVector { + key: &hex!("3a29aec009f44fdd2b1bc07cb7836f29d8589774bd0d74089a68d9e67827d6d8"), + nonce: &hex!("a42c5fb61573c72688ac31d8"), + plaintext: &hex!("d36eb81506c0a0e4ebcac9b4b1acebb38b94b8f2ce3d6f85a8f705fa40cb987a"), + aad: &hex!("2ee2582d544e1663f1d7a0b5033bcb0fce13b3e5"), + ciphertext: &hex!("179ef449daaacb961f88c39b4457d6638f304762bd695924ca9ebd01a3e99b9f"), + tag: &hex!("1fee176c7a5d214748e1d47b77f4bcc8"), + }, + TestVector { + key: &hex!("ed47660054294f3c913c97b869317cbddc395d757bef7d29b8ccbdd2c54e99d3"), + nonce: &hex!("770a00642c67eff93c9f1f56"), + plaintext: &hex!("034193397cbd0eb414459273a88808db2d0711e46f80d7883212c443d9e31b54"), + aad: &hex!("06210fca2018d2357256c09197730e9777caea96"), + ciphertext: &hex!("6a250ebd3390229d46b691142743dba1c432c0feaa0f0dd19d0ce4e6a8918d80"), + tag: &hex!("a5f6e975592b472907c34b93bfc69dde"), + }, + TestVector { + key: &hex!("9539844493362dc3f913308f7e12a2a0e02afdbd8869877b30ce0397fb0349dc"), + nonce: &hex!("eadda3132079195a54fde2c1"), + plaintext: &hex!("62349a0b1e40a9f31eadf27073682da15f0a05cf4566ee718b28325f7d8eaba0"), + aad: &hex!("0ae4a90cb292c4e519b525755af6c720b3145a1e"), + ciphertext: &hex!("ad6c9521bf78d1d95673edd150f2b8dd28f10625d67fa25f1fb42d132ba7fcfa"), + tag: &hex!("916242a9cb80dffcb6d3ae05c278819a"), + }, + TestVector { + key: &hex!("3b4eb08d27ae0b77605ae628a1b54a5402026550679fab0a20752bee510d3d92"), + nonce: &hex!("28a20c40f49a00493da3488a"), + plaintext: &hex!("c8a47edcf84872f53f96ef41ce05ca37cbc3854b556d6e606f0a8a32d0861907"), + aad: &hex!("0591390e2d14ebe62aeb1741c26448ce55b28cab"), + ciphertext: &hex!("a3e8cbf84df8529838f79315c7f1a0b7bb3ad4c4d036ec317b1810b274ee3080"), + tag: &hex!("0a8f66daeb7f0a88756909c4e93fcd36"), + }, + TestVector { + key: &hex!("0cccea8f1f6ce141690e246cf4cb9f35b66baf6e6986b8e0b4cfdd13fcdbc8c3"), + nonce: &hex!("929f07be5aa7bae7607bae3c"), + plaintext: &hex!("9fa5214c599523c695d37937b02f78837f6406960b2a03bf9a6db34bd35e3dc7"), + aad: &hex!("b851e610be70a994808b34ca73f45f1ea973de65"), + ciphertext: &hex!("917ecc8b00b53f7fb0732d66848a106e91f60acf2dcf180832a74d5993c658da"), + tag: &hex!("2959e20746bbb6ab66dfd29b9477799a"), + }, + TestVector { + key: &hex!("ecbfaef2345b34f31fbf6d68efb385e5833df8b6e6ae621ede02baf9735d2dba"), + nonce: &hex!("50c3527b1a35ccb318b446de"), + plaintext: &hex!("634f6dd60783d1f952353fd1d359b9ee4f4afa53cc13e81c5adfe24b46baf08f"), + aad: &hex!("f8981548bde6ee6c1745f947de191bf29997fadf"), + ciphertext: &hex!("705e5f67ab889ba238118e3fd9b90b68be801995ae307378d93b50977cf90588"), + tag: &hex!("12d14468ac18cc9936bd565f8ad42d0d"), + }, + TestVector { + key: &hex!("dc776f0156c15d032623854b625c61868e5db84b7b6f9fbd3672f12f0025e0f6"), + nonce: &hex!("67130951c4a57f6ae7f13241"), + plaintext: &hex!("9378a727a5119595ad631b12a5a6bc8a91756ef09c8d6eaa2b718fe86876da20"), + aad: &hex!("fd0920faeb7b212932280a009bac969145e5c316cf3922622c3705c3457c4e9f124b2076994323fbcfb523f8ed16d241"), + ciphertext: &hex!("6d958c20870d401a3c1f7a0ac092c97774d451c09f7aae992a8841ff0ab9d60d"), + tag: &hex!("b876831b4ecd7242963b040aa45c4114"), + }, + TestVector { + key: &hex!("07b3b8735d67a05632c557076ac41293f52540bac0521573e8c0414ec36f7220"), + nonce: &hex!("0046420eee8d56de35e2f7d5"), + plaintext: &hex!("4835d489828325a0cb38a59fc29cfeedccae25f2e9c399281d9b7641fb609765"), + aad: &hex!("d51cedf9a30e476de37c90b2f60882193630c7497a921ab01590a26bce8cb247e3b5590e7b07b955956ca89c7a041988"), + ciphertext: &hex!("46eb31cd98b6cc3ecafe1cd1fc2d45fa693667cbd3a7d2c5f8c10296827ea83c"), + tag: &hex!("36cd4e76dd0679887477bfb96cf1c5f6"), + }, + TestVector { + key: &hex!("0219f14b9ca6506c1388177c4ae6ee64ad2ac0256ebbf8c219b40df6e8571d70"), + nonce: &hex!("3420a87c4b9b23ba81eb221e"), + plaintext: &hex!("348f7a4ca944f252e4562c66dacf01fb10d70a3c8f5b280a2829567a2a94e47e"), + aad: &hex!("54dc2277b8d1aae660ffcc326e2c5d9e16b8ca17288601aacd02b3eea8bc5cc60718639aa189506b7b333b87da86e940"), + ciphertext: &hex!("58c92119bfb6ad53e387cac6728ce73b82e18f6e5bfbfca5f5acc370cd8c76a4"), + tag: &hex!("e7f9e3e3dae6d0a3470d8f597291180c"), + }, + TestVector { + key: &hex!("87440ee7f6febf3e14ef0a917a87c5d61260fefc979eeaeac0a64662c98cb4f7"), + nonce: &hex!("7c48bc75e58f21cc9989d691"), + plaintext: &hex!("f8e40a6a985f424898a7996307a077c487406c5312eefe055ea5b17a4b22087b"), + aad: &hex!("e0c66e5db1c7665a015ba7e21e08ff3de5b4a5fcd5d35e41db7e97ccd0c3df657ae803c3529d375420ad75ac9621cea0"), + ciphertext: &hex!("5a118fc3dbdaf6bc9490d372b7623af76da7841bf9820a9c6624a15eff6a69c2"), + tag: &hex!("0ddc2ae087d9b8ca2249ea5aa3dbd4c7"), + }, + TestVector { + key: &hex!("b12425796f63bf5435740f9039fa66367fc7702d675c61b2dec4435feeea07f8"), + nonce: &hex!("f26727053e6d67c2d2bf1e69"), + plaintext: &hex!("9df079d98a6e4dbe277a8545f4f6c19fe130f4a84bdd6b760a049fba21d4e99a"), + aad: &hex!("e50fca2e5a81ae56ca07f34c4b5da140d368cceab08494f5e28f746cbfefdc285b79b33cf4969fe618b77ab7baafe271"), + ciphertext: &hex!("845f00202e2e894516d8f4a4021430e531967098c9a94024c7113c9a1b91c8cd"), + tag: &hex!("3566c75967ae00198e39ebe9f0ac697f"), + }, + TestVector { + key: &hex!("674dfb625b8b0ce1dadbbbcbf7e151c5b2cecf0a1bc4e07f4734f3a6792350cd"), + nonce: &hex!("99e7b76e6686449616ad36c7"), + plaintext: &hex!("0a744a72e536a0484db47091609228d803bcfa9a8daf579e3039e3645f7688e2"), + aad: &hex!("2ab1573e5a94ca2997590840bd9c62e6add55e4d3eac12c895d2ec637791caa41d46ed91e6064db627e1fbef71d31d01"), + ciphertext: &hex!("e550ee77069709f5199be3c618f2a4178e4d719ab73df41cbfe32c52777138ff"), + tag: &hex!("134ac3fa8bd4af7ee836f4a3421d9e99"), + }, + TestVector { + key: &hex!("10c1de5f741560dae5be23e15649f0114db52949560bb6cdf2d4883247392ee1"), + nonce: &hex!("7cf73c1472cd60d8d35fde51"), + plaintext: &hex!("05becd366aebaa2e609f507dd2dd4433b2aba0634b0eb9a5bf7ded4cc8fbed72"), + aad: &hex!("d3fa8b6f607a20a18dd7eac85eabef69d4fb5a074d8e7d1bf15d07732ed80e020163b475f209c4b0cbfa00d65d1e82ef"), + ciphertext: &hex!("280f0c306e1a3aab8ff9ab3e4a9adc2e9ae4e4e1a06f190d11b3b4dc4280e4f3"), + tag: &hex!("3bc8be845bf5ff844c07337c2cfd5f80"), + }, + TestVector { + key: &hex!("e8d6ab5e514645dd7e051b028f5bfe624c72f44f30279577365aea65d4a8a819"), + nonce: &hex!("30b0d654ee5b79c2cfb24100"), + plaintext: &hex!("19be7e0feedd402bf4b05995a38e5f423c033de016e3ae83ea8c3c1cba658e1e"), + aad: &hex!("082e534bf860d0061ec2dad34d6b0db8cba1c651f2c705356ff271e47365b0b18f8ddb3a3c2269b437fb0703c9ad367a"), + ciphertext: &hex!("8573800c737d2480b2885ce714ac6a15f23287b1d12949a3d76effbe82b593bd"), + tag: &hex!("50110884292151f51213ccb2fe934d88"), + }, + TestVector { + key: &hex!("2d1eaf5e62ca80fd1515a811c0e4c045aba8c769df03d57f7493eb623ed8b941"), + nonce: &hex!("abf190b05df2e6556cb34b47"), + plaintext: &hex!("9c7cd522ed5c0af3e57da08d2653ef77eb973734f360572bbcb15a2a6cbd60b9"), + aad: &hex!("75ab9bd39c24e498a54d85a8b76a4126dc1879f2a30270a42609763e045a4021785b6134f283fd81c195c3188e78752d"), + ciphertext: &hex!("5fdfdaccb105e5408c375af8ca63a67afaba7ccbcd591acca9a86d92f92fd0f7"), + tag: &hex!("49940b7610618b3a5cb3912339e06b3c"), + }, + TestVector { + key: &hex!("b6020677e098c59e19eacf26732473d843aafd6bf999c707bb08ab896406918d"), + nonce: &hex!("807167ef2b84b32d1df4a94c"), + plaintext: &hex!("3199d6b95d133ba5b7eadc420080a0b249c84f4960bd369d6bf9e313627cf670"), + aad: &hex!("06225d410ada3e04157da7e5481d7d9f2285845824aac0c0e033244ed4c1b19615354c224ba8b7093c5651d10ef952fe"), + ciphertext: &hex!("4618adbfa5ea4ee260e310140b385232b7c3ad46887aa2107f7dafffd85cda22"), + tag: &hex!("2d76307bf55826dfeb58a171b6fa80e4"), + }, + TestVector { + key: &hex!("f75456c4918d0bea72f546a9a1e2db0b6ab9bcd9782b5eb1c2700e729921d666"), + nonce: &hex!("c75b83134e7b9188e5800ffe"), + plaintext: &hex!("f9a23abbd0f2b367ce16c2a0613cd293ac7e66cbe020eaeb5deb09d5031fd992"), + aad: &hex!("5ef46c9eb5865cab2c8a35f9c4c434614a6c9f1b5c479739f7434d3326cff1e70b0d2877c084a71c7a9d33d258d304bb"), + ciphertext: &hex!("56e4efe6c0944153b65ed4909845219842b9b88f54d8d8394051132afb95d391"), + tag: &hex!("255e2c8c43f8979c440c3581bff6cf65"), + }, + TestVector { + key: &hex!("9831c5c12e53e8a961642e93ddb2e13a38506acd0cf422e6ad9fbaeabce7b3f2"), + nonce: &hex!("bff29de3d6869e5fa75b96f9"), + plaintext: &hex!("b1edbed58ed34e99f718db0608e54dd31883baec1c8a0799c4ff8a5dad468de4"), + aad: &hex!("67ebeecb74cc81fdfee8065f8b1c1f5012bf788953bec9525e896611b827084a8e6baa0ce40ee70bc699b152bc6ed903"), + ciphertext: &hex!("13845db7e33bab1f5766a7fadfb942748e779753d97f143e645ccfcbd7c23b23"), + tag: &hex!("10dbe8a3e1901c8b88b0ab1441664d32"), + }, + TestVector { + key: &hex!("a02c2d4a43f0f7f1db57c07f13f07f588edfe069a9d83c9b76e9511946c4fc48"), + nonce: &hex!("84677438592dcaf683d08a67"), + plaintext: &hex!("ad5a884dad20ffa88794c4fca39f2ca01c6f67657ab38e5cf86ac5597318ef07"), + aad: &hex!("d5dea0cd6080af49a1c6b4d69ace674a622f84f9f190b2db8a22e084a66500b52ff20a8d04f62a7aeaedb67e2258598c"), + ciphertext: &hex!("83da16ae07ee0e885484c1330a6255a6e7ac22915c63cbefaabc6f9f059dd69d"), + tag: &hex!("42c4a270705493d85ad7bbcfda86dffb"), + }, + TestVector { + key: &hex!("feba412b641bc762bfa79ef17c3ea16e5630605470db096e36ffd33813641ace"), + nonce: &hex!("e3633f21e7c63a459d5d1670"), + plaintext: &hex!("9326572bd33551322ca42fcfb7cef8be41d78725f392c34907ecd1fe5572bff1"), + aad: &hex!("b7ee0233863b0e185b2f46181eb5fc0718832e1e76e7d4115a4c1f7e998c41319ccef44f5db89e8c5f077bd553d7bf42"), + ciphertext: &hex!("5019ea98cc9dc9368432c6d58f9e144f55446e763c0a8b4d8a6ce26f3dd95260"), + tag: &hex!("1010beb9cd6e9b611280a5395f08bca9"), + }, + TestVector { + key: &hex!("21bd5691f7af1ce765f099e3c5c09786936982834efd81dd5527c7c322f90e83"), + nonce: &hex!("36a59e523df04bc7feb74944"), + plaintext: &hex!("77e539dfdab4cfb9309a75c2ee9f9e9aa1b4651568b05390d73da19f12ccbe78"), + aad: &hex!("48aef5872f67f524b54598781c3b28f9cbcf353066c3670370fca44e132761203100b5e6c7352a930f7e9cbf28a8e1ce"), + ciphertext: &hex!("c21483731f7fe1b8a17d6e133eda16db7d73ddd7e34b47eec2f99b3bbc9669aa"), + tag: &hex!("15f9265bc523298cefb20337f878b283"), + }, + TestVector { + key: &hex!("26bf255bee60ef0f653769e7034db95b8c791752754e575c761059e9ee8dcf78"), + nonce: &hex!("cecd97ab07ce57c1612744f5"), + plaintext: &hex!("96983917a036650763aca2b4e927d95ffc74339519ed40c4336dba91edfbf9ad"), + aad: &hex!("afebbe9f260f8c118e52b84d8880a34622675faef334cdb41be9385b7d059b79c0f8a432d25f8b71e781b177fce4d4c57ac5734543e85d7513f96382ff4b2d4b95b2f1fdbaf9e78bbd1db13a7dd26e8a4ac83a3e8ab42d1d545f"), + ciphertext: &hex!("e34b1540a769f7913331d66796e00bdc3ee0f258cf244eb7663375cc5ad6c658"), + tag: &hex!("3841f02beb7a7fca7e578922d0a2f80c"), + }, + TestVector { + key: &hex!("74ce3121c18bbff4756ad10d0f293bb1ea3f93490daad0249cd3b05e223c9747"), + nonce: &hex!("81107afb4c264f65ae0002b1"), + plaintext: &hex!("7a133385ead593c3907806bec12240943f00a8c3c1b0ac73b8b81af2d3192c6f"), + aad: &hex!("f00847f848d758494afd90b6c49375e0e76e26dcba284e9a608eae33b87ad2deac28ccf40d2db154bbe10dc0fd69b09c9b8920f0f74ea62dd68df275074e288e76a290336b3bf6b485c0159525c362092408f51167c8e59e218f"), + ciphertext: &hex!("64bd17f3e8f71a4844b970d4ebc119961812efb9015b818e8d88b906d5efbd76"), + tag: &hex!("46d0e42aa046237efee17eab6d9cfb75"), + }, + TestVector { + key: &hex!("4c669a1969c97d56da30a46236c15407e06aada686205eed3bd7796b02c97a4b"), + nonce: &hex!("0a07758d5ad44766e051da6c"), + plaintext: &hex!("cd59bb307be76f11304f69ac8b151e1628ac61dec81086e7f24fd5bd83df8856"), + aad: &hex!("0b8277114cbf7ee16c9bbda1ab40419a02e469ebb295883f0a833c3cb755ded44a3c410034a201f7d91b43519fbabb55b974834be5d5afc7aea7c84b44a14e8e16dd68a3e8cc79ad2bf76d0ceb33d58ddb6378b45681ceaa0f2f"), + ciphertext: &hex!("bc62ce0b23cf4aa8e16b4450c8ab8c629a53949f01e68b875ecc5c45ff6d3ab0"), + tag: &hex!("5ffeda728914031006f271c3d9986f2d"), + }, + TestVector { + key: &hex!("a23296632913051e438114deb782fb955b75acc35e86e7e9fdaf4e9025b87f12"), + nonce: &hex!("ad50db40f80f15214e43ffd7"), + plaintext: &hex!("b71116cc27b5a5844d9b51a4a720cb3f06d55d6aaeaeaf921236424db8617204"), + aad: &hex!("a6f96f5a89bfd8c8f34cd07045270d80e58ea62f1f0b10f2506a954f272af0bc71df96ad3fa8eed52c45e0b868091dc4f75d9e0eaf15a0a858a71bf7036c5607110cbfe47ad9b6d02e942fcfae88d4c792a1f824e60e3cf98a37"), + ciphertext: &hex!("8e9e4b0ac93ab8e73688d6b4723d8c5ef399ead72246c7aa7a0783a8bfe29936"), + tag: &hex!("b7dea91e4b357ce805edeea3f91392d2"), + }, + TestVector { + key: &hex!("4036a07bdd4e10eb545f3d9124c9f766d2d0c8c59fc0d5835ac55dcfaebfc3a1"), + nonce: &hex!("815828fbb964497cdadccaad"), + plaintext: &hex!("717f22faff8066182e46d32dbac7831ec24272871c45c7c12ca779f868e7739a"), + aad: &hex!("0bc0e3931388bcb091463bae2989a93bde103bc14fc5d39f9448ca90367e86336b188f73218b2b0ab72a9a564ad5ff32544c5afeacecadfa55d2fb66925a88299dbf58f425cf49e31f42ac4edace743fdf9680d20ec845afc278"), + ciphertext: &hex!("e8c3b0342964c7a71f084d44ba2f93742bccd9821b30087d11b53bbe8b085808"), + tag: &hex!("86ddd9c469849cb6b100c339ca62717d"), + }, + TestVector { + key: &hex!("714bc3ba3839ac6707863a40aa3db5a2eebcb38dc6ec6d22b083cef244fb09f7"), + nonce: &hex!("2cfe1c51d894e5ef2f5a2c3c"), + plaintext: &hex!("0cc4a18bbfea87de0ac3446c777be38ca843d16f93be2c12c790fda4de94c9bf"), + aad: &hex!("84e3d46af2ecb717a39024d62bbc24d119f5aff57569dfef94e7db71ad5aff864abacdc5f8554e18ed5129cfb3366d349c52b3d1a111b867e8772140749e7f33e2e64259968486e32f047d21120da73c77757c4595ccac1b5713"), + ciphertext: &hex!("0857c8fb93412fde69bad287b43deea36506d7ee061d6844d00a7e77418f702f"), + tag: &hex!("24a9e5290957074807d55ad705adaa89"), + }, + TestVector { + key: &hex!("2f93b5a37be1a43853bf1fd578061d0744e6bd89337cde20177d1e95a2b642c4"), + nonce: &hex!("52b6d91557ae15aa792ce4b7"), + plaintext: &hex!("0fcaa316a135d81052509dd85f688aed2e5fd4261e174f435cf1c4115aa6f354"), + aad: &hex!("992ba9efa287a5c3e5177bd4931af498982a1728b56b3d7c4b28476905e29f83326c4f3223a28844fc9b9d84d4f6cd859074aff647a35dde28e1ee889faab3bb9c09a4c3fbf2a16460d48a40dc53378d4673f4325e6aa3992a71"), + ciphertext: &hex!("f99774cef3c15af33cda3cb449cd335ffe4f27435edf83aff4a4f4c2d2df6647"), + tag: &hex!("c5e09b83b1c2cc81e48a1f7c62b7bb35"), + }, + TestVector { + key: &hex!("531ca845af7bf731c49c3136407322b1c0f6b32b8eaebf03744b2edc1202d096"), + nonce: &hex!("baf13b85202bbfc899fc73f7"), + plaintext: &hex!("d4e9783f537c738200e7ba7526605f359a98c9f10cafaa2f433c40f3e5081a36"), + aad: &hex!("e2ba9cf548b4f6fb206f224250d85af327fde8d08916686ae770203dc29c694f8902b02222fd287f28ce6091006368c3949bea2937ff0bdedb7dbbd013ccf0a15ee0af8c56fe211b7c311e182f27707f59e09492b3604e80c6c5"), + ciphertext: &hex!("642f544929202128a783b985d36f60964c7d78e1d41f5d1bfe27de3ae0180df3"), + tag: &hex!("e333528c59ee1909750ed72fd1309ee1"), + }, + TestVector { + key: &hex!("3add17568daa9d441aa7a89bf88fa4e6998a921d57e494a254080445bc9b6f35"), + nonce: &hex!("b290f4a52496380218c3dcf5"), + plaintext: &hex!("2c6908cb34215f89a3f3a3c892e8887f2efa496a15ab913fc7d34cc70c0dff79"), + aad: &hex!("0bc9cc13eb2890aa60515c2297a99f092f6e516236c0dec9f986ea98b8a180680f2c6c20bd4354c33433a4c6f6a25e632f90ebef3a383c3592268b483eebf5f5db006929e7987edbcac4755d3afd1cdf9b02954ebd4fef53d5f6"), + ciphertext: &hex!("2cf3beae94fd5e6a4126a8ec8a7166b0aacb8b8bbce45d6106b78d3456d05149"), + tag: &hex!("ce1509b1bd5c47a593702618b0d79f6c"), + }, + TestVector { + key: &hex!("1c1dcfd4c4cc4beb71d6e368f739d8e681dfe48fbae39728386c9dfc08825743"), + nonce: &hex!("0deceb69ce0dc776a3a71b4c"), + plaintext: &hex!("b12700258ace7b16e40f4e86886892837168b256a170937a3b89063a9a0d68f7"), + aad: &hex!("a3af2db672292431fa8ee1fa5b197593b13e58a68c4129401d0942474d5f4cbe62093aaa5453f6d355d2f4b6dc8abde58ce863d1be5f9ecf39730a49565b3b6882a0a641c0b5d156a4107309dd150fd1f1634ea4e5100b3d4f88"), + ciphertext: &hex!("3ea7f1c0d613323e095558ddde53247420fa0eef17997a1e9c5ba93d5f24c46f"), + tag: &hex!("70534a87c258905d35806f4439f6906e"), + }, + TestVector { + key: &hex!("f2724153aac9d50f350878d3c498bc3dd782d90cce5cce4ae14126c0e1fbb3cf"), + nonce: &hex!("1c07b61c5316659bad65cca9"), + plaintext: &hex!("067ccbd0206f1f05d2872210dc5717a0585e8195d72afd0c77da11b9b3710e44"), + aad: &hex!("e69db7fcd3b590a6d32052612034036d5c8bffa5e5e9b742ffe75a9fbba89dd576dec08154cf4e6d36f0fdd4419bdf50adc1974a80ea313421c926dffa87565b4bd0c1e84f2ff305af91877f830f145bb13dfa7efa5e3aa682e6"), + ciphertext: &hex!("9aba433eef383466a1291bd486c3ce5e0ed126010e0a77bf037c5eaed2c72460"), + tag: &hex!("f30a155e35400bb0540883e8e09b4afd"), + }, + TestVector { + key: &hex!("a2544eb2047c97cfcaf0ec1427c5df395472285233a93ffccda8fee660aced56"), + nonce: &hex!("a751bea3c769bb5db25ab109"), + plaintext: &hex!("b9514cc01a357605918f9cc19123dcc8db328c605ca0eb9d69d871afeea1dcfb"), + aad: &hex!("eb9e09884de1454d6aeb0d6c82375f2428992031ea6cabf6a29aa6a4de49a353e4ffae043dad18ae651b20b7bca13f5c327ca9f132014bfa86e716d4724e05a1ef675521a6607a536756e6a8c16bb885b64815f1eb5ec282ce8e"), + ciphertext: &hex!("cb442b17088f6ac5f24c7a04f0050559386f3a57131b92a54142c7a556fdb935"), + tag: &hex!("5f80c5c0cdf0c7890bfd1fbd58c33081"), + }, + TestVector { + key: &hex!("ceb057782efb1e85d805448af946a9b4d4128bf09a12473cce1e8ef8bfd2869d"), + nonce: &hex!("406f9730e9b1e421e428439b"), + plaintext: &hex!("0815723d5367b1328cac632fa26e23f2b814a1d59a2971d94d02ebd7ecf5c14a"), + aad: &hex!("0772ae00e1ca05d096cf533fd3de2818ac783edfca0eee7686a6290f3357481e883fb2f895b9a4f4004c56b8a1265242cfdf1fb4af7edc41ed78c5f4ffe9c4080d4a17318f9c56ecdb3a06f3c748535387d56a096943a76d46f6"), + ciphertext: &hex!("9d82355d8e460896201be15fd95fed48a8524666d987ab078550883034d0253c"), + tag: &hex!("a0bee8ac0e636d64d3b1eb33fd6f21d4"), + }, + TestVector { + key: &hex!("7dbdbdfe36d4936940ad6d6f76c67c2851a0477f0aa7d6797bfdf2b7878ef7e0"), + nonce: &hex!("bc672b224b4b6b91fc3fd697"), + plaintext: &hex!("dfea463d35f0fa20487b606d6ccfd422a5b707f16527b422bf1d68a77db67e9c"), + aad: &hex!("faacb84ec7cfadd731de2f7c0892d7e38cbfb782b48412331af0b3eab602a722cad1069dea0052beb5ca70e2ee476c340c6193bcc60f939aabe446bf3ce958fe11a2ffc90241f0a7e4e274f0c1441def795893895bd848bf0f0e"), + ciphertext: &hex!("0ddc2281b1fcb904864a43657bc72357cf73fc1f16520caad7cddde10f846bd9"), + tag: &hex!("9d96699450aa9707695e5de56597101b"), + }, + TestVector { + key: &hex!("187214df6e2d80ee8e9aae1fc569acd41589e952ddcbe8da018550d103767122"), + nonce: &hex!("56db334422b6c5e93460d013"), + plaintext: &hex!("53355283186719a9146c7305e3d1959a11ccf197570b855a43cbc7563a053c73"), + aad: &hex!("cbedb7ccfbf56dfd72e530bfe16b4f5aac48a90204bcb7a8cae1046010882cfc8b526e7562a7880914e61b60cbd605165242737d85eeed583c98cab3443874e5989ec9cde001adf7de9c9967de5178f75b8412b0c4d6fec5af72"), + ciphertext: &hex!("c2262585966bc9c23dc7cc1059d060211e86f3b3161d38b153635fbea4a28c05"), + tag: &hex!("a94297c584dfcd10ee5df19a2ee5c3d2"), + }, + TestVector { + key: &hex!("1fded32d5999de4a76e0f8082108823aef60417e1896cf4218a2fa90f632ec8a"), + nonce: &hex!("1f3afa4711e9474f32e70462"), + plaintext: &hex!("06b2c75853df9aeb17befd33cea81c630b0fc53667ff45199c629c8e15dce41e530aa792f796b8138eeab2e86c7b7bee1d40b0"), + aad: b"", + ciphertext: &hex!("91fbd061ddc5a7fcc9513fcdfdc9c3a7c5d4d64cedf6a9c24ab8a77c36eefbf1c5dc00bc50121b96456c8cd8b6ff1f8b3e480f"), + tag: &hex!("30096d340f3d5c42d82a6f475def23eb"), + }, + TestVector { + key: &hex!("b405ac89724f8b555bfee1eaa369cd854003e9fae415f28c5a199d4d6efc83d6"), + nonce: &hex!("cec71a13b14c4d9bd024ef29"), + plaintext: &hex!("ab4fd35bef66addfd2856b3881ff2c74fdc09c82abe339f49736d69b2bd0a71a6b4fe8fc53f50f8b7d6d6d6138ab442c7f653f"), + aad: b"", + ciphertext: &hex!("69a079bca9a6a26707bbfa7fd83d5d091edc88a7f7ff08bd8656d8f2c92144ff23400fcb5c370b596ad6711f386e18f2629e76"), + tag: &hex!("6d2b7861a3c59ba5a3e3a11c92bb2b14"), + }, + TestVector { + key: &hex!("fad40c82264dc9b8d9a42c10a234138344b0133a708d8899da934bfee2bdd6b8"), + nonce: &hex!("0dade2c95a9b85a8d2bc13ef"), + plaintext: &hex!("664ea95d511b2cfdb9e5fb87efdd41cbfb88f3ff47a7d2b8830967e39071a89b948754ffb0ed34c357ed6d4b4b2f8a76615c03"), + aad: b"", + ciphertext: &hex!("ea94dcbf52b22226dda91d9bfc96fb382730b213b66e30960b0d20d2417036cbaa9e359984eea947232526e175f49739095e69"), + tag: &hex!("5ca8905d469fffec6fba7435ebdffdaf"), + }, + TestVector { + key: &hex!("aa5fca688cc83283ecf39454679948f4d30aa8cb43db7cc4da4eff1669d6c52f"), + nonce: &hex!("4b2d7b699a5259f9b541fa49"), + plaintext: &hex!("c691f3b8f3917efb76825108c0e37dc33e7a8342764ce68a62a2dc1a5c940594961fcd5c0df05394a5c0fff66c254c6b26a549"), + aad: b"", + ciphertext: &hex!("2cd380ebd6b2cf1b80831cff3d6dc2b6770778ad0d0a91d03eb8553696800f84311d337302519d1036feaab8c8eb845882c5f0"), + tag: &hex!("5de4ef67bf8896fbe82c01dca041d590"), + }, + TestVector { + key: &hex!("1c7690d5d845fceabba227b11ca221f4d6d302233641016d9cd3a158c3e36017"), + nonce: &hex!("93bca8de6b11a4830c5f5f64"), + plaintext: &hex!("3c79a39878a605f3ac63a256f68c8a66369cc3cd7af680d19692b485a7ba58ce1d536707c55eda5b256c8b29bbf0b4cbeb4fc4"), + aad: b"", + ciphertext: &hex!("c9e48684df13afccdb1d9ceaa483759022e59c3111188c1eceb02eaf308035b0428db826de862d925a3c55af0b61fd8f09a74d"), + tag: &hex!("8f577e8730c19858cad8e0124f311dd9"), + }, + TestVector { + key: &hex!("dbdb5132f126e62ce5b74bf85a2ac33b276588a3fc91d1bb5c7405a1bf68418b"), + nonce: &hex!("64f9e16489995e1a99568118"), + plaintext: &hex!("b2740a3d5647aa5aaeb98a2e7bbf31edaea1ebacd63ad96b4e2688f1ff08af8ee4071bf26941c517d74523668ca1f9dfdbcaab"), + aad: b"", + ciphertext: &hex!("e5fec362d26a1286b7fd2ec0fa876017437c7bce242293ff03d72c2f321d9e39316a6aa7404a65ccd84890c2f527c1232b58d5"), + tag: &hex!("dfa591ee2372699758d2cc43bfcbd2ba"), + }, + TestVector { + key: &hex!("8433a85f16c7c921476c83d042cb713eb11a83fc0cffe31dde97907f060b4ee9"), + nonce: &hex!("55ffc85ffd1cdea8b8c48382"), + plaintext: &hex!("23bc3983ba5b3be91c8a6aa148a99995241ee9e82ce44e1184beb742affbe48f545c9a980480cf1fab758a46e4711ea9267466"), + aad: b"", + ciphertext: &hex!("2f4bdc7b8b8cec1863e3145871554778c43963b527f8413bb9779935c138a34d86d7c76a9e6af689902f316191e12f34126a42"), + tag: &hex!("7dc63156b12c9868e6b9a5843df2d79e"), + }, + TestVector { + key: &hex!("5d7bf55457929c65e4f2a97cbdcc9b432405b1352451ccc958bceebce557491d"), + nonce: &hex!("f45ae70c264ed6e1cc132978"), + plaintext: &hex!("ba5ac2a16d84b0df5a6e40f097d9d44bf21de1fcec06e4c7857463963e5c65c936d37d78867f253ce25690811bf39463e5702a"), + aad: b"", + ciphertext: &hex!("47c16f87ebf00ba3e50416b44b99976c2db579423c3a3420479c477cd5ef57621c9c0cee7520acb55e739cc5435bc8665a2a0c"), + tag: &hex!("456054ecb55cf7e75f9543def2c6e98c"), + }, + TestVector { + key: &hex!("595f259c55abe00ae07535ca5d9b09d6efb9f7e9abb64605c337acbd6b14fc7e"), + nonce: &hex!("92f258071d79af3e63672285"), + plaintext: &hex!("a6fee33eb110a2d769bbc52b0f36969c287874f665681477a25fc4c48015c541fbe2394133ba490a34ee2dd67b898177849a91"), + aad: b"", + ciphertext: &hex!("bbca4a9e09ae9690c0f6f8d405e53dccd666aa9c5fa13c8758bc30abe1ddd1bcce0d36a1eaaaaffef20cd3c5970b9673f8a65c"), + tag: &hex!("26ccecb9976fd6ac9c2c0f372c52c821"), + }, + TestVector { + key: &hex!("251227f72c481a7e064cbbaa5489bc85d740c1e6edea2282154507877ed56819"), + nonce: &hex!("db7193d9cd7aeced99062a1c"), + plaintext: &hex!("cccffd58fded7e589481da18beec51562481f4b28c2944819c37f7125d56dceca0ef0bb6f7d7eeb5b7a2bd6b551254e9edff3a"), + aad: b"", + ciphertext: &hex!("1cc08d75a03d32ee9a7ae88e0071406dbee1c306383cf41731f3c547f3377b92f7cc28b3c1066601f54753fbd689af5dbc5448"), + tag: &hex!("a0c7b7444229a8cfef24a31ee2de9961"), + }, + TestVector { + key: &hex!("f256504fc78fff7139c42ed1510edf9ac5de27da706401aa9c67fd982d435911"), + nonce: &hex!("8adcf2d678abcef9dd45e8f9"), + plaintext: &hex!("d1b6db2b2c81751170d9e1a39997539e3e926ca4a43298cdd3eb6fe8678b508cdb90a8a94171abe2673894405eda5977694d7a"), + aad: b"", + ciphertext: &hex!("76205d63b9c5144e5daa8ac7e51f19fa96e71a3106ab779b67a8358ab5d60ef77197706266e2c214138334a3ed66ceccb5a6cd"), + tag: &hex!("c1fe53cf85fbcbff932c6e1d026ea1d5"), + }, + TestVector { + key: &hex!("21d296335f58515a90537a6ca3a38536eba1f899a2927447a3be3f0add70bea5"), + nonce: &hex!("2be3ad164fcbcf8ee6708535"), + plaintext: &hex!("ad278650092883d348be63e991231ef857641e5efc0cab9bb28f360becc3c103d2794785024f187beaf9665b986380c92946a7"), + aad: b"", + ciphertext: &hex!("b852aeba704e9d89448ba180a0bfde9e975a21cc073d0c02701215872ed7469f00fe349294ba2d72bf3c7780b72c76101ba148"), + tag: &hex!("bdd6d708b45ae54cd8482e4c5480a3c1"), + }, + TestVector { + key: &hex!("d42380580e3491ddfbc0ec32424e3a281cbe71aa7505ff5ab8d24e64fbe47518"), + nonce: &hex!("fbed88de61d605a7137ffeb2"), + plaintext: &hex!("4887a6ef947888bf80e4c40d9769650506eb4f4a5fd241b42c9046e3a2cf119db002f89a9eba1d11b7a378be6b27d6f8fc86c9"), + aad: b"", + ciphertext: &hex!("87aa27f96187ce27e26caf71ba5ba4e37705fd86ca9291ea68d6c6f9030291cdbff58bff1e6741590b268367e1f1b8c4b94cd4"), + tag: &hex!("d1690a6fe403c4754fd3773d89395ecd"), + }, + TestVector { + key: &hex!("5511727ecd92acec510d5d8c0c49b3caacd2140431cf51e09437ebd8ca82e2ce"), + nonce: &hex!("ae80d03696e23464c881ccff"), + plaintext: &hex!("184b086646ef95111ccb3d319f3124f4d4d241f9d731ce26662ea39e43457e30b0bd739b5d5dbceb353ce0c3647a3a4c87e3b0"), + aad: b"", + ciphertext: &hex!("aa28cb257698963dfc3e3fe86368d881ac066eb8ee215a7c0ed72e4d081db0b940071e2e64ff6204960da8e3464daf4cb7f37b"), + tag: &hex!("c1578aa6e3325ee4b5e9fb9ee62a7028"), + }, + TestVector { + key: &hex!("d48f3072bbd535a2df0a2864feb33b488596cd523ad1623b1cefe7b8cbefcf4a"), + nonce: &hex!("bbf2a537d285444d94f5e944"), + plaintext: &hex!("060c585bd51539afdd8ff871440db36bfdce33b7f039321b0a63273a318bd25375a2d9615b236cfe63d627c6c561535ddfb6bd"), + aad: b"", + ciphertext: &hex!("993d5d692c218570d294ab90d5f7aa683dc0e470efac279a776040f3b49386813f68b0db6a7aef59025cc38520fb318a1eac55"), + tag: &hex!("8cd808438a8f5b6a69ff3ae255bf2cb2"), + }, + TestVector { + key: &hex!("5fe01c4baf01cbe07796d5aaef6ec1f45193a98a223594ae4f0ef4952e82e330"), + nonce: &hex!("bd587321566c7f1a5dd8652d"), + plaintext: &hex!("881dc6c7a5d4509f3c4bd2daab08f165ddc204489aa8134562a4eac3d0bcad7965847b102733bb63d1e5c598ece0c3e5dadddd"), + aad: &hex!("9013617817dda947e135ee6dd3653382"), + ciphertext: &hex!("16e375b4973b339d3f746c1c5a568bc7526e909ddff1e19c95c94a6ccff210c9a4a40679de5760c396ac0e2ceb1234f9f5fe26"), + tag: &hex!("abd3d26d65a6275f7a4f56b422acab49"), + }, + TestVector { + key: &hex!("885a9b124137e40bd0f697771317e401ce36327e61a8f9d0b80f4798f30a731d"), + nonce: &hex!("beebc2f5a26fd2cab1e9c395"), + plaintext: &hex!("427ec568ad8367c202f5d9999240f9994cc113500154f7f49e9ca27cc8154143b855238bca5c7bd6d9852b4eebd41e4eb98f16"), + aad: &hex!("2e8bdde32258a5fcd8cd21037d0545eb"), + ciphertext: &hex!("a1d83aab6864db463d9d7c22419462bde0740355c1147c62b4c4f23ceeaf65b16b873b1cc7e698dff6e3d19cf9da33e8cbcba7"), + tag: &hex!("4fdbfd5210afa3556ec0fdc48b98e1eb"), + }, + TestVector { + key: &hex!("21c190e2b52e27b107f7a24b913a34bd5b7022060c5a4dec9ab289ff8ae67e2d"), + nonce: &hex!("b28a61e6c1dfa7f76d086063"), + plaintext: &hex!("4e1b9528cf46b1dd889858d3904d41d3174dcb225923f923d80adbfe6eec144b1d4eb3690d0b8519c99beaee25bb50fd2d148f"), + aad: &hex!("d80657377ddbbed1f9b8d824b3c4d876"), + ciphertext: &hex!("7126fa807aa6b61a60958fe4cc8682bb256e5bbdc499d04a6caa81b23f9e67d3da4cf1994b5a8ecc7bce641864d0519a6509cd"), + tag: &hex!("d3e96568f2cd1a48771ee4f67ad042c1"), + }, + TestVector { + key: &hex!("11c33ae37680130c51ed11bfaf0fcb6ed4fc7d903ff432b811763d2c7ef83a33"), + nonce: &hex!("0f224d26dbf632cebdce3b8b"), + plaintext: &hex!("f8a2affe5a7e67f2c62622e4a56804b48e529d1faf9096f94409224129921ce46aed898dd5391746e8170e05f91e0524166625"), + aad: &hex!("dee803732ff662cba9f861227f8b67cf"), + ciphertext: &hex!("3856558375c363b25e8f9e9e2eb63cf0e76a1c6e228893c7b22da4a69b682528b4a4ca2b99e7a537390e2d1e05a68f3e39c4e9"), + tag: &hex!("9b12691b2002ca9227035c68ea941ef3"), + }, + TestVector { + key: &hex!("3b291794fbb9152c3e4f4de4608a9137d277bd651f97e738afaa548d97b4ec60"), + nonce: &hex!("4d1c69c6da96c085d31422ba"), + plaintext: &hex!("21b3ca1f47a0c7f6ebd097eda69d9e5b5fbf5c24d781658003cfd443ae7096be19e1cd3c14fe9738efb00847697fccb466ae1b"), + aad: &hex!("f3a5fa61a4e987413a8fab4aa51d895d"), + ciphertext: &hex!("6c1439cd2cb564e7944fd52f316e84aeffc3fd8024df5a7d95a87c4d31a0f8ea17f21442c709a83b326d067d5f8e3005ebe22a"), + tag: &hex!("e58048f2c1f806e09552c2e5cdf1b9d9"), + }, + TestVector { + key: &hex!("8e7a8e7b129326e5410c8ae67fbd318de1909caba1d2b79210793c6b2c6e61c7"), + nonce: &hex!("8e48513fdd971861ef7b5dc3"), + plaintext: &hex!("ef6b4145910139293631db87a0d7782a1d95db568e857598128582e8914b4fa7c03c1b83e5624a2eb4c340c8ad7e6736a3e700"), + aad: &hex!("80bb66a4727095b6c201fb3d82b0fcf5"), + ciphertext: &hex!("e302687c0548973897a27c31911fc87ee93d8758c4ded68d6bd6415eaaf86bcc45fa6a1ef8a6ae068820549b170405b3fc0925"), + tag: &hex!("ff5c193952558e5a120e672f566be411"), + }, + TestVector { + key: &hex!("d687e0262f7af2768570df90b698094e03b668ce6183b6c6b6ca385dcd622729"), + nonce: &hex!("50f6904f2d8466daa33c2461"), + plaintext: &hex!("79e3067d94464e019a7c8af10b53adf5b09426d35f2257c3cbaffe1ff720565c07e77aeef06f9d03a2353053992073a4ed1fc8"), + aad: &hex!("e8fa99432929d66f10205ad3e9592151"), + ciphertext: &hex!("18f6e6aeecc8dc5a3d0b63a2a8b7bfaf695bd9c49a7392dbfa8ed44771eebe27f94589d8a430da4cf03a8693bc7525e1fcac82"), + tag: &hex!("3c864eaa1b0ae44a7f0ad9ba287ba800"), + }, + TestVector { + key: &hex!("26dc5ce74b4d64d1dc2221cdd6a63d7a9226134708299cd719a68f636b6b5ebd"), + nonce: &hex!("0294c54ff4ed30782222c834"), + plaintext: &hex!("ae4c7f040d3a5ff108e29381e7a0830221d5378b13b87ef0703c327686d30af004902d4ddb59d5787fecea4731eaa8042443d5"), + aad: &hex!("2a9fb326f98bbe2d2cf57bae9ecbeff7"), + ciphertext: &hex!("9601aec6bc6e8a09d054a01e500a4e4cdcc7c2cf83122656be7c26fc7dc1a773a40be7e8a049a6cdf059e93a23ca441ef1ca96"), + tag: &hex!("b620a8a0c8fe6117f22735c0ca29434c"), + }, + TestVector { + key: &hex!("7fa0644efc7f2e8df4b311f54ba8b8c975b2c2aa97962f8ca8a322541bedaa9d"), + nonce: &hex!("5e774e45a07eeb9721734412"), + plaintext: &hex!("84d1c75455e4c57419a9d78a90efc232c179517fe94aff53a4b8f7575db5af627f3d008006f216ecfc49ab8da8927ff5dc3959"), + aad: &hex!("6ad673daa8c412bf280ea39ba0d9b6d4"), + ciphertext: &hex!("e2f00b5a86b3dec2b77e54db328c8d954d4b716f9735e5798b05d65c512674d56e88bda0d486685a45d5c249719884329e3297"), + tag: &hex!("0ce8eb54d5ad35dd2cb3fa75e7b70e33"), + }, + TestVector { + key: &hex!("91d0429f2c45cf8ab01d50b9f04daaaccbe0503c9f115f9457c83a043dc83b23"), + nonce: &hex!("34401d8d922eebac1829f22e"), + plaintext: &hex!("d600d82a3c20c94792362959de440c93119a718ac749fa88aa606fc99cb02b4ca9ba958d28dc85f0523c99d82f43f58c5f979b"), + aad: &hex!("1b29de9321aebc3ff9d1c2507aee80e9"), + ciphertext: &hex!("84cbc9936eb7270080bb7024780113d064eccb63d3da0bd6bce4f8737d28304bfb6102f3ae9c394cc6452633fc551582bbfe1d"), + tag: &hex!("e132dc8a31d21f24ea0e69dfb6b26557"), + }, + TestVector { + key: &hex!("44e6411b9fbfcef387d0ca07b719181c7567e27dba59e8e1c3cc1763cfeaca04"), + nonce: &hex!("25a1cfd97bd8e63de5d65974"), + plaintext: &hex!("db28a592b1f3603c287991a69cc64eacdd62046445a8ba4067575f12553de155d06a9b40ddf58fec56c8171687b9cb54b1f346"), + aad: &hex!("4b1751b074ab649d27fd3f2c4d7ee33a"), + ciphertext: &hex!("36bf6bb761b2248fe71a620e34e9d18e12a74ca42c9a9a21d30345995a83eb44bcae3c67c020730cd8d5e51a741694cc396469"), + tag: &hex!("e69ebf80a88d6eca41ae87cdcab4e1f2"), + }, + TestVector { + key: &hex!("a94bfcefae90f9078860db80ccc50819eadf7cce29df3279f94f5eea97009ef2"), + nonce: &hex!("f481bcb7f5da296e9454ff78"), + plaintext: &hex!("97d0c7dfcab32a386f51d92e89333ec84eecd552e68d14cf48b75067bf0e1946ad03a5d063b852ca053c929088af45d0884a88"), + aad: &hex!("9f80d845577818df9ba984ee552ae203"), + ciphertext: &hex!("18a1c9bfe1b1dfdd06e465df347c1e942b37b3e48cb0c905841a593b5b0d0330feb3b8970dbc9429252a897f0f8e12860ea39a"), + tag: &hex!("10cf4d335b8d8e7e8bbaf49222a1cd66"), + }, + TestVector { + key: &hex!("a50a60e568ff35a610ef9479c08bbc7bb64c373fc853f37fa6b350250a26f232"), + nonce: &hex!("5ada1d4aca883d7bd6fa869f"), + plaintext: &hex!("9ea44e72a1d21395cd81d20db05816441010efd8f811b75bb143ab47f55eefce4eec5f606fa5d98b260d7e5df4a7474cbd8599"), + aad: &hex!("cc7a7a541be7a6d1b846354cb6a571e6"), + ciphertext: &hex!("4165b135187faeb395d4531c062738e0d47df8bed91982eb32e391a6b3711f117b6fae0afde791de3e72fcf96d2b53ff1a621a"), + tag: &hex!("e2cbfea2100585b2cbe5107da17ff77a"), + }, + TestVector { + key: &hex!("5ff3311461d247ceb1eaf591292fcba54308dd3484fd1851e09a12b8f6663fc1"), + nonce: &hex!("61af2e6aec183129cf053c2b"), + plaintext: &hex!("920df8b2888a74022ede6919ed0bf48ccf51e395fe5bfa69a6209ff9a46674024eaa4f43ae2c933730b9fdc8ad216130447cc8"), + aad: &hex!("5eafed6674f2ae83397df923e059db49"), + ciphertext: &hex!("0e35e1208168b639e012df398bc8bf2b19b08d46af0353cd78f6d1b7ae14e6224c1da6fdc9433b171f1cd2b512d5f1acd84f03"), + tag: &hex!("5bc77eb02e4d51e2019446b468498d0e"), + }, + TestVector { + key: &hex!("42e93547eee7e18ec9620dd3dc0e2b1cf3e5d448198a902ded3f935da9d35b33"), + nonce: &hex!("e02e12ba92a6046af11adf0e"), + plaintext: &hex!("6c3704b32527ace3d5236687c4a98a1ad5a4f83c04af2f62c9e87e7f3d0469327919d810bb6c44fd3c9b146852583a44ed2f3c"), + aad: &hex!("ac3d536981e3cabc81211646e14f2f92"), + ciphertext: &hex!("8b6506af703ae3158eb61e2f9c2b63de403b2ebc6b1e6759ceb99c08aa66cb07d1d913ac4acd7af9b9e03b3af602bcaf2bb65e"), + tag: &hex!("a6ce2ccb236fc99e87b76cc412a79031"), + }, + TestVector { + key: &hex!("24501ad384e473963d476edcfe08205237acfd49b5b8f33857f8114e863fec7f"), + nonce: &hex!("9ff18563b978ec281b3f2794"), + plaintext: &hex!("27f348f9cdc0c5bd5e66b1ccb63ad920ff2219d14e8d631b3872265cf117ee86757accb158bd9abb3868fdc0d0b074b5f01b2c"), + aad: &hex!("adb5ec720ccf9898500028bf34afccbcaca126ef"), + ciphertext: &hex!("eb7cb754c824e8d96f7c6d9b76c7d26fb874ffbf1d65c6f64a698d839b0b06145dae82057ad55994cf59ad7f67c0fa5e85fab8"), + tag: &hex!("bc95c532fecc594c36d1550286a7a3f0"), + }, + TestVector { + key: &hex!("fb43f5ab4a1738a30c1e053d484a94254125d55dccee1ad67c368bc1a985d235"), + nonce: &hex!("9fbb5f8252db0bca21f1c230"), + plaintext: &hex!("34b797bb82250e23c5e796db2c37e488b3b99d1b981cea5e5b0c61a0b39adb6bd6ef1f50722e2e4f81115cfcf53f842e2a6c08"), + aad: &hex!("98f8ae1735c39f732e2cbee1156dabeb854ec7a2"), + ciphertext: &hex!("871cd53d95a8b806bd4821e6c4456204d27fd704ba3d07ce25872dc604ea5c5ea13322186b7489db4fa060c1fd4159692612c8"), + tag: &hex!("07b48e4a32fac47e115d7ac7445d8330"), + }, + TestVector { + key: &hex!("9f953b9f2f3bb4103a4b34d8ca2ec3720df7fedf8c69cac900bd75338beababe"), + nonce: &hex!("eb731ae04e39f3eb88cc77fa"), + plaintext: &hex!("3b80d5ac12ba9dad9d9ff30a73732674e11c9edf9bb057fd1c6adc97cf6c5fa3ee8690ad4c51b10b3bd5da9a28e6275cbe28cb"), + aad: &hex!("d44a07d869ac0d89b15262a1e8e1aa74f09bcb82"), + ciphertext: &hex!("1533ce8e2fc6ab485aef6fcfb08ded83ae549a7111fce2a1d8a3f691f35182ce46fce6204d7dafb8d3206c4e4b645bc3f5afd1"), + tag: &hex!("f09265c21f90ef79b309a93db73d9290"), + }, + TestVector { + key: &hex!("2426e2d1cd9545ec2fb7ab9137ad852734333925bfc5674763d6ee906e81c091"), + nonce: &hex!("49a094a71d393b36daa4a591"), + plaintext: &hex!("7cbe7982d365a55d147c954583f9760a09948ab73ebbe1b2c1d69ed58e092a347392192cfe8bce18ca43ee19af7652331bd92c"), + aad: &hex!("177309cfc913e3f5c093e8b1319ba81826d43ce5"), + ciphertext: &hex!("cab992e17cf6ec69fd3c67ea0424bcd67475a7f1f16e6733c4419d1b5a755f78d6eda8e368360d403800a08f0d52b4bc0aa0ab"), + tag: &hex!("b125f8caee9e54b9f9414b1c09021ed8"), + }, + TestVector { + key: &hex!("8dc1b24bcbbee3cb8e14b344166d461d00c7490041edc9fa07e19cc82a3ed9c4"), + nonce: &hex!("31768ad18c971b188d947019"), + plaintext: &hex!("84e4f79dbb7209cbaf70e4fefe137c494786c899602783e9c034296978d7f0c571f7ea9d80ed0cc4723124872d7326890300c1"), + aad: &hex!("eb3673b64560cca7bda76a1de7ae1014ee1acaee"), + ciphertext: &hex!("2402acd865d4b731bc9395eae0e57d38fdf5ce847ac7aef75791a52c7573ea9b3a296e62cb1ed97c4bd34be50ee7f3d75747cf"), + tag: &hex!("665abb725498ede2b0df655fc1765a2b"), + }, + TestVector { + key: &hex!("bc898f643a5f2cd864c10b507b4b803b4ff4ace61fadcc7bcd98af394731b791"), + nonce: &hex!("cc447d83c0a6734a79778c64"), + plaintext: &hex!("124eb963cdb56fa49c70a9b1aa682445c55065f26859f1d16eef7cfe491587533eedd7e23deabddfc5550c2fa6a08b17822699"), + aad: &hex!("e932bd2e0e6c550d136f725e14c53d27ffb20f6a"), + ciphertext: &hex!("45d8908ef9eef369e78b7ea0b7d023a92c63648271927efe9b0220eb09ed96f3b635c6ec8bfc68b4c228b712494bb37f4c7f1a"), + tag: &hex!("47899857494bac28d2176a9c923026b2"), + }, + TestVector { + key: &hex!("8e82a85466ee024eb1ae10c4982d6a95e6dbe5582299ab37fe89a9db80ab51a6"), + nonce: &hex!("04cfd489e18eeb7a4a8ab36b"), + plaintext: &hex!("3aa2e4eaed18c4602715ae77379e9083708af9f9b49031324d41abca61440319c8c8e6dbcc20006a825b12ced00b2286848a94"), + aad: &hex!("7bb54b1a6ed0ca387268a146430c0bfa2602a8fd"), + ciphertext: &hex!("674b1391937074642408eeae9b748ca629da9fd00281824f5a108f6078ee78f98749392bb6e29b53e53e4b11739ac53a8e653b"), + tag: &hex!("e320a873a9c2e8ef455698c37ea59a6d"), + }, + TestVector { + key: &hex!("f1f2c5503ebf35ac1373c29e2305e963f89f6ed015a181b70fb549429805d5d9"), + nonce: &hex!("2fb5c6a24f406872755db05c"), + plaintext: &hex!("b4a2809198035c277637bb1c2927fb5c60b49ef9087c800012d8663d997983fcb78d51a054114a24e1e1b5214b58e7dee47195"), + aad: &hex!("92c1f3489aed90aedafb55562a34b3f4be29e101"), + ciphertext: &hex!("f051a3a968278a46630b2894a0d386c18fa034960d8ddd14e88e1071afbbca5baf02967c2270117b4fb2bd4cfd032174505f99"), + tag: &hex!("6f1db5293660b6904f7f008e409bdc06"), + }, + TestVector { + key: &hex!("f0338d26d74bd1768da5bb79c59fab2b4abe1966324048790c44bc98a6b34b6c"), + nonce: &hex!("c8269e4406fa0be1cf057b2f"), + plaintext: &hex!("323c373e4d85a1fd21f387fdd8c7e6aeebd5aae893d7af286cb214600cba8b9eb06df085a2dc5aed870259f7f3cc81d3eb53bd"), + aad: &hex!("13fb0edcba095cef9c4343a0629fd5020f03729d"), + ciphertext: &hex!("08572b9cf9bcfd21d4403a1218d94476b9ee8c3b94c56625c21ccaf4c0efa34cf22a532389210793699c9de1ab14f8c4c52928"), + tag: &hex!("29968c9fb610940cee9fd5b2f7c8ba21"), + }, + TestVector { + key: &hex!("a67648285b65b9196060aaa02af279170164353e38fb77c3968c403cfa9acdc8"), + nonce: &hex!("0822d6b3e91eccb7e14245fd"), + plaintext: &hex!("b5d271768c12ccabf89eb2d58cbde840c26d1c9b3692581f90c8b0d7b2cff31ae9192d284f5448de7d924a7b08f115edae75aa"), + aad: &hex!("0d9a5af7ac27438d92534d97ff4378274790e59f"), + ciphertext: &hex!("b59041eed7abc2ff507d1932b5c55ac52728e5ac6648dcc74b38870db6181b1989f95a0144f0db368ec50414cfda0b977141e3"), + tag: &hex!("1d12ce89e1261d73470f3ae36ab87288"), + }, + TestVector { + key: &hex!("51162b2435f3cf43471f4cc0ffac98b438501ee9b887843a66e9951ca35b8767"), + nonce: &hex!("dcb902eaa837ed22bf5fa636"), + plaintext: &hex!("3edf43358f5109a4dfb4a02987170a67cdd170f6028f7708bdd7726f476b882b9640270f2270f7babfa384181c8e58c15d04c4"), + aad: &hex!("4d459905ff89aed07dcda43a3d191a3da9309faa"), + ciphertext: &hex!("046a2313d36cbc43b6d0787e5ef37d153090a31d0f6656004034be72b9b07ace3a8abe8614362282d87da40c29c60a1a9f5c40"), + tag: &hex!("c7410b5cb94d2877c189983791cee82e"), + }, + TestVector { + key: &hex!("2fa2beb1cde2226f28fb42a5fb0af3fc58fbb76bf14aa436e6535d466456a0f4"), + nonce: &hex!("50190514a3740b3c0b1df576"), + plaintext: &hex!("a5e0b4837dfca263ba286abf7940b6e70fabb55d8dee5028617c1190fbd327f79b79d2f34db6076ab07cecff7114b15ca02a33"), + aad: &hex!("25142928c1ae9c7b850309e07df359389db539fc"), + ciphertext: &hex!("850fd22bd0897b98ce40bc6c1345a9d59abf796b1b8c34ee8b377e54ee7d59dec05c022ecae96ffdfa1311bdd4e7a9d35aac47"), + tag: &hex!("4b5ab89b4f627ca32d12a1791c286870"), + }, + TestVector { + key: &hex!("a92a797ce2b2f382030b77a1abe94c8076eee88de2dc4929350b244dbdaddd30"), + nonce: &hex!("716f577401a7893c42c91710"), + plaintext: &hex!("9d26ff79a89720fab6e4cda85887e3c0c3f86a4670d065c8ea68042b6f9f16dd2c5b31acb36331f5b1e50f08c492dc12eebd9e"), + aad: &hex!("8642681f1839b88990c2a939f00c9b90766dadac"), + ciphertext: &hex!("3080bcf3604cf81f5f2c6edc80dfe5d877168a9903598a700a0bbae188fadc7a8b76a04b40400f9252d7f9437fa8f024a3bdeb"), + tag: &hex!("8fc56f6bf48efb00476886b2a03ecb89"), + }, + TestVector { + key: &hex!("89d0723e5a087456b7b709b8b21be380b463ba3dc9b79170e9947526798fe91c"), + nonce: &hex!("68e2f307b7d49d4d9c041755"), + plaintext: &hex!("7fe2afb710e8fd49cca1c2ba8fd0814594fba4d667017630e170a8a379fa5837bf370ca1cd4c98bd8c4f13eb7068ffa71ab07c"), + aad: &hex!("b34805b30703a62b6d37c93f2443e1a33154b5fb"), + ciphertext: &hex!("b841012752bbf1dfa7b59366dbf353bf98b61ff2e6e7a13d64d9dcb58b771003c8842ac002aac1fa8ca00a21eaf101ab44f380"), + tag: &hex!("73a93e2722db63c2bbf470d5193b2230"), + }, + TestVector { + key: &hex!("329a6e94b1cce693e445694650d62b8c2c9ab03a09e6d4eca05c48291e576b89"), + nonce: &hex!("78f471bc32f8637a213e87ac"), + plaintext: &hex!("65264d75e1a176a7e966e59109cd074ac5d54740eb0c58084af023e5599eb611846199579d95ba94b6d25ee4d9074b9714f231"), + aad: &hex!("c00c465524e2e2f8a55c0793ed9af851be45a70e"), + ciphertext: &hex!("964d665d1e3c1018dfd883e217cfe4c856cc844f7644b53bb68fbe66f8541fa43ac54e92a2b194d6d8929fe031e94b3e70eca0"), + tag: &hex!("fd511385711236f2e99e6da5042007b7"), + }, + TestVector { + key: &hex!("463b412911767d57a0b33969e674ffe7845d313b88c6fe312f3d724be68e1fca"), + nonce: &hex!("611ce6f9a6880750de7da6cb"), + plaintext: &hex!("e7d1dcf668e2876861940e012fe52a98dacbd78ab63c08842cc9801ea581682ad54af0c34d0d7f6f59e8ee0bf4900e0fd85042"), + aad: &hex!("0a682fbc6192e1b47a5e0868787ffdafe5a50cead3575849990cdd2ea9b3597749403efb4a56684f0c6bde352d4aeec5"), + ciphertext: &hex!("8886e196010cb3849d9c1a182abe1eeab0a5f3ca423c3669a4a8703c0f146e8e956fb122e0d721b869d2b6fcd4216d7d4d3758"), + tag: &hex!("2469cecd70fd98fec9264f71df1aee9a"), + }, + TestVector { + key: &hex!("55f9171a03c21e09e3a5fd771e56bffb775ebb190319f3dc214c4b19f72e5482"), + nonce: &hex!("14f3bf95a08e8f52eb46fbf9"), + plaintext: &hex!("af6b17fd67bc1173b063fc6f0941483cee9cbbbbed3a4dcff55a74b0c9535b977efa640e5b1a30faa859fd3daa8dd780cc94a0"), + aad: &hex!("bac1ddefd111d471e75f0efb0f8127b4da923ecc788a5c91e3e2f65e2943e4caf42f54896604af19ed0b4d8697d45ab9"), + ciphertext: &hex!("3ae8678089522371fe4bd4da99ffd83a32988e0728aa3a4970ded1fe73bc30c2eb1fe24c0ff5ab549ac7e567d7036628fd718d"), + tag: &hex!("cf59603e05f4ed1d2da04e19399b8512"), + }, + TestVector { + key: &hex!("54601d1538e5f04dc3fe95e483e40dec0aaa58375dc868da167c9a599ed345d9"), + nonce: &hex!("c5150872e45c341c2b99c69a"), + plaintext: &hex!("ae87c08c7610a125e7aa6f93fac0f80472530b2ce4d7194f5f4cb8ac025323c6c43a806788ef50c5028764ec32f2839005c813"), + aad: &hex!("93cd7ee8648a64c59d54cdac455b05ffdfc2effe8b19b50babd8c1a8c21f5dc8dc6050e2347f4cd28701594b9f8d4de5"), + ciphertext: &hex!("d5f005dc67bdc9738407ce2401977f59c9c83520e262d0c8db7fe47ae0eada30d674694f008e222f9733a6e63d81499e247567"), + tag: &hex!("3470155144c74929980134db6995dd88"), + }, + TestVector { + key: &hex!("e966c470cbecc819260640d5404c84382e6e649da96d29cad2d4412e671ed802"), + nonce: &hex!("b3a92d6f49fe2cb9c144d339"), + plaintext: &hex!("7adf6fcb41d59b8d2b663010c3d4cf5f5f0b95cf754f76f8626c4428467e5c6684e77e7857b1cc755762e9ea9117e3bb077040"), + aad: &hex!("dfa62a3a4b5b3af6770cfd3cef3bbb4cce3f64925782a9a8a6e15fe3744d8f9310400dd04e8d7966c03850539e440aa5"), + ciphertext: &hex!("5f5b09486e6cd2a854e5622b4988e2408fddaca42c21d946c5cd789fe5a1306ef33c8cd44467ad7aa4c8152bce656a20367284"), + tag: &hex!("2b388109afdada6473435230d747b4eb"), + }, + TestVector { + key: &hex!("4a8a12c0575ec65ae1c5784d2829bc7b04818eb00bd4c90a0d032ea281076e27"), + nonce: &hex!("959f113b705397fb738018b0"), + plaintext: &hex!("0c5571195586e4fc7096fb86cfcd6684081446f3d7adc33a897f03ac4ff6c3cc2019b67bd3184c86070764f6deaa8a10d0d81f"), + aad: &hex!("adb8bc96142a1025122dc22f826957197af33dcdcf6b7ab56bc1a5e17e8534e48b8daf685faf9543bb343614bdf6737f"), + ciphertext: &hex!("84212d5991231d35c4e8621163e5b370a0105a05856866e74df72c0808c062981570d32d274ea732fa4d29f9cfa7839cadbe6a"), + tag: &hex!("39cee3b8fa0bf92605666ccd9eb19840"), + }, + TestVector { + key: &hex!("6197a4fa7cfcedeff223f69ea68b4ddf54b683350c20875be353077e9bbce346"), + nonce: &hex!("1a69ecabd42c53c0ec64fcd0"), + plaintext: &hex!("40a487b4daf866c20f3c4911a0586709c3344aa988dc9c464bcf36cc4e3d92701e611e60cf69f3edbf76cd27ff6ba935026d7f"), + aad: &hex!("b20a7ca5b5b603f661587e01f7ef171823ef463c187ded77a3d616400cc1d2b0b688ac9e927498341560cbc8eb9a4198"), + ciphertext: &hex!("06420fa038ee62db30cc05bfe34c8d2c39a9d439653907c512ed606511921fe76110913a5bfb6b6c7b23d7f8883f5ab65f4b14"), + tag: &hex!("4d3097c9919002cd1da83f29820312ed"), + }, + TestVector { + key: &hex!("c9dbe185023ecaa78be9bfac1b91b9da6bd7c11349feb69e6b0be83a838e77b2"), + nonce: &hex!("8940fa7c6afd3f7a09ec93b6"), + plaintext: &hex!("075be0d61273e6975978d0b88b3fa38fc398d4d0f22a342a8afa5562af0e7c8fa548f0d8faec898a20c97e851754992c1ed4a3"), + aad: &hex!("f17bd357608365e66b98e49191cdc2a3813bba5a1b7988aa8aaaaad4b86d0ef4e2698cad799d63fcd2a5e87c0e3e929a"), + ciphertext: &hex!("615c1097d577363a77bfc7dd57179acb68166e78021b3397d7029ce33cbc848f036b9c07989eeb9f42aeaeebe8542f103b1d32"), + tag: &hex!("a22ab25fd8a6127469e8ce9ff686d575"), + }, + TestVector { + key: &hex!("e6cdcf497a6e119009bf43ac183d2dd4d4e967964ef92811f69eb18d92923305"), + nonce: &hex!("3e88459a76e1dcc890788297"), + plaintext: &hex!("72a3dfb555ba0029fc3d1c85b836f76135bd1858189efdde2db29045f2c26e6a65627d81a0b85ca42e8269d432a41154e929ac"), + aad: &hex!("a359f86ec918537d80a84da7b66bca700c1ff9ec7f8695a30808d484da218d15ae89c5f943e71778445130191f779001"), + ciphertext: &hex!("9ae3f8ccae0bb5789b1105118760c406e41175a76612435cb0c8be225ea6b368c9d08c9d9a24b512d1458e94af79e3060ab69e"), + tag: &hex!("ac3bbc8fd6a7097df6f298411c23e385"), + }, + TestVector { + key: &hex!("de5531b50888b61d63af2210ee23f46d91a5e60312bd578584af586bf22ea756"), + nonce: &hex!("0fde8689b0348bbcfaa89fec"), + plaintext: &hex!("80621e54eef1c92afb1f64ed860e39311eea7e2cca6f5624008c1d2e581d7112b7ee0b559fc3db575b7b7c42ee4f2a20442dc0"), + aad: &hex!("22db97cd5f359f12aec66c51c7da79ba629db4c8c7e5501be2ec1e4cc3f3944b6e3057d093bc68b735b5156950f91804"), + ciphertext: &hex!("933018419a32b7bf65f9777c44889a44b32d61ceddbb46839366ce2ca2ffeb1833f46559e59c93bb07f622d9633f13932cf7f1"), + tag: &hex!("25023a4ee9bdbf525cfef888e2480f86"), + }, + TestVector { + key: &hex!("bc0c6368a9bb2622f6d5ba12de581f003336c298adac34499bf26b11e630f891"), + nonce: &hex!("2aa8f30b567cf1edd818e42d"), + plaintext: &hex!("1dcc1a3167fba55c00d3383e26d386eaa0449154599992da7f7f6598f41b3eb8e4d0a9143dfcab963f5c390a6ae2010fbcf6ec"), + aad: &hex!("0e28ebf87eb757e83031fb836f7b049a46bd740b0a39c9b798d2407e1150da86dfe84121c7c98449559453ad7558e779"), + ciphertext: &hex!("78d00a6e3302369817b9cf1f24ea13c41751382e3fea74403d094737e32fb507184cfebce48d10b4ce8db12ef961e4df2c8e95"), + tag: &hex!("c0aff3594f86b58e229c7ad05c2b84f0"), + }, + TestVector { + key: &hex!("5d98a0c7ad6f9c0b116613ca5082250356a6a9bca55fe1a4a2962b733214dac4"), + nonce: &hex!("8b2d8e8d83bdd6a3125dd997"), + plaintext: &hex!("4f3685c2cfbc856379d1fd00f9611fe4c0a4b9c4013fe1bee144449709a6a7e31ff6fb0da74ed464b066b03b50f19cd7f5f9bc"), + aad: &hex!("2f20636d46ce37e9bb0ca0c41d819e3eabcedacbd1ca3ced112d3ad620bbd3b2effe80d3ec8760706e8f14db83139a70"), + ciphertext: &hex!("8e178c0e3e5d22b3be897e0b8879b0d53fef2efb9946ccff6d717b001e3033f2cc22d01d9551e9c0749de704fbe3189328cbb0"), + tag: &hex!("541b7db823e37b5ed323626b9c6748f6"), + }, + TestVector { + key: &hex!("d80a2703e982de1a2fe706ffe6e389f351ab356ccf056df045e2941b42ef21a4"), + nonce: &hex!("1521ab8f7242cba05427f429"), + plaintext: &hex!("6f9fde28e85776a49cfbad1459d94611757a3cd996aa6e2d702d0483a4d88d532131ebd405b351226b16d19d30d32807a1d511"), + aad: &hex!("5395de90d6bec7c159ab9d6cfa663bdc6295d025e1fcc8b760b9ba42d785eda218dabc6fa7c0f733ad77f61682bff2db"), + ciphertext: &hex!("1e72a8495ceadaf0d31b28ba7cb7c37ccb117761d38fe7dd98eb230ff4ea0b400401e9b5311a7be9b2a533523ad469e2fdb233"), + tag: &hex!("bb174b7624c935ff75b3b77ff7068a98"), + }, + TestVector { + key: &hex!("6d5c69d7135c0b5b7fef512c127fa788092f1a908358ab658b8f23e463409aa5"), + nonce: &hex!("b36cccad38cd6148a384a026"), + plaintext: &hex!("b4e74f5c56f2ea056d9ff931525944dfad207e063ba226c354e0320a50449967e964580d9b57028c14005aba6865f8bc6a3ef8"), + aad: &hex!("b19f4616bb1452251a2a7dbf78f920194f139e0424d27683621d1ee1e865737c2466e058439c8e122e582a7b63607ce9"), + ciphertext: &hex!("1ce12cd5502efa9ea259584ae9b3c7dbd9444380d4b77a2c787f9b2257019b23ee183dffebb3106a26b18d8a23445626a578e2"), + tag: &hex!("62945e31bae3181855b69c37898ac5bf"), + }, + TestVector { + key: &hex!("e6afe3c4db2c1d13edb1c5931b2b4b515ec0fd6201139ee1ea55cec92263830e"), + nonce: &hex!("358bd9ea64177d1e23a41726"), + plaintext: &hex!("710bb3394b094ee7d053bc6599b26dafd337e8a61c580d0446c3bf195e77ca5132c8ec3a47a61579dce38360bba7c65e4d5634"), + aad: &hex!("7e0f841cddd7eeebd1ec7b7b8d0e2f71656e5e9ff3cfa739c0b9d0ec4941a0b3f3b396690dbe5f5082d6fb6dd701c68d"), + ciphertext: &hex!("4574a8db515b41c14c2a962dff34e2161a7195c491b11b79889aff93c5b79a6455df9fe8ef5c5b9edb5da1aa9fe66058b9065f"), + tag: &hex!("7c928d7f5cbac9bb4b5928fe727899eb"), + }, + TestVector { + key: &hex!("5cb962278d79417b7795499e8b92befe4228f3ba5f31992201aa356a6d139a67"), + nonce: &hex!("76f7e7608f09a05f336994cf"), + plaintext: &hex!("2e12cbd468086aa70e2ecd1ddef561e85c225dd083e5956f5c67503344b0ea982bb5044dafbcc02a5b9be1e9b988902d80172b"), + aad: &hex!("032de3fdec273fc8446c2bf767e201f2c7c190acf9d6d321a24a0462cbc3356e798fe23d6c1b4fe83be9c95d71c05504"), + ciphertext: &hex!("c959344a46aa5216d2b37c832436eb72a4a363a6df5642cfbbfd640dea1d64c80bd97eabc1aab192969ee0b799e592a13d2351"), + tag: &hex!("51b227eaf7228a4419f2f3b79b53463a"), + }, + TestVector { + key: &hex!("148579a3cbca86d5520d66c0ec71ca5f7e41ba78e56dc6eebd566fed547fe691"), + nonce: &hex!("b08a5ea1927499c6ecbfd4e0"), + plaintext: &hex!("9d0b15fdf1bd595f91f8b3abc0f7dec927dfd4799935a1795d9ce00c9b879434420fe42c275a7cd7b39d638fb81ca52b49dc41"), + aad: &hex!("e4f963f015ffbb99ee3349bbaf7e8e8e6c2a71c230a48f9d59860a29091d2747e01a5ca572347e247d25f56ba7ae8e05cde2be3c97931292c02370208ecd097ef692687fecf2f419d3200162a6480a57dad408a0dfeb492e2c5d"), + ciphertext: &hex!("2097e372950a5e9383c675e89eea1c314f999159f5611344b298cda45e62843716f215f82ee663919c64002a5c198d7878fd3f"), + tag: &hex!("adbecdb0d5c2224d804d2886ff9a5760"), + }, + TestVector { + key: &hex!("e49af19182faef0ebeeba9f2d3be044e77b1212358366e4ef59e008aebcd9788"), + nonce: &hex!("e7f37d79a6a487a5a703edbb"), + plaintext: &hex!("461cd0caf7427a3d44408d825ed719237272ecd503b9094d1f62c97d63ed83a0b50bdc804ffdd7991da7a5b6dcf48d4bcd2cbc"), + aad: &hex!("19a9a1cfc647346781bef51ed9070d05f99a0e0192a223c5cd2522dbdf97d9739dd39fb178ade3339e68774b058aa03e9a20a9a205bc05f32381df4d63396ef691fefd5a71b49a2ad82d5ea428778ca47ee1398792762413cff4"), + ciphertext: &hex!("32ca3588e3e56eb4c8301b009d8b84b8a900b2b88ca3c21944205e9dd7311757b51394ae90d8bb3807b471677614f4198af909"), + tag: &hex!("3e403d035c71d88f1be1a256c89ba6ad"), + }, + TestVector { + key: &hex!("c277df045d0a1a3956958f271055c229d2634427b1d73e99d54920da69f72e01"), + nonce: &hex!("79e24f84bc77a21a6cb14ee2"), + plaintext: &hex!("5ca68d858cc30b1cb0514c4e9de98e1a1a835df401f69e9ec6f1bcb1158f09114dff551683b3827457f77e17a7097b1ea69eac"), + aad: &hex!("ca09282238d492029afbd30ea9b4aa9d448d77b4b41a791c35ebe3f8e5034ac71210117a843fae647cea020712c27e5c8f85acf933d5e28430c7770862d8dbb197cbbcfe49dd63f6aa05fbd13e32c459342698dfee5935c7c321"), + ciphertext: &hex!("5c5223c8eda59a8dc28b08e6c21482a46e5d84d32c7050bf144fc57f4e8094de133198da7b4b8398b167204aff837da15d9ab2"), + tag: &hex!("378885950a4491bee3cd681d3c957b9a"), + }, + TestVector { + key: &hex!("4d07f78d19e6d8bb32bf209f138307890f0f1ae39362779ff2bf1f9b734fe653"), + nonce: &hex!("d983a5d5af78a3b1cd5fbd58"), + plaintext: &hex!("94f0bbc4340d97d854e25cc7ce85ea1e781e68bf6f639e0a981bb03e3c209cbf5127171cb0fff65bc3ecac92774d10146d1ac5"), + aad: &hex!("a3dc9ff9210bc4b3276909883db2c2aa0762cd22b46901a248c0372d073e7778b9c1d8469b26bb42406e484ef7747f71dea785fc0020a2eac17e0ac3fbe0453629efd68d5678fbecc10af8ffbe7828f826defb638763f4ecfe82"), + ciphertext: &hex!("6543b4d97fccd273b36436fef719ac31bf0e5c4c058ea71aea2a0e5b60e329be6ea81ce386e6e9fe4480e58363c3b2036865ac"), + tag: &hex!("924cf7c0770f228a4b92e9b2a11fc70b"), + }, + TestVector { + key: &hex!("9572b9c57abdf1caae3bebc0e4bbf9e556b5cbacca2c4756050fefd10a666155"), + nonce: &hex!("de292a9858caaccdcab6a433"), + plaintext: &hex!("6f420a32708ccd4df0d3149e8c1d88dceba66ee4546f38db07046ebf30f47627f7fdda1dd79783adabe5f6b6853857b99b864c"), + aad: &hex!("a042d97a9b8f6caf51c5f24522d7ed83e2c5d8ec6b37ef2598134a30e57319300c3fdf92fb1d9797f5ef00971f662aae768f69f9ca0455bd6d1059d5f85b8ecb977006b833f90ac2d5bbf4498c83f4d1a42584c0dfc4a2e2453c"), + ciphertext: &hex!("a9af961d61ab578cc1348eb6f729603f481c5d9bf9bee3a13eda022bd09c03a4f207c21c45c0232a9742ae8f0c54b4278a3a63"), + tag: &hex!("eff9bb26156ec76f0060cd93a959e055"), + }, + TestVector { + key: &hex!("3cc8671c4d25c3cbc887f4dcbd64e531e91cf6252f6ee9c29d9988d20ab6747f"), + nonce: &hex!("f960a09c0b5067280926a9c3"), + plaintext: &hex!("5b58717b0b32076566b58bf37c6133e61468b2be67715fb0007fe390c4b5578decf55502a4e3c12e7bdf0ba98784d126e4753a"), + aad: &hex!("79d73a7ff86698e6114a0f465373fbee029e042424c439b22e3ad37b36b9e02bab82e16844114e99e39c169f462fe61b87c4627c394384acc9531680706e4e56491a304c6075cca37c64db24468c1fb9519605c83f0ee3e0316a"), + ciphertext: &hex!("1d0be097470c1ac30619f63c3961152ab27db88ce694b7bba4db185cb31803cc7bab890e931c90766621bfe5d887eb0cd6995d"), + tag: &hex!("dbd57ea091ff16fc7dbc5435030cc74e"), + }, + TestVector { + key: &hex!("882068be4552d7ad224fc8fa2af00d6abf76ccf1a7689d75f6f0e9bd82c1215e"), + nonce: &hex!("890a5315992f12674d1c8018"), + plaintext: &hex!("8464c03e0280cb1f63c054a24a050e980f60cc7313f09f2092c45d77bbe9ad2a8c1f6cdca2acd8c57c87e887edadb66bcb66c4"), + aad: &hex!("916721df816b1cad531dee8e4a8e634d43ed87db99609bcc986d16bfac2cff577d536d749a5c3625de53c5351825c228911f0a64be1fc9738a26394efe5332c0762bf59b65d3f1c5aafa9ca2e63eccd59568e6c0269950911a71"), + ciphertext: &hex!("020e297d907177dba12dde4bfe1b0ff9b6a9d9db0695193e4181449e157137b59b488616ba151b06d889f8498ce373d2396ab9"), + tag: &hex!("e48537ecb27460b477a6e7c3463dbcb0"), + }, + TestVector { + key: &hex!("4deadcf0f7e19231f8afcb6fb902b105bef23f2fa9323a51833ff8368ccb4f91"), + nonce: &hex!("6d4d01abd587ed110e512ed2"), + plaintext: &hex!("75686e0fdd3fd96f3e6dfafd7a2a907f9f375d93943cb2229bd72b032bf624af4fc72071289386e3dccc45959e47ab42b261a2"), + aad: &hex!("31a2797318104b2dc9977e599435b041c56bafe5e7d901a58614c2d3fb9d220e3fd3e2828cef69e0604ed73340cb1e21967294dcd874893942442200b2a5b860ee8cf91e1d8eb3d364d0e43e84f6379f434a1ae17c236b216842"), + ciphertext: &hex!("8feaf9a089599812117a67aed2f4bf3431ff1f6cfd64ea5ff475287abb4ff1ab6b3e4f8a55d1c6b3f08594f403e771ec7e9956"), + tag: &hex!("5040407621712e053591179e1689698e"), + }, + TestVector { + key: &hex!("80f1c515f10d79cdbee275213aa9ac0845e2cf42874f7e695081cb103abf1a27"), + nonce: &hex!("399d5f9b218b62ff60c267bd"), + plaintext: &hex!("9e95221873f65282dd1ec75494d2500e62a2b6edda5a6f33b3d4dd7516ef25cf4154472e61c6aed2749c5a7d86637052b00f54"), + aad: &hex!("d2a8fff8ae24a6a5efc75764549a765222df317e323a798cbb8a23d1af8fdf8a3b767f55703b1c0feba3912d4234441978191262f1999c69caa4e9a3e0454c143af0022cd6e44cec14149f9e9964a1f2c5e5a6e3e768bd870060"), + ciphertext: &hex!("4f996562e23ebbfd4fe26523aee9525b13d6e134e72d21bdc7f195c6403501fd8300b6e597b668f199f93591ba742a91b54454"), + tag: &hex!("2da1c7325f58575d275abf96c7fa9e51"), + }, + TestVector { + key: &hex!("c2c6e9be5a480a4a56bfcd0e268faa2276093bd1f7e8ce61e746d003decc761e"), + nonce: &hex!("c1541eb25721d4856df8f928"), + plaintext: &hex!("87d22e0318fbbb420b86b0585bd12c14645ff2c742e5639b3a114cc96c5f738edfbe2055116f259e3d6c14cb6d8fca45708289"), + aad: &hex!("f34e79e5fe437eda03ccfef2f1d6319df51a71c9891863e4b98a7298bd64490460354db5a28b0fadcb815024ea17f3b84810e27954afb1fdf44f0defb930b1793684a781310b9af95b4bcf0a727a2cb0ac529b805811b3721d98"), + ciphertext: &hex!("b5d6e57c7aa0240e0b6e332d3b3323b525a3d8a553ad041ba599e909188da537c3293d1687fb967882d16a5615b84e95f9dd77"), + tag: &hex!("1cce334cec4b51216cac0fc620cdadf9"), + }, + TestVector { + key: &hex!("ea0d6184a71456e27f9ac82dfc7f6694c898f7c0d19d1cb0db4e575dd0094bb6"), + nonce: &hex!("5018fb816d515511bfb939d5"), + plaintext: &hex!("083147d0c80f134f7393855c8a95bf6e6abd6f9a7b1fca584e8bfc6b5dc13a8edbfd473e232c041d9be9ee7709dc86b3aa320a"), + aad: &hex!("8bc6bd0a263212bd7281fd1a45e512fca104f859358eae9293a297c529a0abaffd8a77507b9069040f2b3141a7620691e110a8b593b956d8e3e71694506b89018a03861c1ba6082687adce15a874c73477430cef075eba077a93"), + ciphertext: &hex!("f0a5c4941782e2f2941dd05acee29b65341773f2e8d51935a3f4fa6f268ff030c880976cf1ee858f6571abd8411b695a2fadf0"), + tag: &hex!("067d8cc2d38c30697272daa00c7f70cf"), + }, + TestVector { + key: &hex!("c624feb6cb0d78d634b627134c692f0bf5debf84d8639e22ff27ce2ace49d438"), + nonce: &hex!("a54f4f1204255f6b312222cd"), + plaintext: &hex!("ec34f45c1b70fd56518cc5c404cc13330ab7d51c10f4d2cfeb26b097ae76897191ec1b3953b0086e425c7da221d29f65d5ccf3"), + aad: &hex!("d9099ba6be50dca77e0b9803766ad993132479fbab43b8f4126a7f9ef673ac0caf2de235e1e84ad9fe505c43d1ac779f5072c025c14ea0d930ce39db8c5930baada23b3e4654470e559fcb6eb1c133a77318b87cc7913e12d404"), + ciphertext: &hex!("713d28a5123d65e82cca6e7fd919e1e5e3bdaab12ae715cf8b7c974eb5f62be8c3b42637074c6b891f6c6033eb4b7e61db9f0b"), + tag: &hex!("01ededff6e4d1dce4ac790218e208ebe"), + }, + TestVector { + key: &hex!("1afc68b32596198ae0f3a8612751c2413322e8054ff2ac6bede3d4a1ee20ee62"), + nonce: &hex!("356860e76e794492de6a68f3"), + plaintext: &hex!("293041038f9e8edee23d2f18bce87b522380f1fa18b3021830a54ab891da8548095228ed9860176152e27945d66254f0db8590"), + aad: &hex!("205e44009e0ef963838aff615b35c9f1271d487cf719677d956718bce8ab676cceb636ad381432c5c790c26b07051b661a2fec4e607f9644f84993c8335db21ae36b6008bab2883ad7541809bf5f49272295c1c1f1cf8c678553"), + ciphertext: &hex!("e06109680d5fefd345665ec9a5b2e7bf3ece3af1b62841a95c453e7753b5a1d6d8a10b3c6c42df1f23832b74e74871821f1c0b"), + tag: &hex!("953d8d04f70e2af055ac902a455235b2"), + }, + TestVector { + key: &hex!("f61b723359e798fefecc26b10b168dc331c639079598f1f651166cc58c671ee1"), + nonce: &hex!("b07e9407b592d4fd95509343"), + plaintext: &hex!("2724f1ad6b5b409a59c7f2ff649eb24b4a33a03d7a0426e29a6ea3aa91b4f00699fbed75bb7189964303e2e9fe3a7e5f74b7a1"), + aad: &hex!("1429c6f27828cb94ad5e62451da10fd574660cec2b8f279a19bbb8a167a630d3ac60db04e8faa02204792e49aed4501844a419d3ecdff0d03799866fee81a91187b08a44d5bb617ff3b2cef79cd48750ea20903e1d3627a17730"), + ciphertext: &hex!("362bad8de943dce8f53edf682d02e1d893c23c5272b13fd35b492f8477083a8c34027db32b6131931f03555ac5fbc6dbb13801"), + tag: &hex!("a51775606343755691f125019b44fdfc"), + }, + TestVector { + key: &hex!("6be7f4d18ff0fbdd9b3b3cacaba4629a0c617387079add62f6ce1584b33faad1"), + nonce: &hex!("fda568c9cb13d9c176bcef03"), + plaintext: &hex!("4df668e99d5068604a48bcca5baa8245435928558a83d68d7b0b081861224e9bd39ea8f2d55a635949e66c6f6a7ff5cc34dd94"), + aad: &hex!("11ebeb97dd4a9925c1fbe2b9af77392058d2d971e42db15da39f090d7bc132573c34bf7d92a2d72dc66ee6840c3ff07985b8976ee8d8f36bf47ae330b899fdc60652dd5a23c45f3680f11951f019e0697c8acfcaa95f01b9c7dd"), + ciphertext: &hex!("488b40ad594e1845ccdd9e9467fc5e1afbbfde34e57d45bfcd30b61cc326d57fe8e3f31a39cdebf00f60bbd2c3cdf69f756eff"), + tag: &hex!("3bf3fbab9b48486fd08a5552604df639"), + }, +]; + +tests!(Aes256Gcm, TEST_VECTORS); + +// Test vectors from Wycheproof +aead::new_test!(wycheproof, "wycheproof-256", Aes256Gcm); diff --git a/vendor/aes-gcm/tests/common/mod.rs b/vendor/aes-gcm/tests/common/mod.rs new file mode 100644 index 00000000..6255bb3a --- /dev/null +++ b/vendor/aes-gcm/tests/common/mod.rs @@ -0,0 +1,97 @@ +//! Common functionality shared by tests + +/// Test vectors +#[derive(Debug)] +pub struct TestVector { + pub key: &'static K, + pub nonce: &'static [u8; 12], + pub aad: &'static [u8], + pub plaintext: &'static [u8], + pub ciphertext: &'static [u8], + pub tag: &'static [u8; 16], +} + +#[macro_export] +macro_rules! tests { + ($aead:ty, $vectors:expr) => { + #[test] + fn encrypt() { + for vector in $vectors { + let key = GenericArray::from_slice(vector.key); + let nonce = GenericArray::from_slice(vector.nonce); + let payload = Payload { + msg: vector.plaintext, + aad: vector.aad, + }; + + let cipher = <$aead>::new(key); + let ciphertext = cipher.encrypt(nonce, payload).unwrap(); + let (ct, tag) = ciphertext.split_at(ciphertext.len() - 16); + assert_eq!(vector.ciphertext, ct); + assert_eq!(vector.tag, tag); + } + } + + #[test] + fn decrypt() { + for vector in $vectors { + let key = GenericArray::from_slice(vector.key); + let nonce = GenericArray::from_slice(vector.nonce); + let mut ciphertext = Vec::from(vector.ciphertext); + ciphertext.extend_from_slice(vector.tag); + + let payload = Payload { + msg: &ciphertext, + aad: vector.aad, + }; + + let cipher = <$aead>::new(key); + let plaintext = cipher.decrypt(nonce, payload).unwrap(); + + assert_eq!(vector.plaintext, plaintext.as_slice()); + } + } + + #[test] + fn decrypt_modified() { + let vector = &$vectors[0]; + let key = GenericArray::from_slice(vector.key); + let nonce = GenericArray::from_slice(vector.nonce); + + let mut ciphertext = Vec::from(vector.ciphertext); + ciphertext.extend_from_slice(vector.tag); + + // Tweak the first byte + ciphertext[0] ^= 0xaa; + + let payload = Payload { + msg: &ciphertext, + aad: vector.aad, + }; + + let cipher = <$aead>::new(key); + assert!(cipher.decrypt(nonce, payload).is_err()); + } + + #[test] + fn decrypt_in_place_detached_modified() { + let vector = &$vectors.iter().last().unwrap(); + let key = GenericArray::from_slice(vector.key); + let nonce = GenericArray::from_slice(vector.nonce); + + let mut buffer = Vec::from(vector.ciphertext); + assert!(!buffer.is_empty()); + + // Tweak the first byte + let mut tag = GenericArray::clone_from_slice(vector.tag); + tag[0] ^= 0xaa; + + let cipher = <$aead>::new(key); + assert!(cipher + .decrypt_in_place_detached(nonce, &[], &mut buffer, &tag) + .is_err()); + + assert_eq!(vector.ciphertext, buffer); + } + }; +} diff --git a/vendor/aes-gcm/tests/data/wycheproof-128.blb b/vendor/aes-gcm/tests/data/wycheproof-128.blb new file mode 100644 index 00000000..5e4ea3f1 Binary files /dev/null and b/vendor/aes-gcm/tests/data/wycheproof-128.blb differ diff --git a/vendor/aes-gcm/tests/data/wycheproof-256.blb b/vendor/aes-gcm/tests/data/wycheproof-256.blb new file mode 100644 index 00000000..1a37b698 Binary files /dev/null and b/vendor/aes-gcm/tests/data/wycheproof-256.blb differ diff --git a/vendor/aes-gcm/tests/other_ivlen.rs b/vendor/aes-gcm/tests/other_ivlen.rs new file mode 100644 index 00000000..71d3c770 --- /dev/null +++ b/vendor/aes-gcm/tests/other_ivlen.rs @@ -0,0 +1,77 @@ +//! Tests for AES-GCM when used with non-96-bit nonces. +//! +//! Vectors taken from NIST CAVS vectors' `gcmEncryptExtIV128.rsp` file: +//! + +use aead::{ + generic_array::{typenum, GenericArray}, + Aead, KeyInit, +}; +use aes::Aes128; +use aes_gcm::AesGcm; +use hex_literal::hex; + +/// Based on the following `gcmEncryptExtIV128.rsp` test vector: +/// +/// [Keylen = 128] +/// [IVlen = 8] +/// [PTlen = 128] +/// [AADlen = 0] +/// [Taglen = 128] +/// +/// Count = 0 +mod ivlen8 { + use super::*; + + type Aes128GcmWith8BitNonce = AesGcm; + + #[test] + fn encrypt() { + let key = hex!("15b2d414826453f9e1c7dd0b69d8d1eb"); + let nonce = hex!("b6"); + let plaintext = hex!("8cfa255530c6fbc19d51bd4aeb39c91b"); + + let ciphertext = Aes128GcmWith8BitNonce::new(&key.into()) + .encrypt(GenericArray::from_slice(&nonce), &plaintext[..]) + .unwrap(); + + let (ct, tag) = ciphertext.split_at(ciphertext.len() - 16); + assert_eq!(hex!("4822cb98bd5f5d921ee19285c9032375"), ct); + assert_eq!(hex!("8a40670ebac98cf4e9cc1bf8f803167d"), tag); + } +} + +/// Based on the following `gcmEncryptExtIV128.rsp` test vector: +/// +/// [Keylen = 128] +/// [IVlen = 1024] +/// [PTlen = 128] +/// [AADlen = 0] +/// [Taglen = 128] +/// +/// Count = 0 +mod ivlen1024 { + use super::*; + + type Aes128GcmWith1024BitNonce = AesGcm; + + #[test] + fn encrypt() { + let key = hex!("71eebc49c8fb773b2224eaff3ad68714"); + let nonce = hex!( + "07e961e67784011f72faafd95b0eb64089c8de15ad685ec57e63d56e679d3e20 + 2b18b75fcbbec3185ffc41653bc2ac4ae6ae8be8c85636f353a9d19a86100d0b + d035cc6bdefcab4318ac7b1a08b819427ad8f6abc782466c6ebd4d6a0dd76e78 + 389b0a2a66506bb85f038ffc1da220c24f3817c7b2d02c5e8fc5e7e3be5074bc" + ); + let plaintext = hex!("705da82292143d2c949dc4ba014f6396"); + + let ciphertext = Aes128GcmWith1024BitNonce::new(&key.into()) + .encrypt(GenericArray::from_slice(&nonce), &plaintext[..]) + .unwrap(); + + let (ct, tag) = ciphertext.split_at(ciphertext.len() - 16); + assert_eq!(hex!("032363cf0828a03553478bec0f51f372"), ct); + assert_eq!(hex!("c681b2c568feaa21900bc44b86aeb946"), tag); + } +} diff --git a/vendor/aes/.cargo-checksum.json b/vendor/aes/.cargo-checksum.json new file mode 100644 index 00000000..af88fe49 --- /dev/null +++ b/vendor/aes/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"eca699db9c1d803f1dd09b642057b24bcec570c47ad44d5ffd6df2499ea0355a","Cargo.toml":"0e3a91948ceb119a3f36209a8c5a6a7627cd7a09de903b5e606f563276376fed","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"f7e8ab639afef15573680c97f796166835cbeb3865175882fea41c60d106b733","README.md":"fd8bd9c342defe127d5e751445af9b67ff84de509a3e595c66011909ef8d4428","benches/mod.rs":"dbd545b67721cd5e351c431c0eeb115699c903a2584a3d414ccbb919c44221c2","src/armv8.rs":"bc8ff3cae2f799d849105b79091604e1579ae5e8a8fbe19db24c6ccbf48146a4","src/armv8/encdec.rs":"54f85c5942fbb384c106321fb54aa06f29ae16be87ebce127fd4932a329a4feb","src/armv8/expand.rs":"d40ee141eb7dec4ccb675455ec93fe08a75dfd228bc5339096cfa8d7270ff375","src/armv8/hazmat.rs":"f6d722a53ca464b16b1bc9bb7c23a5780510252cbcb059735e2acf656c5b2cbe","src/armv8/intrinsics.rs":"3192f65da7cac81f3a48601d950c66c72814fa9cacab9a9d8c8969dbae6b098c","src/armv8/test_expand.rs":"7bc04e7fc5bba65f4451c86ba2e80ce98b04faa734f16d28af09660c5623d96a","src/autodetect.rs":"150d63066a8f1a6cac359661752db49d2d5c8d2d5b34cfee413072ff95b9041f","src/hazmat.rs":"7198ef0d62287642cd4d7394295f333fbc69d95938c7541f82f2492ce9bd7d47","src/lib.rs":"8904ed0f1da5d3c6ca6cfb61add4a957054a9f95ce573c3ab198b59ba9ab06cd","src/ni.rs":"15b9a67dbedc3b558ddec063489be4a6607e568afddd8345506be36952fc3bde","src/ni/aes128.rs":"88b94c99163b6b82810d7817e02374ddca4086b0896a8ebe183241a604ec92be","src/ni/aes192.rs":"156254b46e469a20e09a1cefa22bae2afd9c10e2b68fd2bf40eaf9a05095cdda","src/ni/aes256.rs":"f9fba1a4ac1e91fc908f3164460fc531f91cf0b0d015b3463056d0bd97981eae","src/ni/hazmat.rs":"eeeb4a8cd92204095ecef3d40e1786dede05b63afba41c9fa3e9b871f40eb6d8","src/ni/test_expand.rs":"6ad46711aeb49c21144ea31f801493ab87d3cb19d35bb3610657bfadfa75d044","src/ni/utils.rs":"10fe6c0ad778a59cde5cef6cb6bc478cc68d21e28bda9331ced3c26b0a732426","src/soft.rs":"3a84211717fdc86a2b0f0d9086f33410bee2ff9be480f50c981980f678a0c2a8","src/soft/fixslice32.rs":"c69c0fa430cb62c4d88a13d5c3387202e1962b47978a6a7026bd34789f2d2577","src/soft/fixslice64.rs":"b071d85916e4e09da703168eb7cebc2ba4c4ab2b783713b8caf9541742b741e3","tests/data/aes128.blb":"96bd534f5025089a88d1062d666e1228fc507334b61f08ba9033d3e85e36a356","tests/data/aes192.blb":"4361e569dd7413058b1c73b89eeff9db1f7fd199c36f21a2e63c6a667f81d23d","tests/data/aes256.blb":"28c4f1e84e188645a59077f1304816d18ff1115f974a46eea19ab76a26ef467e","tests/hazmat.rs":"c74cc6eb51f1064222206e9ae7a21fafc9188dd3ba3d3cde7aeb4f9e388cd1ce","tests/mod.rs":"33a9de6d44d892e24c6fdd58b584d1d7f625adefce065a2c4134095177d3d723"},"package":"b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"} \ No newline at end of file diff --git a/vendor/aes/CHANGELOG.md b/vendor/aes/CHANGELOG.md new file mode 100644 index 00000000..92e1c441 --- /dev/null +++ b/vendor/aes/CHANGELOG.md @@ -0,0 +1,146 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.8.4 (2024-02-13) +### Changed +- Assert soundness preconditions for ARMv8 key expansion ([#407], [#408]) + +[#407]: https://github.com/RustCrypto/block-ciphers/pull/407 +[#408]: https://github.com/RustCrypto/block-ciphers/pull/408 + +## 0.8.3 (2023-06-17) +### Added +- Support `aes_armv8` on Rust 1.61+ using `asm!` ([#365]) + +[#365]: https://github.com/RustCrypto/block-ciphers/pull/365 + +## 0.8.2 (2022-10-27) +### Fixed +- Crate documentation around configuration flags ([#343]) + +[#343]: https://github.com/RustCrypto/block-ciphers/pull/343 + +## 0.8.1 (2022-02-17) +### Fixed +- Minimal versions build ([#303]) + +[#303]: https://github.com/RustCrypto/block-ciphers/pull/303 + +## 0.8.0 (2022-02-10) +### Changed +- Bump `cipher` dependency to v0.4 ([#284]) + +### Added +- Encrypt-only and decrypt-only cipher types ([#284]) + +[#284]: https://github.com/RustCrypto/block-ciphers/pull/284 + +## 0.7.5 (2021-08-26) +### Changed +- Bump `ctr` dependency to v0.8 ([#275]) +- Use the `aes` target feature instead of `crypto` on ARMv8 ([#279]) +- Use `core::arch::aarch64::vst1q_u8` intrinsic on `armv8` ([#280]) +- Bump `cpufeatures` dependency to v0.2 ([#281]) + +[#275]: https://github.com/RustCrypto/block-ciphers/pull/275 +[#279]: https://github.com/RustCrypto/block-ciphers/pull/279 +[#280]: https://github.com/RustCrypto/block-ciphers/pull/280 +[#281]: https://github.com/RustCrypto/block-ciphers/pull/281 + +## 0.7.4 (2021-06-01) +### Added +- Soft `hazmat` backend ([#267], [#268]) +- Parallel `hazmat` APIs ([#269]) + +[#267]: https://github.com/RustCrypto/block-ciphers/pull/267 +[#268]: https://github.com/RustCrypto/block-ciphers/pull/268 +[#269]: https://github.com/RustCrypto/block-ciphers/pull/269 + +## 0.7.3 (2021-05-26) +### Added +- `hazmat` feature/module providing round function access ([#257], [#259], [#260]) +- `BLOCK_SIZE` constant ([#263]) + +[#257]: https://github.com/RustCrypto/block-ciphers/pull/257 +[#259]: https://github.com/RustCrypto/block-ciphers/pull/259 +[#260]: https://github.com/RustCrypto/block-ciphers/pull/260 +[#263]: https://github.com/RustCrypto/block-ciphers/pull/263 + +## 0.7.2 (2021-05-17) +### Added +- Nightly-only ARMv8 intrinsics support gated under the `armv8` feature ([#250]) + +[#250]: https://github.com/RustCrypto/block-ciphers/pull/250 + +## 0.7.1 (2021-05-09) +### Fixed +- Restore `fixslice64.rs` ([#247]) + +[#247]: https://github.com/RustCrypto/block-ciphers/pull/247 + +## 0.7.0 (2021-04-29) +### Added +- Auto-detection support for AES-NI; MSRV 1.49+ ([#208], [#214], [#215], [#216]) +- `ctr` feature providing SIMD accelerated AES-CTR ([#200]) + +### Changed +- Unify the `aes`, `aesni`, `aes-ctr`, and `aes-soft` crates ([#200]) +- Use `cfg-if` crate ([#203]) +- Rename `semi_fixslice` feature to `compact` ([#204]) +- Refactor NI backend ([#224], [#225]) +- Bump `cipher` crate dependency to v0.3 ([#235]) +- Bump `ctr` crate dependency to v0.7 ([#237]) + +[#200]: https://github.com/RustCrypto/block-ciphers/pull/200 +[#203]: https://github.com/RustCrypto/block-ciphers/pull/203 +[#204]: https://github.com/RustCrypto/block-ciphers/pull/204 +[#208]: https://github.com/RustCrypto/block-ciphers/pull/208 +[#214]: https://github.com/RustCrypto/block-ciphers/pull/214 +[#215]: https://github.com/RustCrypto/block-ciphers/pull/215 +[#216]: https://github.com/RustCrypto/block-ciphers/pull/216 +[#224]: https://github.com/RustCrypto/block-ciphers/pull/224 +[#225]: https://github.com/RustCrypto/block-ciphers/pull/225 +[#235]: https://github.com/RustCrypto/block-ciphers/pull/235 +[#237]: https://github.com/RustCrypto/block-ciphers/pull/237 + +## 0.6.0 (2020-10-16) +### Changed +- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#167]) + +[#167]: https://github.com/RustCrypto/block-ciphers/pull/167 + +## 0.5.1 (2020-08-25) +### Changed +- Bump `aesni` dependency to v0.9 ([#158]) + +[#158]: https://github.com/RustCrypto/block-ciphers/pull/158 + +## 0.5.0 (2020-08-07) +### Changed +- Bump `block-cipher` dependency to v0.8 ([#138]) +- Bump `opaque-debug` dependency to v0.3 ([#140]) + +[#138]: https://github.com/RustCrypto/block-ciphers/pull/138 +[#140]: https://github.com/RustCrypto/block-ciphers/pull/140 + +## 0.4.0 (2020-06-05) +### Changed +- Bump `block-cipher` dependency to v0.7 ([#86], [#122]) +- Update to Rust 2018 edition ([#86]) + +[#121]: https://github.com/RustCrypto/block-ciphers/pull/122 +[#86]: https://github.com/RustCrypto/block-ciphers/pull/86 + +## 0.3.2 (2018-11-01) + +## 0.3.1 (2018-10-04) + +## 0.3.0 (2018-10-03) + +## 0.2.0 (2018-07-27) + +## 0.1.0 (2018-06-22) diff --git a/vendor/aes/Cargo.toml b/vendor/aes/Cargo.toml new file mode 100644 index 00000000..c7214b67 --- /dev/null +++ b/vendor/aes/Cargo.toml @@ -0,0 +1,70 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "aes" +version = "0.8.4" +authors = ["RustCrypto Developers"] +description = "Pure Rust implementation of the Advanced Encryption Standard (a.k.a. Rijndael)" +documentation = "https://docs.rs/aes" +readme = "README.md" +keywords = [ + "crypto", + "aes", + "rijndael", + "block-cipher", +] +categories = [ + "cryptography", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/block-ciphers" +resolver = "1" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.cfg-if] +version = "1" + +[dependencies.cipher] +version = "0.4.2" + +[dev-dependencies.cipher] +version = "0.4.2" +features = ["dev"] + +[dev-dependencies.hex-literal] +version = "0.3" + +[features] +hazmat = [] + +[target."cfg(all(aes_armv8, target_arch = \"aarch64\"))".dependencies.zeroize] +version = "1.5.6" +features = ["aarch64"] +optional = true +default_features = false + +[target."cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))".dependencies.cpufeatures] +version = "0.2" + +[target."cfg(not(all(aes_armv8, target_arch = \"aarch64\")))".dependencies.zeroize] +version = "1.6.0" +optional = true +default_features = false diff --git a/vendor/aes/LICENSE-APACHE b/vendor/aes/LICENSE-APACHE new file mode 100644 index 00000000..78173fa2 --- /dev/null +++ b/vendor/aes/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 [yyyy] [name of copyright owner] + +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/vendor/aes/LICENSE-MIT b/vendor/aes/LICENSE-MIT new file mode 100644 index 00000000..f5b157a6 --- /dev/null +++ b/vendor/aes/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018 Artyom Pavlov + +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/vendor/aes/README.md b/vendor/aes/README.md new file mode 100644 index 00000000..ce95a3a1 --- /dev/null +++ b/vendor/aes/README.md @@ -0,0 +1,95 @@ +# RustCrypto: Advanced Encryption Standard (AES) + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] +[![Build Status][build-image]][build-link] +[![Downloads][downloads-image]][crate-link] +[![HAZMAT][hazmat-image]][hazmat-link] + +Pure Rust implementation of the [Advanced Encryption Standard (AES)][1]. + +This crate implements the low-level AES block function, and is intended +for use for implementing higher-level constructions *only*. It is NOT +intended for direct use in applications. + +[Documentation][docs-link] + + + +## Security + +### ⚠️ Warning: [Hazmat!][hazmat-link] + +This crate does not ensure ciphertexts are authentic (i.e. by using a MAC to +verify ciphertext integrity), which can lead to serious vulnerabilities +if used incorrectly! + +To avoid this, use an [AEAD][2] mode based on AES, such as [AES-GCM][3] or [AES-GCM-SIV][4]. +See the [RustCrypto/AEADs][5] repository for more information. + +USE AT YOUR OWN RISK! + +### Notes + +This crate has received one [security audit by NCC Group][6], with no significant +findings. We would like to thank [MobileCoin][7] for funding the audit. + +All implementations contained in the crate are designed to execute in constant +time, either by relying on hardware intrinsics (i.e. AES-NI on x86/x86_64), or +using a portable implementation based on bitslicing. + +## Minimum Supported Rust Version + +Rust **1.56** or higher. + +Minimum supported Rust version can be changed in future releases, but it will +be done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/aes.svg +[crate-link]: https://crates.io/crates/aes +[docs-image]: https://docs.rs/aes/badge.svg +[docs-link]: https://docs.rs/aes/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers +[build-image]: https://github.com/RustCrypto/block-ciphers/workflows/aes/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/block-ciphers/actions?query=workflow%3Aaes +[downloads-image]: https://img.shields.io/crates/d/aes.svg +[hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg +[hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md + +[//]: # (general links) + +[1]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard +[2]: https://en.wikipedia.org/wiki/Authenticated_encryption +[3]: https://github.com/RustCrypto/AEADs/tree/master/aes-gcm +[4]: https://github.com/RustCrypto/AEADs/tree/master/aes-gcm-siv +[5]: https://github.com/RustCrypto/AEADs +[6]: https://research.nccgroup.com/2020/02/26/public-report-rustcrypto-aes-gcm-and-chacha20poly1305-implementation-review/ +[7]: https://www.mobilecoin.com/ diff --git a/vendor/aes/benches/mod.rs b/vendor/aes/benches/mod.rs new file mode 100644 index 00000000..579b0731 --- /dev/null +++ b/vendor/aes/benches/mod.rs @@ -0,0 +1,62 @@ +#![feature(test)] +extern crate test; + +use cipher::{block_decryptor_bench, block_encryptor_bench, KeyInit}; + +block_encryptor_bench!( + Key: aes::Aes128, + aes128_encrypt_block, + aes128_encrypt_blocks, +); +block_decryptor_bench!( + Key: aes::Aes128, + aes128_decrypt_block, + aes128_decrypt_blocks, +); +block_encryptor_bench!( + Key: aes::Aes192, + aes192_encrypt_block, + aes192_encrypt_blocks, +); +block_decryptor_bench!( + Key: aes::Aes192, + aes192_decrypt_block, + aes192_decrypt_blocks, +); +block_encryptor_bench!( + Key: aes::Aes256, + aes256_encrypt_block, + aes256_encrypt_blocks, +); +block_decryptor_bench!( + Key: aes::Aes256, + aes256_decrypt_block, + aes256_decrypt_blocks, +); + +#[bench] +fn aes128_new(bh: &mut test::Bencher) { + bh.iter(|| { + let key = test::black_box(Default::default()); + let cipher = aes::Aes128::new(&key); + test::black_box(&cipher); + }); +} + +#[bench] +fn aes192_new(bh: &mut test::Bencher) { + bh.iter(|| { + let key = test::black_box(Default::default()); + let cipher = aes::Aes192::new(&key); + test::black_box(&cipher); + }); +} + +#[bench] +fn aes256_new(bh: &mut test::Bencher) { + bh.iter(|| { + let key = test::black_box(Default::default()); + let cipher = aes::Aes256::new(&key); + test::black_box(&cipher); + }); +} diff --git a/vendor/aes/src/armv8.rs b/vendor/aes/src/armv8.rs new file mode 100644 index 00000000..3ece1b44 --- /dev/null +++ b/vendor/aes/src/armv8.rs @@ -0,0 +1,343 @@ +//! AES block cipher implementation using the ARMv8 Cryptography Extensions. +//! +//! Based on this C intrinsics implementation: +//! +//! +//! Original C written and placed in public domain by Jeffrey Walton. +//! Based on code from ARM, and by Johannes Schneiders, Skip Hovsmith and +//! Barry O'Rourke for the mbedTLS project. + +#![allow(clippy::needless_range_loop)] + +#[cfg(feature = "hazmat")] +pub(crate) mod hazmat; + +mod encdec; +mod expand; +mod intrinsics; +#[cfg(test)] +mod test_expand; + +use self::{ + encdec::{decrypt1, decrypt8, encrypt1, encrypt8}, + expand::{expand_key, inv_expanded_keys}, +}; +use crate::{Block, Block8}; +use cipher::{ + consts::{U16, U24, U32, U8}, + inout::InOut, + AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, + BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, +}; +use core::arch::aarch64::*; +use core::fmt; + +macro_rules! define_aes_impl { + ( + $name:ident, + $name_enc:ident, + $name_dec:ident, + $name_back_enc:ident, + $name_back_dec:ident, + $key_size:ty, + $rounds:tt, + $doc:expr $(,)? + ) => { + #[doc=$doc] + #[doc = "block cipher"] + #[derive(Clone)] + pub struct $name { + encrypt: $name_enc, + decrypt: $name_dec, + } + + impl $name { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + self.encrypt.get_enc_backend() + } + + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + self.decrypt.get_dec_backend() + } + } + + impl BlockCipher for $name {} + + impl KeySizeUser for $name { + type KeySize = $key_size; + } + + impl KeyInit for $name { + #[inline] + fn new(key: &Key) -> Self { + let encrypt = $name_enc::new(key); + let decrypt = $name_dec::from(&encrypt); + Self { encrypt, decrypt } + } + } + + impl From<$name_enc> for $name { + #[inline] + fn from(encrypt: $name_enc) -> $name { + let decrypt = (&encrypt).into(); + Self { encrypt, decrypt } + } + } + + impl From<&$name_enc> for $name { + #[inline] + fn from(encrypt: &$name_enc) -> $name { + let decrypt = encrypt.into(); + let encrypt = encrypt.clone(); + Self { encrypt, decrypt } + } + } + + impl BlockSizeUser for $name { + type BlockSize = U16; + } + + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + self.encrypt.encrypt_with_backend(f) + } + } + + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + self.decrypt.decrypt_with_backend(f) + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + #[derive(Clone)] + pub struct $name_enc { + round_keys: [uint8x16_t; $rounds], + } + + impl $name_enc { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + $name_back_enc(self) + } + } + + impl BlockCipher for $name_enc {} + + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } + + impl KeyInit for $name_enc { + fn new(key: &Key) -> Self { + Self { + round_keys: unsafe { expand_key(key.as_ref()) }, + } + } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } + + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } + + impl Drop for $name_enc { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + #[derive(Clone)] + pub struct $name_dec { + round_keys: [uint8x16_t; $rounds], + } + + impl $name_dec { + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + $name_back_dec(self) + } + } + + impl BlockCipher for $name_dec {} + + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } + + impl KeyInit for $name_dec { + fn new(key: &Key) -> Self { + $name_enc::new(key).into() + } + } + + impl From<$name_enc> for $name_dec { + #[inline] + fn from(enc: $name_enc) -> $name_dec { + Self::from(&enc) + } + } + + impl From<&$name_enc> for $name_dec { + fn from(enc: &$name_enc) -> $name_dec { + let mut round_keys = enc.round_keys; + unsafe { inv_expanded_keys(&mut round_keys) }; + Self { round_keys } + } + } + + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()); + } + } + + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } + + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + + impl Drop for $name_dec { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + + pub(crate) struct $name_back_enc<'a>(&'a $name_enc); + + impl<'a> BlockSizeUser for $name_back_enc<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_enc<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + encrypt1(&self.0.round_keys, block); + } + } + + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { encrypt8(&self.0.round_keys, blocks) } + } + } + + pub(crate) struct $name_back_dec<'a>(&'a $name_dec); + + impl<'a> BlockSizeUser for $name_back_dec<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_dec<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + decrypt1(&self.0.round_keys, block); + } + } + + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { decrypt8(&self.0.round_keys, blocks) } + } + } + }; +} + +define_aes_impl!( + Aes128, + Aes128Enc, + Aes128Dec, + Aes128BackEnc, + Aes128BackDec, + U16, + 11, + "AES-128", +); +define_aes_impl!( + Aes192, + Aes192Enc, + Aes192Dec, + Aes192BackEnc, + Aes192BackDec, + U24, + 13, + "AES-192", +); +define_aes_impl!( + Aes256, + Aes256Enc, + Aes256Dec, + Aes256BackEnc, + Aes256BackDec, + U32, + 15, + "AES-256", +); diff --git a/vendor/aes/src/armv8/encdec.rs b/vendor/aes/src/armv8/encdec.rs new file mode 100644 index 00000000..09c59cee --- /dev/null +++ b/vendor/aes/src/armv8/encdec.rs @@ -0,0 +1,152 @@ +//! AES encryption support + +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::arch::aarch64::*; + +// Stable "polyfills" for unstable core::arch::aarch64 intrinsics +// TODO(tarcieri): remove when these intrinsics have been stabilized +use super::intrinsics::{ + vaesdq_u8, vaesdq_u8_and_vaesimcq_u8, vaeseq_u8, vaeseq_u8_and_vaesmcq_u8, +}; + +/// Perform AES encryption using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn encrypt1( + expanded_keys: &[uint8x16_t; N], + block: InOut<'_, '_, Block>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = block.into_raw(); + + let mut state = vld1q_u8(in_ptr as *const u8); + + for k in expanded_keys.iter().take(rounds - 1) { + // AES single round encryption and mix columns + state = vaeseq_u8_and_vaesmcq_u8(state, *k); + } + + // AES single round encryption + state = vaeseq_u8(state, expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state = veorq_u8(state, expanded_keys[rounds]); + + vst1q_u8(out_ptr as *mut u8, state); +} + +/// Perform parallel AES encryption 8-blocks-at-a-time using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn encrypt8( + expanded_keys: &[uint8x16_t; N], + blocks: InOut<'_, '_, Block8>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = blocks.into_raw(); + let in_ptr = in_ptr as *const Block; + let out_ptr = out_ptr as *const Block; + + let mut state = [ + vld1q_u8(in_ptr.add(0) as *const u8), + vld1q_u8(in_ptr.add(1) as *const u8), + vld1q_u8(in_ptr.add(2) as *const u8), + vld1q_u8(in_ptr.add(3) as *const u8), + vld1q_u8(in_ptr.add(4) as *const u8), + vld1q_u8(in_ptr.add(5) as *const u8), + vld1q_u8(in_ptr.add(6) as *const u8), + vld1q_u8(in_ptr.add(7) as *const u8), + ]; + + for k in expanded_keys.iter().take(rounds - 1) { + for i in 0..8 { + // AES single round encryption and mix columns + state[i] = vaeseq_u8_and_vaesmcq_u8(state[i], *k); + } + } + + for i in 0..8 { + // AES single round encryption + state[i] = vaeseq_u8(state[i], expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state[i] = veorq_u8(state[i], expanded_keys[rounds]); + + vst1q_u8(out_ptr.add(i) as *mut u8, state[i]); + } +} + +/// Perform AES decryption using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn decrypt1( + expanded_keys: &[uint8x16_t; N], + block: InOut<'_, '_, Block>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = block.into_raw(); + let mut state = vld1q_u8(in_ptr as *const u8); + + for k in expanded_keys.iter().take(rounds - 1) { + // AES single round decryption and inverse mix columns + state = vaesdq_u8_and_vaesimcq_u8(state, *k); + } + + // AES single round decryption + state = vaesdq_u8(state, expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state = veorq_u8(state, expanded_keys[rounds]); + + vst1q_u8(out_ptr as *mut u8, state); +} + +/// Perform parallel AES decryption 8-blocks-at-a-time using the given expanded keys. +#[target_feature(enable = "aes")] +#[target_feature(enable = "neon")] +pub(super) unsafe fn decrypt8( + expanded_keys: &[uint8x16_t; N], + blocks: InOut<'_, '_, Block8>, +) { + let rounds = N - 1; + assert!(rounds == 10 || rounds == 12 || rounds == 14); + + let (in_ptr, out_ptr) = blocks.into_raw(); + let in_ptr = in_ptr as *const Block; + let out_ptr = out_ptr as *const Block; + + let mut state = [ + vld1q_u8(in_ptr.add(0) as *const u8), + vld1q_u8(in_ptr.add(1) as *const u8), + vld1q_u8(in_ptr.add(2) as *const u8), + vld1q_u8(in_ptr.add(3) as *const u8), + vld1q_u8(in_ptr.add(4) as *const u8), + vld1q_u8(in_ptr.add(5) as *const u8), + vld1q_u8(in_ptr.add(6) as *const u8), + vld1q_u8(in_ptr.add(7) as *const u8), + ]; + + for k in expanded_keys.iter().take(rounds - 1) { + for i in 0..8 { + // AES single round decryption and inverse mix columns + state[i] = vaesdq_u8_and_vaesimcq_u8(state[i], *k); + } + } + + for i in 0..8 { + // AES single round decryption + state[i] = vaesdq_u8(state[i], expanded_keys[rounds - 1]); + + // Final add (bitwise XOR) + state[i] = veorq_u8(state[i], expanded_keys[rounds]); + + vst1q_u8(out_ptr.add(i) as *mut u8, state[i]); + } +} diff --git a/vendor/aes/src/armv8/expand.rs b/vendor/aes/src/armv8/expand.rs new file mode 100644 index 00000000..7cbcb0ce --- /dev/null +++ b/vendor/aes/src/armv8/expand.rs @@ -0,0 +1,79 @@ +//! AES key expansion support. + +use core::{arch::aarch64::*, mem, slice}; + +// Stable "polyfills" for unstable core::arch::aarch64 intrinsics +// TODO(tarcieri): remove when these intrinsics have been stabilized +use super::intrinsics::{vaeseq_u8, vaesimcq_u8}; + +/// There are 4 AES words in a block. +const BLOCK_WORDS: usize = 4; + +/// The AES (nee Rijndael) notion of a word is always 32-bits, or 4-bytes. +const WORD_SIZE: usize = 4; + +/// AES round constants. +const ROUND_CONSTS: [u32; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + +/// AES key expansion. +#[target_feature(enable = "aes")] +pub unsafe fn expand_key(key: &[u8; L]) -> [uint8x16_t; N] { + assert!((L == 16 && N == 11) || (L == 24 && N == 13) || (L == 32 && N == 15)); + + let mut expanded_keys: [uint8x16_t; N] = mem::zeroed(); + + // Sanity check, as this is required in order for the following line to be sound. + const _: () = assert!(mem::align_of::() >= mem::align_of::()); + let keys_ptr: *mut u32 = expanded_keys.as_mut_ptr().cast(); + let columns = slice::from_raw_parts_mut(keys_ptr, N * BLOCK_WORDS); + + for (i, chunk) in key.chunks_exact(WORD_SIZE).enumerate() { + columns[i] = u32::from_ne_bytes(chunk.try_into().unwrap()); + } + + // From "The Rijndael Block Cipher" Section 4.1: + // > The number of columns of the Cipher Key is denoted by `Nk` and is + // > equal to the key length divided by 32 [bits]. + let nk = L / WORD_SIZE; + + for i in nk..(N * BLOCK_WORDS) { + let mut word = columns[i - 1]; + + if i % nk == 0 { + word = sub_word(word).rotate_right(8) ^ ROUND_CONSTS[i / nk - 1]; + } else if nk > 6 && i % nk == 4 { + word = sub_word(word); + } + + columns[i] = columns[i - nk] ^ word; + } + + expanded_keys +} + +/// Compute inverse expanded keys (for decryption). +/// +/// This is the reverse of the encryption keys, with the Inverse Mix Columns +/// operation applied to all but the first and last expanded key. +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(expanded_keys: &mut [uint8x16_t; N]) { + assert!(N == 11 || N == 13 || N == 15); + + for ek in expanded_keys.iter_mut().take(N - 1).skip(1) { + *ek = vaesimcq_u8(*ek); + } + + expanded_keys.reverse(); +} + +/// Sub bytes for a single AES word: used for key expansion. +#[inline] +#[target_feature(enable = "aes")] +unsafe fn sub_word(input: u32) -> u32 { + let input = vreinterpretq_u8_u32(vdupq_n_u32(input)); + + // AES single round encryption (with a "round" key of all zeros) + let sub_input = vaeseq_u8(input, vdupq_n_u8(0)); + + vgetq_lane_u32(vreinterpretq_u32_u8(sub_input), 0) +} diff --git a/vendor/aes/src/armv8/hazmat.rs b/vendor/aes/src/armv8/hazmat.rs new file mode 100644 index 00000000..3e078cfe --- /dev/null +++ b/vendor/aes/src/armv8/hazmat.rs @@ -0,0 +1,107 @@ +//! Low-level "hazmat" AES functions: ARMv8 Cryptography Extensions support. +//! +//! Note: this isn't actually used in the `Aes128`/`Aes192`/`Aes256` +//! implementations in this crate, but instead provides raw AES-NI accelerated +//! access to the AES round function gated under the `hazmat` crate feature. + +use crate::{Block, Block8}; +use core::arch::aarch64::*; + +// Stable "polyfills" for unstable core::arch::aarch64 intrinsics +use super::intrinsics::{vaesdq_u8, vaeseq_u8, vaesimcq_u8, vaesmcq_u8}; + +/// AES cipher (encrypt) round function. +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "aes")] +pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) { + let b = vld1q_u8(block.as_ptr()); + let k = vld1q_u8(round_key.as_ptr()); + + // AES single round encryption (all-zero round key, deferred until the end) + let mut state = vaeseq_u8(b, vdupq_n_u8(0)); + + // AES mix columns (the `vaeseq_u8` instruction otherwise omits this step) + state = vaesmcq_u8(state); + + // AES add round key (bitwise XOR) + state = veorq_u8(state, k); + + vst1q_u8(block.as_mut_ptr(), state); +} + +/// AES cipher (encrypt) round function: parallel version. +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "aes")] +pub(crate) unsafe fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + for i in 0..8 { + let mut state = vld1q_u8(blocks[i].as_ptr()); + + // AES single round encryption + state = vaeseq_u8(state, vdupq_n_u8(0)); + + // AES mix columns + state = vaesmcq_u8(state); + + // AES add round key (bitwise XOR) + state = veorq_u8(state, vld1q_u8(round_keys[i].as_ptr())); + + vst1q_u8(blocks[i].as_mut_ptr(), state); + } +} + +/// AES equivalent inverse cipher (decrypt) round function. +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "aes")] +pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + let b = vld1q_u8(block.as_ptr()); + let k = vld1q_u8(round_key.as_ptr()); + + // AES single round decryption (all-zero round key, deferred until the end) + let mut state = vaesdq_u8(b, vdupq_n_u8(0)); + + // AES inverse mix columns (the `vaesdq_u8` instruction otherwise omits this step) + state = vaesimcq_u8(state); + + // AES add round key (bitwise XOR) + state = veorq_u8(state, k); + + vst1q_u8(block.as_mut_ptr(), state); +} + +/// AES equivalent inverse cipher (decrypt) round function: parallel version. +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "aes")] +pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + for i in 0..8 { + let mut state = vld1q_u8(blocks[i].as_ptr()); + + // AES single round decryption (all-zero round key, deferred until the end) + state = vaesdq_u8(state, vdupq_n_u8(0)); + + // AES inverse mix columns (the `vaesdq_u8` instruction otherwise omits this step) + state = vaesimcq_u8(state); + + // AES add round key (bitwise XOR) + state = veorq_u8(state, vld1q_u8(round_keys[i].as_ptr())); + + vst1q_u8(blocks[i].as_mut_ptr(), state); + } +} + +/// AES mix columns function. +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "aes")] +pub(crate) unsafe fn mix_columns(block: &mut Block) { + let b = vld1q_u8(block.as_ptr()); + let out = vaesmcq_u8(b); + vst1q_u8(block.as_mut_ptr(), out); +} + +/// AES inverse mix columns function. +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "aes")] +pub(crate) unsafe fn inv_mix_columns(block: &mut Block) { + let b = vld1q_u8(block.as_ptr()); + let out = vaesimcq_u8(b); + vst1q_u8(block.as_mut_ptr(), out); +} diff --git a/vendor/aes/src/armv8/intrinsics.rs b/vendor/aes/src/armv8/intrinsics.rs new file mode 100644 index 00000000..752af492 --- /dev/null +++ b/vendor/aes/src/armv8/intrinsics.rs @@ -0,0 +1,93 @@ +//! Stable "polyfills" for unstable `core::arch::aarch64` intrinsics which use +//! `asm!` internally to allow use on stable Rust. +// TODO(tarcieri): remove when these intrinsics have been stabilized + +use core::arch::{aarch64::uint8x16_t, asm}; + +/// AES single round encryption. +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn vaeseq_u8(mut data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { + asm!( + "AESE {d:v}.16B, {k:v}.16B", + d = inout(vreg) data, + k = in(vreg) key, + options(pure, nomem, nostack, preserves_flags) + ); + data +} + +/// AES single round decryption. +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn vaesdq_u8(mut data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { + asm!( + "AESD {d:v}.16B, {k:v}.16B", + d = inout(vreg) data, + k = in(vreg) key, + options(pure, nomem, nostack, preserves_flags) + ); + data +} + +/// AES mix columns. +#[cfg(feature = "hazmat")] +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn vaesmcq_u8(mut data: uint8x16_t) -> uint8x16_t { + asm!( + "AESMC {d:v}.16B, {d:v}.16B", + d = inout(vreg) data, + options(pure, nomem, nostack, preserves_flags) + ); + data +} + +/// AES inverse mix columns. +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn vaesimcq_u8(mut data: uint8x16_t) -> uint8x16_t { + asm!( + "AESIMC {d:v}.16B, {d:v}.16B", + d = inout(vreg) data, + options(pure, nomem, nostack, preserves_flags) + ); + data +} + +/// AES single round encryption combined with mix columns. +/// +/// These two instructions are combined into a single assembly block to ensure +/// that instructions fuse properly. +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn vaeseq_u8_and_vaesmcq_u8(mut data: uint8x16_t, key: uint8x16_t) -> uint8x16_t { + asm!( + "AESE {d:v}.16B, {k:v}.16B", + "AESMC {d:v}.16B, {d:v}.16B", + d = inout(vreg) data, + k = in(vreg) key, + options(pure, nomem, nostack, preserves_flags) + ); + data +} + +/// AES single round decryption combined with mix columns. +/// +/// These two instructions are combined into a single assembly block to ensure +/// that instructions fuse properly. +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn vaesdq_u8_and_vaesimcq_u8( + mut data: uint8x16_t, + key: uint8x16_t, +) -> uint8x16_t { + asm!( + "AESD {d:v}.16B, {k:v}.16B", + "AESIMC {d:v}.16B, {d:v}.16B", + d = inout(vreg) data, + k = in(vreg) key, + options(pure, nomem, nostack, preserves_flags) + ); + data +} diff --git a/vendor/aes/src/armv8/test_expand.rs b/vendor/aes/src/armv8/test_expand.rs new file mode 100644 index 00000000..23ca90aa --- /dev/null +++ b/vendor/aes/src/armv8/test_expand.rs @@ -0,0 +1,130 @@ +use super::{expand_key, inv_expanded_keys}; +use core::arch::aarch64::*; +use hex_literal::hex; + +/// FIPS 197, Appendix A.1: AES-128 Cipher Key +/// user input, unaligned buffer +const AES128_KEY: [u8; 16] = hex!("2b7e151628aed2a6abf7158809cf4f3c"); + +/// FIPS 197 Appendix A.1: Expansion of a 128-bit Cipher Key +/// library controlled, aligned buffer +const AES128_EXP_KEYS: [[u8; 16]; 11] = [ + AES128_KEY, + hex!("a0fafe1788542cb123a339392a6c7605"), + hex!("f2c295f27a96b9435935807a7359f67f"), + hex!("3d80477d4716fe3e1e237e446d7a883b"), + hex!("ef44a541a8525b7fb671253bdb0bad00"), + hex!("d4d1c6f87c839d87caf2b8bc11f915bc"), + hex!("6d88a37a110b3efddbf98641ca0093fd"), + hex!("4e54f70e5f5fc9f384a64fb24ea6dc4f"), + hex!("ead27321b58dbad2312bf5607f8d292f"), + hex!("ac7766f319fadc2128d12941575c006e"), + hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"), +]; + +/// Inverse expanded keys for [`AES128_EXPANDED_KEYS`] +const AES128_EXP_INVKEYS: [[u8; 16]; 11] = [ + hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"), + hex!("0c7b5a631319eafeb0398890664cfbb4"), + hex!("df7d925a1f62b09da320626ed6757324"), + hex!("12c07647c01f22c7bc42d2f37555114a"), + hex!("6efcd876d2df54807c5df034c917c3b9"), + hex!("6ea30afcbc238cf6ae82a4b4b54a338d"), + hex!("90884413d280860a12a128421bc89739"), + hex!("7c1f13f74208c219c021ae480969bf7b"), + hex!("cc7505eb3e17d1ee82296c51c9481133"), + hex!("2b3708a7f262d405bc3ebdbf4b617d62"), + AES128_KEY, +]; + +/// FIPS 197, Appendix A.2: AES-192 Cipher Key +/// user input, unaligned buffer +const AES192_KEY: [u8; 24] = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"); + +/// FIPS 197 Appendix A.2: Expansion of a 192-bit Cipher Key +/// library controlled, aligned buffer +const AES192_EXP_KEYS: [[u8; 16]; 13] = [ + hex!("8e73b0f7da0e6452c810f32b809079e5"), + hex!("62f8ead2522c6b7bfe0c91f72402f5a5"), + hex!("ec12068e6c827f6b0e7a95b95c56fec2"), + hex!("4db7b4bd69b5411885a74796e92538fd"), + hex!("e75fad44bb095386485af05721efb14f"), + hex!("a448f6d94d6dce24aa326360113b30e6"), + hex!("a25e7ed583b1cf9a27f939436a94f767"), + hex!("c0a69407d19da4e1ec1786eb6fa64971"), + hex!("485f703222cb8755e26d135233f0b7b3"), + hex!("40beeb282f18a2596747d26b458c553e"), + hex!("a7e1466c9411f1df821f750aad07d753"), + hex!("ca4005388fcc5006282d166abc3ce7b5"), + hex!("e98ba06f448c773c8ecc720401002202"), +]; + +/// FIPS 197, Appendix A.3: AES-256 Cipher Key +/// user input, unaligned buffer +const AES256_KEY: [u8; 32] = + hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + +/// FIPS 197 Appendix A.3: Expansion of a 256-bit Cipher Key +/// library controlled, aligned buffer +const AES256_EXP_KEYS: [[u8; 16]; 15] = [ + hex!("603deb1015ca71be2b73aef0857d7781"), + hex!("1f352c073b6108d72d9810a30914dff4"), + hex!("9ba354118e6925afa51a8b5f2067fcde"), + hex!("a8b09c1a93d194cdbe49846eb75d5b9a"), + hex!("d59aecb85bf3c917fee94248de8ebe96"), + hex!("b5a9328a2678a647983122292f6c79b3"), + hex!("812c81addadf48ba24360af2fab8b464"), + hex!("98c5bfc9bebd198e268c3ba709e04214"), + hex!("68007bacb2df331696e939e46c518d80"), + hex!("c814e20476a9fb8a5025c02d59c58239"), + hex!("de1369676ccc5a71fa2563959674ee15"), + hex!("5886ca5d2e2f31d77e0af1fa27cf73c3"), + hex!("749c47ab18501ddae2757e4f7401905a"), + hex!("cafaaae3e4d59b349adf6acebd10190d"), + hex!("fe4890d1e6188d0b046df344706c631e"), +]; + +fn load_expanded_keys(input: [[u8; 16]; N]) -> [uint8x16_t; N] { + let mut output = [unsafe { vdupq_n_u8(0) }; N]; + + for (src, dst) in input.iter().zip(output.iter_mut()) { + *dst = unsafe { vld1q_u8(src.as_ptr()) } + } + + output +} + +fn store_expanded_keys(input: [uint8x16_t; N]) -> [[u8; 16]; N] { + let mut output = [[0u8; 16]; N]; + + for (src, dst) in input.iter().zip(output.iter_mut()) { + unsafe { vst1q_u8(dst.as_mut_ptr(), *src) } + } + + output +} + +#[test] +fn aes128_key_expansion() { + let ek = unsafe { expand_key(&AES128_KEY) }; + assert_eq!(store_expanded_keys(ek), AES128_EXP_KEYS); +} + +#[test] +fn aes128_key_expansion_inv() { + let mut ek = load_expanded_keys(AES128_EXP_KEYS); + unsafe { inv_expanded_keys(&mut ek) }; + assert_eq!(store_expanded_keys(ek), AES128_EXP_INVKEYS); +} + +#[test] +fn aes192_key_expansion() { + let ek = unsafe { expand_key(&AES192_KEY) }; + assert_eq!(store_expanded_keys(ek), AES192_EXP_KEYS); +} + +#[test] +fn aes256_key_expansion() { + let ek = unsafe { expand_key(&AES256_KEY) }; + assert_eq!(store_expanded_keys(ek), AES256_EXP_KEYS); +} diff --git a/vendor/aes/src/autodetect.rs b/vendor/aes/src/autodetect.rs new file mode 100644 index 00000000..ac471fab --- /dev/null +++ b/vendor/aes/src/autodetect.rs @@ -0,0 +1,430 @@ +//! Autodetection support for hardware accelerated AES backends with fallback +//! to the fixsliced "soft" implementation. + +use crate::soft; +use cipher::{ + consts::{U16, U24, U32}, + AlgorithmName, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, BlockSizeUser, Key, + KeyInit, KeySizeUser, +}; +use core::fmt; +use core::mem::ManuallyDrop; + +#[cfg(all(target_arch = "aarch64", aes_armv8))] +use crate::armv8 as intrinsics; + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +use crate::ni as intrinsics; + +cpufeatures::new!(aes_intrinsics, "aes"); + +macro_rules! define_aes_impl { + ( + $name:ident, + $name_enc:ident, + $name_dec:ident, + $module:tt, + $key_size:ty, + $doc:expr $(,)? + ) => { + mod $module { + use super::{intrinsics, soft}; + use core::mem::ManuallyDrop; + + pub(super) union Inner { + pub(super) intrinsics: ManuallyDrop, + pub(super) soft: ManuallyDrop, + } + + pub(super) union InnerEnc { + pub(super) intrinsics: ManuallyDrop, + pub(super) soft: ManuallyDrop, + } + + pub(super) union InnerDec { + pub(super) intrinsics: ManuallyDrop, + pub(super) soft: ManuallyDrop, + } + } + + #[doc=$doc] + #[doc = "block cipher"] + pub struct $name { + inner: $module::Inner, + token: aes_intrinsics::InitToken, + } + + impl KeySizeUser for $name { + type KeySize = $key_size; + } + impl From<$name_enc> for $name { + #[inline] + fn from(enc: $name_enc) -> $name { + Self::from(&enc) + } + } + + impl From<&$name_enc> for $name { + fn from(enc: &$name_enc) -> $name { + use core::ops::Deref; + let inner = if enc.token.get() { + $module::Inner { + intrinsics: ManuallyDrop::new(unsafe { + enc.inner.intrinsics.deref().into() + }), + } + } else { + $module::Inner { + soft: ManuallyDrop::new(unsafe { enc.inner.soft.deref().into() }), + } + }; + + Self { + inner, + token: enc.token, + } + } + } + + impl KeyInit for $name { + #[inline] + fn new(key: &Key) -> Self { + let (token, aesni_present) = aes_intrinsics::init_get(); + + let inner = if aesni_present { + $module::Inner { + intrinsics: ManuallyDrop::new(intrinsics::$name::new(key)), + } + } else { + $module::Inner { + soft: ManuallyDrop::new(soft::$name::new(key)), + } + }; + + Self { inner, token } + } + } + + impl Clone for $name { + fn clone(&self) -> Self { + let inner = if self.token.get() { + $module::Inner { + intrinsics: unsafe { self.inner.intrinsics.clone() }, + } + } else { + $module::Inner { + soft: unsafe { self.inner.soft.clone() }, + } + }; + + Self { + inner, + token: self.token, + } + } + } + + impl BlockSizeUser for $name { + type BlockSize = U16; + } + + impl BlockCipher for $name {} + + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name, + f: impl BlockClosure, + ) { + f.call(&mut state.get_enc_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_enc_backend()); + } + } + } + } + + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name, + f: impl BlockClosure, + ) { + f.call(&mut state.get_dec_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_dec_backend()); + } + } + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + impl Drop for $name { + #[inline] + fn drop(&mut self) { + if self.token.get() { + unsafe { ManuallyDrop::drop(&mut self.inner.intrinsics) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.inner.soft) }; + }; + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + pub struct $name_enc { + inner: $module::InnerEnc, + token: aes_intrinsics::InitToken, + } + + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } + + impl KeyInit for $name_enc { + #[inline] + fn new(key: &Key) -> Self { + let (token, aesni_present) = aes_intrinsics::init_get(); + + let inner = if aesni_present { + $module::InnerEnc { + intrinsics: ManuallyDrop::new(intrinsics::$name_enc::new(key)), + } + } else { + $module::InnerEnc { + soft: ManuallyDrop::new(soft::$name_enc::new(key)), + } + }; + + Self { inner, token } + } + } + + impl Clone for $name_enc { + fn clone(&self) -> Self { + let inner = if self.token.get() { + $module::InnerEnc { + intrinsics: unsafe { self.inner.intrinsics.clone() }, + } + } else { + $module::InnerEnc { + soft: unsafe { self.inner.soft.clone() }, + } + }; + + Self { + inner, + token: self.token, + } + } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } + + impl BlockCipher for $name_enc {} + + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name_enc, + f: impl BlockClosure, + ) { + f.call(&mut state.get_enc_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_enc_backend()); + } + } + } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } + + impl Drop for $name_enc { + #[inline] + fn drop(&mut self) { + if self.token.get() { + unsafe { ManuallyDrop::drop(&mut self.inner.intrinsics) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.inner.soft) }; + }; + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + pub struct $name_dec { + inner: $module::InnerDec, + token: aes_intrinsics::InitToken, + } + + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } + + impl From<$name_enc> for $name_dec { + #[inline] + fn from(enc: $name_enc) -> $name_dec { + Self::from(&enc) + } + } + + impl From<&$name_enc> for $name_dec { + fn from(enc: &$name_enc) -> $name_dec { + use core::ops::Deref; + let inner = if enc.token.get() { + $module::InnerDec { + intrinsics: ManuallyDrop::new(unsafe { + enc.inner.intrinsics.deref().into() + }), + } + } else { + $module::InnerDec { + soft: ManuallyDrop::new(unsafe { enc.inner.soft.deref().into() }), + } + }; + + Self { + inner, + token: enc.token, + } + } + } + + impl KeyInit for $name_dec { + #[inline] + fn new(key: &Key) -> Self { + let (token, aesni_present) = aes_intrinsics::init_get(); + + let inner = if aesni_present { + $module::InnerDec { + intrinsics: ManuallyDrop::new(intrinsics::$name_dec::new(key)), + } + } else { + $module::InnerDec { + soft: ManuallyDrop::new(soft::$name_dec::new(key)), + } + }; + + Self { inner, token } + } + } + + impl Clone for $name_dec { + fn clone(&self) -> Self { + let inner = if self.token.get() { + $module::InnerDec { + intrinsics: unsafe { self.inner.intrinsics.clone() }, + } + } else { + $module::InnerDec { + soft: unsafe { self.inner.soft.clone() }, + } + }; + + Self { + inner, + token: self.token, + } + } + } + + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } + + impl BlockCipher for $name_dec {} + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + unsafe { + if self.token.get() { + #[target_feature(enable = "aes")] + unsafe fn inner( + state: &intrinsics::$name_dec, + f: impl BlockClosure, + ) { + f.call(&mut state.get_dec_backend()); + } + inner(&self.inner.intrinsics, f); + } else { + f.call(&mut self.inner.soft.get_dec_backend()); + } + } + } + } + + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } + + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + + impl Drop for $name_dec { + #[inline] + fn drop(&mut self) { + if self.token.get() { + unsafe { ManuallyDrop::drop(&mut self.inner.intrinsics) }; + } else { + unsafe { ManuallyDrop::drop(&mut self.inner.soft) }; + }; + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + }; +} + +define_aes_impl!(Aes128, Aes128Enc, Aes128Dec, aes128, U16, "AES-128"); +define_aes_impl!(Aes192, Aes192Enc, Aes192Dec, aes192, U24, "AES-192"); +define_aes_impl!(Aes256, Aes256Enc, Aes256Dec, aes256, U32, "AES-256"); diff --git a/vendor/aes/src/hazmat.rs b/vendor/aes/src/hazmat.rs new file mode 100644 index 00000000..4776bb4e --- /dev/null +++ b/vendor/aes/src/hazmat.rs @@ -0,0 +1,159 @@ +//! ⚠️ Low-level "hazmat" AES functions. +//! +//! # ☢️️ WARNING: HAZARDOUS API ☢️ +//! +//! This module contains an extremely low-level cryptographic primitive +//! which is likewise extremely difficult to use correctly. +//! +//! There are very few valid uses cases for this API. It's intended to be used +//! for implementing well-reviewed higher-level constructions. +//! +//! We do NOT recommend using it to implement any algorithm which has not +//! received extensive peer review by cryptographers. + +use crate::{soft::fixslice::hazmat as soft, Block, Block8}; + +#[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))] +use crate::armv8::hazmat as intrinsics; + +#[cfg(all(any(target_arch = "x86_64", target_arch = "x86"), not(aes_force_soft)))] +use crate::ni::hazmat as intrinsics; + +#[cfg(all( + any( + target_arch = "x86", + target_arch = "x86_64", + all(target_arch = "aarch64", aes_armv8) + ), + not(aes_force_soft) +))] +cpufeatures::new!(aes_intrinsics, "aes"); + +/// Execute the provided body if CPU intrinsics are available. +// TODO(tarcieri): more `cfg-if`-like macro with an else branch? +macro_rules! if_intrinsics_available { + ($body:expr) => {{ + #[cfg(all( + any( + target_arch = "x86", + target_arch = "x86_64", + all(target_arch = "aarch64", aes_armv8) + ), + not(aes_force_soft) + ))] + if aes_intrinsics::get() { + unsafe { $body } + return; + } + }}; +} + +/// ⚠️ AES cipher (encrypt) round function. +/// +/// This API performs the following steps as described in FIPS 197 Appendix C: +/// +/// - `s_box`: state after `SubBytes()` +/// - `s_row`: state after `ShiftRows()` +/// - `m_col`: state after `MixColumns()` +/// - `k_sch`: key schedule value for `round[r]` +/// +/// This series of operations is equivalent to the Intel AES-NI `AESENC` instruction. +/// +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// Use this function with great care! See the [module-level documentation][crate::hazmat] +/// for more information. +pub fn cipher_round(block: &mut Block, round_key: &Block) { + if_intrinsics_available! { + intrinsics::cipher_round(block, round_key) + } + + soft::cipher_round(block, round_key); +} + +/// ⚠️ AES cipher (encrypt) round function: parallel version. +/// +/// Equivalent to [`cipher_round`], but acts on 8 blocks-at-a-time, applying +/// the same number of round keys. +/// +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// Use this function with great care! See the [module-level documentation][crate::hazmat] +/// for more information. +pub fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + if_intrinsics_available! { + intrinsics::cipher_round_par(blocks, round_keys) + } + + soft::cipher_round_par(blocks, round_keys); +} + +/// ⚠️ AES equivalent inverse cipher (decrypt) round function. +/// +/// This API performs the following steps as described in FIPS 197 Appendix C: +/// +/// - `is_box`: state after `InvSubBytes()` +/// - `is_row`: state after `InvShiftRows()` +/// - `im_col`: state after `InvMixColumns()` +/// - `ik_sch`: key schedule value for `round[r]` +/// +/// This series of operations is equivalent to the Intel AES-NI `AESDEC` instruction. +/// +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// Use this function with great care! See the [module-level documentation][crate::hazmat] +/// for more information. +pub fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + if_intrinsics_available! { + intrinsics::equiv_inv_cipher_round(block, round_key) + } + + soft::equiv_inv_cipher_round(block, round_key); +} + +/// ⚠️ AES equivalent inverse cipher (decrypt) round function: parallel version. +/// +/// Equivalent to [`equiv_inv_cipher_round`], but acts on 8 blocks-at-a-time, +/// applying the same number of round keys. +/// +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// Use this function with great care! See the [module-level documentation][crate::hazmat] +/// for more information. +pub fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + if_intrinsics_available! { + intrinsics::equiv_inv_cipher_round_par(blocks, round_keys) + } + + soft::equiv_inv_cipher_round_par(blocks, round_keys); +} + +/// ⚠️ AES mix columns function. +/// +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// Use this function with great care! See the [module-level documentation][crate::hazmat] +/// for more information. +pub fn mix_columns(block: &mut Block) { + if_intrinsics_available! { + intrinsics::mix_columns(block) + } + + soft::mix_columns(block); +} + +/// ⚠️ AES inverse mix columns function. +/// +/// This function is equivalent to the Intel AES-NI `AESIMC` instruction. +/// +/// # ☢️️ WARNING: HAZARDOUS API ☢️ +/// +/// Use this function with great care! See the [module-level documentation][crate::hazmat] +/// for more information. +pub fn inv_mix_columns(block: &mut Block) { + if_intrinsics_available! { + intrinsics::inv_mix_columns(block) + } + + soft::inv_mix_columns(block); +} diff --git a/vendor/aes/src/lib.rs b/vendor/aes/src/lib.rs new file mode 100644 index 00000000..1df43ea6 --- /dev/null +++ b/vendor/aes/src/lib.rs @@ -0,0 +1,233 @@ +//! Pure Rust implementation of the [Advanced Encryption Standard][AES] +//! (AES, a.k.a. Rijndael). +//! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate implements only the low-level block cipher function, and is intended +//! for use for implementing higher-level constructions *only*. It is NOT +//! intended for direct use in applications. +//! +//! USE AT YOUR OWN RISK! +//! +//! # Supported backends +//! This crate provides multiple backends including a portable pure Rust +//! backend as well as ones based on CPU intrinsics. +//! +//! By default, it performs runtime detection of CPU intrinsics and uses them +//! if they are available. +//! +//! ## "soft" portable backend +//! As a baseline implementation, this crate provides a constant-time pure Rust +//! implementation based on [fixslicing], a more advanced form of bitslicing +//! implemented entirely in terms of bitwise arithmetic with no use of any +//! lookup tables or data-dependent branches. +//! +//! Enabling the `aes_compact` configuration flag will reduce the code size of this +//! backend at the cost of decreased performance (using a modified form of +//! the fixslicing technique called "semi-fixslicing"). +//! +//! ## ARMv8 intrinsics (Rust 1.61+) +//! On `aarch64` targets including `aarch64-apple-darwin` (Apple M1) and Linux +//! targets such as `aarch64-unknown-linux-gnu` and `aarch64-unknown-linux-musl`, +//! support for using AES intrinsics provided by the ARMv8 Cryptography Extensions +//! is available when using Rust 1.61 or above, and can be enabled using the +//! `aes_armv8` configuration flag. +//! +//! On Linux and macOS, when the `aes_armv8` flag is enabled support for AES +//! intrinsics is autodetected at runtime. On other platforms the `aes` +//! target feature must be enabled via RUSTFLAGS. +//! +//! ## `x86`/`x86_64` intrinsics (AES-NI) +//! By default this crate uses runtime detection on `i686`/`x86_64` targets +//! in order to determine if AES-NI is available, and if it is not, it will +//! fallback to using a constant-time software implementation. +//! +//! Passing `RUSTFLAGS=-C target-feature=+aes,+ssse3` explicitly at compile-time +//! will override runtime detection and ensure that AES-NI is always used. +//! Programs built in this manner will crash with an illegal instruction on +//! CPUs which do not have AES-NI enabled. +//! +//! Note: runtime detection is not possible on SGX targets. Please use the +//! afforementioned `RUSTFLAGS` to leverage AES-NI on these targets. +//! +//! # Examples +//! ``` +//! use aes::Aes128; +//! use aes::cipher::{ +//! BlockCipher, BlockEncrypt, BlockDecrypt, KeyInit, +//! generic_array::GenericArray, +//! }; +//! +//! let key = GenericArray::from([0u8; 16]); +//! let mut block = GenericArray::from([42u8; 16]); +//! +//! // Initialize cipher +//! let cipher = Aes128::new(&key); +//! +//! let block_copy = block.clone(); +//! +//! // Encrypt block in-place +//! cipher.encrypt_block(&mut block); +//! +//! // And decrypt it back +//! cipher.decrypt_block(&mut block); +//! assert_eq!(block, block_copy); +//! +//! // Implementation supports parallel block processing. Number of blocks +//! // processed in parallel depends in general on hardware capabilities. +//! // This is achieved by instruction-level parallelism (ILP) on a single +//! // CPU core, which is differen from multi-threaded parallelism. +//! let mut blocks = [block; 100]; +//! cipher.encrypt_blocks(&mut blocks); +//! +//! for block in blocks.iter_mut() { +//! cipher.decrypt_block(block); +//! assert_eq!(block, &block_copy); +//! } +//! +//! // `decrypt_blocks` also supports parallel block processing. +//! cipher.decrypt_blocks(&mut blocks); +//! +//! for block in blocks.iter_mut() { +//! cipher.encrypt_block(block); +//! assert_eq!(block, &block_copy); +//! } +//! ``` +//! +//! For implementation of block cipher modes of operation see +//! [`block-modes`] repository. +//! +//! # Configuration Flags +//! +//! You can modify crate using the following configuration flags: +//! +//! - `aes_armv8`: enable ARMv8 AES intrinsics (Rust 1.61+). +//! - `aes_force_soft`: force software implementation. +//! - `aes_compact`: reduce code size at the cost of slower performance +//! (affects only software backend). +//! +//! It can be enabled using `RUSTFLAGS` environmental variable +//! (e.g. `RUSTFLAGS="--cfg aes_compact"`) or by modifying `.cargo/config`. +//! +//! [AES]: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard +//! [fixslicing]: https://eprint.iacr.org/2020/1123.pdf +//! [AES-NI]: https://en.wikipedia.org/wiki/AES_instruction_set +//! [`block-modes`]: https://github.com/RustCrypto/block-modes/ + +#![no_std] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg" +)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "hazmat")] +#[cfg_attr(docsrs, doc(cfg(feature = "hazmat")))] +pub mod hazmat; + +mod soft; + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))] { + mod armv8; + mod autodetect; + pub use autodetect::*; + } else if #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + not(aes_force_soft) + ))] { + mod autodetect; + mod ni; + pub use autodetect::*; + } else { + pub use soft::*; + } +} + +pub use cipher; +use cipher::{ + consts::{U16, U8}, + generic_array::GenericArray, +}; + +/// 128-bit AES block +pub type Block = GenericArray; +/// Eight 128-bit AES blocks +pub type Block8 = GenericArray; + +#[cfg(test)] +mod tests { + #[cfg(feature = "zeroize")] + #[test] + fn zeroize_works() { + use super::soft; + + fn test_for(val: T) { + use core::mem::{size_of, ManuallyDrop}; + + let mut val = ManuallyDrop::new(val); + let ptr = &val as *const _ as *const u8; + let len = size_of::>(); + + unsafe { ManuallyDrop::drop(&mut val) }; + + let slice = unsafe { core::slice::from_raw_parts(ptr, len) }; + + assert!(slice.iter().all(|&byte| byte == 0)); + } + + let key_128 = [42; 16].into(); + let key_192 = [42; 24].into(); + let key_256 = [42; 32].into(); + + use cipher::KeyInit as _; + test_for(soft::Aes128::new(&key_128)); + test_for(soft::Aes128Enc::new(&key_128)); + test_for(soft::Aes128Dec::new(&key_128)); + test_for(soft::Aes192::new(&key_192)); + test_for(soft::Aes192Enc::new(&key_192)); + test_for(soft::Aes192Dec::new(&key_192)); + test_for(soft::Aes256::new(&key_256)); + test_for(soft::Aes256Enc::new(&key_256)); + test_for(soft::Aes256Dec::new(&key_256)); + + #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), not(aes_force_soft)))] + { + use super::ni; + + cpufeatures::new!(aes_intrinsics, "aes"); + if aes_intrinsics::get() { + test_for(ni::Aes128::new(&key_128)); + test_for(ni::Aes128Enc::new(&key_128)); + test_for(ni::Aes128Dec::new(&key_128)); + test_for(ni::Aes192::new(&key_192)); + test_for(ni::Aes192Enc::new(&key_192)); + test_for(ni::Aes192Dec::new(&key_192)); + test_for(ni::Aes256::new(&key_256)); + test_for(ni::Aes256Enc::new(&key_256)); + test_for(ni::Aes256Dec::new(&key_256)); + } + } + + #[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))] + { + use super::armv8; + + cpufeatures::new!(aes_intrinsics, "aes"); + if aes_intrinsics::get() { + test_for(armv8::Aes128::new(&key_128)); + test_for(armv8::Aes128Enc::new(&key_128)); + test_for(armv8::Aes128Dec::new(&key_128)); + test_for(armv8::Aes192::new(&key_192)); + test_for(armv8::Aes192Enc::new(&key_192)); + test_for(armv8::Aes192Dec::new(&key_192)); + test_for(armv8::Aes256::new(&key_256)); + test_for(armv8::Aes256Enc::new(&key_256)); + test_for(armv8::Aes256Dec::new(&key_256)); + } + } + } +} diff --git a/vendor/aes/src/ni.rs b/vendor/aes/src/ni.rs new file mode 100644 index 00000000..15b49ef5 --- /dev/null +++ b/vendor/aes/src/ni.rs @@ -0,0 +1,361 @@ +//! AES block ciphers implementation using AES-NI instruction set. +//! +//! Ciphers functionality is accessed using `BlockCipher` trait from the +//! [`cipher`](https://docs.rs/cipher) crate. +//! +//! # Vulnerability +//! Lazy FP state restory vulnerability can allow local process to leak content +//! of the FPU register, in which round keys are stored. This vulnerability +//! can be mitigated at the operating system level by installing relevant +//! patches. (i.e. keep your OS updated!) More info: +//! - [Intel advisory](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00145.html) +//! - [Wikipedia](https://en.wikipedia.org/wiki/Lazy_FP_state_restore) +//! +//! # Related documents +//! - [Intel AES-NI whitepaper](https://software.intel.com/sites/default/files/article/165683/aes-wp-2012-09-22-v01.pdf) +//! - [Use of the AES Instruction Set](https://www.cosic.esat.kuleuven.be/ecrypt/AESday/slides/Use_of_the_AES_Instruction_Set.pdf) + +#[macro_use] +mod utils; + +mod aes128; +mod aes192; +mod aes256; + +#[cfg(test)] +mod test_expand; + +#[cfg(feature = "hazmat")] +pub(crate) mod hazmat; + +#[cfg(target_arch = "x86")] +use core::arch::x86 as arch; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64 as arch; + +use crate::{Block, Block8}; +use cipher::{ + consts::{U16, U24, U32, U8}, + inout::InOut, + AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, + BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, +}; +use core::fmt; + +macro_rules! define_aes_impl { + ( + $name:tt, + $name_enc:ident, + $name_dec:ident, + $name_back_enc:ident, + $name_back_dec:ident, + $module:tt, + $key_size:ty, + $doc:expr $(,)? + ) => { + #[doc=$doc] + #[doc = "block cipher"] + #[derive(Clone)] + pub struct $name { + encrypt: $name_enc, + decrypt: $name_dec, + } + + impl $name { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + self.encrypt.get_enc_backend() + } + + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + self.decrypt.get_dec_backend() + } + } + + impl BlockCipher for $name {} + + impl KeySizeUser for $name { + type KeySize = $key_size; + } + + impl KeyInit for $name { + #[inline] + fn new(key: &Key) -> Self { + let encrypt = $name_enc::new(key); + let decrypt = $name_dec::from(&encrypt); + Self { encrypt, decrypt } + } + } + + impl From<$name_enc> for $name { + #[inline] + fn from(encrypt: $name_enc) -> $name { + let decrypt = (&encrypt).into(); + Self { encrypt, decrypt } + } + } + + impl From<&$name_enc> for $name { + #[inline] + fn from(encrypt: &$name_enc) -> $name { + let decrypt = encrypt.into(); + let encrypt = encrypt.clone(); + Self { encrypt, decrypt } + } + } + + impl BlockSizeUser for $name { + type BlockSize = U16; + } + + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + self.encrypt.encrypt_with_backend(f) + } + } + + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + self.decrypt.decrypt_with_backend(f) + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + #[derive(Clone)] + pub struct $name_enc { + round_keys: $module::RoundKeys, + } + + impl $name_enc { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + $name_back_enc(self) + } + } + + impl BlockCipher for $name_enc {} + + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } + + impl KeyInit for $name_enc { + fn new(key: &Key) -> Self { + // SAFETY: we enforce that this code is called only when + // target features required by `expand` were properly checked. + Self { + round_keys: unsafe { $module::expand_key(key.as_ref()) }, + } + } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } + + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } + + impl Drop for $name_enc { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + #[derive(Clone)] + pub struct $name_dec { + round_keys: $module::RoundKeys, + } + + impl $name_dec { + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + $name_back_dec(self) + } + } + + impl BlockCipher for $name_dec {} + + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } + + impl KeyInit for $name_dec { + fn new(key: &Key) -> Self { + $name_enc::new(key).into() + } + } + + impl From<$name_enc> for $name_dec { + #[inline] + fn from(enc: $name_enc) -> $name_dec { + Self::from(&enc) + } + } + + impl From<&$name_enc> for $name_dec { + #[inline] + fn from(enc: &$name_enc) -> $name_dec { + let round_keys = unsafe { $module::inv_expanded_keys(&enc.round_keys) }; + Self { round_keys } + } + } + + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()); + } + } + + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } + + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + + impl Drop for $name_dec { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.round_keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + + pub(crate) struct $name_back_enc<'a>(&'a $name_enc); + + impl<'a> BlockSizeUser for $name_back_enc<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_enc<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + $module::encrypt1(&self.0.round_keys, block); + } + } + + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { + $module::encrypt8(&self.0.round_keys, blocks); + } + } + } + + pub(crate) struct $name_back_dec<'a>(&'a $name_dec); + + impl<'a> BlockSizeUser for $name_back_dec<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { + type ParBlocksSize = U8; + } + + impl<'a> BlockBackend for $name_back_dec<'a> { + #[inline(always)] + fn proc_block(&mut self, block: InOut<'_, '_, Block>) { + unsafe { + $module::decrypt1(&self.0.round_keys, block); + } + } + + #[inline(always)] + fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { + unsafe { + $module::decrypt8(&self.0.round_keys, blocks); + } + } + } + }; +} + +define_aes_impl!( + Aes128, + Aes128Enc, + Aes128Dec, + Aes128BackEnc, + Aes128BackDec, + aes128, + U16, + "AES-128", +); + +define_aes_impl!( + Aes192, + Aes192Enc, + Aes192Dec, + Aes192BackEnc, + Aes192BackDec, + aes192, + U24, + "AES-192", +); + +define_aes_impl!( + Aes256, + Aes256Enc, + Aes256Dec, + Aes256BackEnc, + Aes256BackDec, + aes256, + U32, + "AES-256", +); diff --git a/vendor/aes/src/ni/aes128.rs b/vendor/aes/src/ni/aes128.rs new file mode 100644 index 00000000..b0836a16 --- /dev/null +++ b/vendor/aes/src/ni/aes128.rs @@ -0,0 +1,145 @@ +use super::{arch::*, utils::*}; +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::mem; + +/// AES-128 round keys +pub(super) type RoundKeys = [__m128i; 11]; + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[0]); + b = _mm_aesenc_si128(b, keys[1]); + b = _mm_aesenc_si128(b, keys[2]); + b = _mm_aesenc_si128(b, keys[3]); + b = _mm_aesenc_si128(b, keys[4]); + b = _mm_aesenc_si128(b, keys[5]); + b = _mm_aesenc_si128(b, keys[6]); + b = _mm_aesenc_si128(b, keys[7]); + b = _mm_aesenc_si128(b, keys[8]); + b = _mm_aesenc_si128(b, keys[9]); + b = _mm_aesenclast_si128(b, keys[10]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[0]); + aesenc8(&mut b, keys[1]); + aesenc8(&mut b, keys[2]); + aesenc8(&mut b, keys[3]); + aesenc8(&mut b, keys[4]); + aesenc8(&mut b, keys[5]); + aesenc8(&mut b, keys[6]); + aesenc8(&mut b, keys[7]); + aesenc8(&mut b, keys[8]); + aesenc8(&mut b, keys[9]); + aesenclast8(&mut b, keys[10]); + store8(out_ptr, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[10]); + b = _mm_aesdec_si128(b, keys[9]); + b = _mm_aesdec_si128(b, keys[8]); + b = _mm_aesdec_si128(b, keys[7]); + b = _mm_aesdec_si128(b, keys[6]); + b = _mm_aesdec_si128(b, keys[5]); + b = _mm_aesdec_si128(b, keys[4]); + b = _mm_aesdec_si128(b, keys[3]); + b = _mm_aesdec_si128(b, keys[2]); + b = _mm_aesdec_si128(b, keys[1]); + b = _mm_aesdeclast_si128(b, keys[0]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[10]); + aesdec8(&mut b, keys[9]); + aesdec8(&mut b, keys[8]); + aesdec8(&mut b, keys[7]); + aesdec8(&mut b, keys[6]); + aesdec8(&mut b, keys[5]); + aesdec8(&mut b, keys[4]); + aesdec8(&mut b, keys[3]); + aesdec8(&mut b, keys[2]); + aesdec8(&mut b, keys[1]); + aesdeclast8(&mut b, keys[0]); + store8(out_ptr, b); +} + +macro_rules! expand_round { + ($keys:expr, $pos:expr, $round:expr) => { + let mut t1 = $keys[$pos - 1]; + let mut t2; + let mut t3; + + t2 = _mm_aeskeygenassist_si128(t1, $round); + t2 = _mm_shuffle_epi32(t2, 0xff); + t3 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t3); + t3 = _mm_slli_si128(t3, 0x4); + t1 = _mm_xor_si128(t1, t3); + t3 = _mm_slli_si128(t3, 0x4); + t1 = _mm_xor_si128(t1, t3); + t1 = _mm_xor_si128(t1, t2); + + $keys[$pos] = t1; + }; +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn expand_key(key: &[u8; 16]) -> RoundKeys { + // SAFETY: `RoundKeys` is a `[__m128i; 11]` which can be initialized + // with all zeroes. + let mut keys: RoundKeys = mem::zeroed(); + + let k = _mm_loadu_si128(key.as_ptr() as *const __m128i); + keys[0] = k; + + expand_round!(keys, 1, 0x01); + expand_round!(keys, 2, 0x02); + expand_round!(keys, 3, 0x04); + expand_round!(keys, 4, 0x08); + expand_round!(keys, 5, 0x10); + expand_round!(keys, 6, 0x20); + expand_round!(keys, 7, 0x40); + expand_round!(keys, 8, 0x80); + expand_round!(keys, 9, 0x1B); + expand_round!(keys, 10, 0x36); + + keys +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(keys: &RoundKeys) -> RoundKeys { + [ + keys[0], + _mm_aesimc_si128(keys[1]), + _mm_aesimc_si128(keys[2]), + _mm_aesimc_si128(keys[3]), + _mm_aesimc_si128(keys[4]), + _mm_aesimc_si128(keys[5]), + _mm_aesimc_si128(keys[6]), + _mm_aesimc_si128(keys[7]), + _mm_aesimc_si128(keys[8]), + _mm_aesimc_si128(keys[9]), + keys[10], + ] +} diff --git a/vendor/aes/src/ni/aes192.rs b/vendor/aes/src/ni/aes192.rs new file mode 100644 index 00000000..eee1f211 --- /dev/null +++ b/vendor/aes/src/ni/aes192.rs @@ -0,0 +1,197 @@ +use super::{arch::*, utils::*}; +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::{mem, ptr}; + +/// AES-192 round keys +pub(super) type RoundKeys = [__m128i; 13]; + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[0]); + b = _mm_aesenc_si128(b, keys[1]); + b = _mm_aesenc_si128(b, keys[2]); + b = _mm_aesenc_si128(b, keys[3]); + b = _mm_aesenc_si128(b, keys[4]); + b = _mm_aesenc_si128(b, keys[5]); + b = _mm_aesenc_si128(b, keys[6]); + b = _mm_aesenc_si128(b, keys[7]); + b = _mm_aesenc_si128(b, keys[8]); + b = _mm_aesenc_si128(b, keys[9]); + b = _mm_aesenc_si128(b, keys[10]); + b = _mm_aesenc_si128(b, keys[11]); + b = _mm_aesenclast_si128(b, keys[12]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[0]); + aesenc8(&mut b, keys[1]); + aesenc8(&mut b, keys[2]); + aesenc8(&mut b, keys[3]); + aesenc8(&mut b, keys[4]); + aesenc8(&mut b, keys[5]); + aesenc8(&mut b, keys[6]); + aesenc8(&mut b, keys[7]); + aesenc8(&mut b, keys[8]); + aesenc8(&mut b, keys[9]); + aesenc8(&mut b, keys[10]); + aesenc8(&mut b, keys[11]); + aesenclast8(&mut b, keys[12]); + store8(out_ptr, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[12]); + b = _mm_aesdec_si128(b, keys[11]); + b = _mm_aesdec_si128(b, keys[10]); + b = _mm_aesdec_si128(b, keys[9]); + b = _mm_aesdec_si128(b, keys[8]); + b = _mm_aesdec_si128(b, keys[7]); + b = _mm_aesdec_si128(b, keys[6]); + b = _mm_aesdec_si128(b, keys[5]); + b = _mm_aesdec_si128(b, keys[4]); + b = _mm_aesdec_si128(b, keys[3]); + b = _mm_aesdec_si128(b, keys[2]); + b = _mm_aesdec_si128(b, keys[1]); + b = _mm_aesdeclast_si128(b, keys[0]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[12]); + aesdec8(&mut b, keys[11]); + aesdec8(&mut b, keys[10]); + aesdec8(&mut b, keys[9]); + aesdec8(&mut b, keys[8]); + aesdec8(&mut b, keys[7]); + aesdec8(&mut b, keys[6]); + aesdec8(&mut b, keys[5]); + aesdec8(&mut b, keys[4]); + aesdec8(&mut b, keys[3]); + aesdec8(&mut b, keys[2]); + aesdec8(&mut b, keys[1]); + aesdeclast8(&mut b, keys[0]); + store8(out_ptr, b); +} + +macro_rules! expand_round { + ($t1:expr, $t3:expr, $round:expr) => {{ + let mut t1 = $t1; + let mut t2; + let mut t3 = $t3; + let mut t4; + + t2 = _mm_aeskeygenassist_si128(t3, $round); + t2 = _mm_shuffle_epi32(t2, 0x55); + t4 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t1 = _mm_xor_si128(t1, t2); + t2 = _mm_shuffle_epi32(t1, 0xff); + t4 = _mm_slli_si128(t3, 0x4); + t3 = _mm_xor_si128(t3, t4); + t3 = _mm_xor_si128(t3, t2); + + (t1, t3) + }}; +} + +macro_rules! shuffle { + ($a:expr, $b:expr, $imm:expr) => { + mem::transmute::<_, __m128i>(_mm_shuffle_pd(mem::transmute($a), mem::transmute($b), $imm)) + }; +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn expand_key(key: &[u8; 24]) -> RoundKeys { + // SAFETY: `RoundKeys` is a `[__m128i; 13]` which can be initialized + // with all zeroes. + let mut keys: RoundKeys = mem::zeroed(); + // we are being extra pedantic here to remove out-of-bound access. + // this should be optimized out into movups, movsd sequence + // note that unaligned load MUST be used here, even though we read + // from the array (compiler missoptimizes aligned load) + let (k0, k1l) = { + let mut t = [0u8; 32]; + ptr::write(t.as_mut_ptr() as *mut [u8; 24], *key); + + ( + _mm_loadu_si128(t.as_ptr() as *const __m128i), + _mm_loadu_si128(t.as_ptr().offset(16) as *const __m128i), + ) + }; + + keys[0] = k0; + + let (k1_2, k2r) = expand_round!(k0, k1l, 0x01); + keys[1] = shuffle!(k1l, k1_2, 0); + keys[2] = shuffle!(k1_2, k2r, 1); + + let (k3, k4l) = expand_round!(k1_2, k2r, 0x02); + keys[3] = k3; + + let (k4_5, k5r) = expand_round!(k3, k4l, 0x04); + let k4 = shuffle!(k4l, k4_5, 0); + let k5 = shuffle!(k4_5, k5r, 1); + keys[4] = k4; + keys[5] = k5; + + let (k6, k7l) = expand_round!(k4_5, k5r, 0x08); + keys[6] = k6; + + let (k7_8, k8r) = expand_round!(k6, k7l, 0x10); + keys[7] = shuffle!(k7l, k7_8, 0); + keys[8] = shuffle!(k7_8, k8r, 1); + + let (k9, k10l) = expand_round!(k7_8, k8r, 0x20); + keys[9] = k9; + + let (k10_11, k11r) = expand_round!(k9, k10l, 0x40); + keys[10] = shuffle!(k10l, k10_11, 0); + keys[11] = shuffle!(k10_11, k11r, 1); + + let (k12, _) = expand_round!(k10_11, k11r, 0x80); + keys[12] = k12; + + keys +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(keys: &RoundKeys) -> RoundKeys { + [ + keys[0], + _mm_aesimc_si128(keys[1]), + _mm_aesimc_si128(keys[2]), + _mm_aesimc_si128(keys[3]), + _mm_aesimc_si128(keys[4]), + _mm_aesimc_si128(keys[5]), + _mm_aesimc_si128(keys[6]), + _mm_aesimc_si128(keys[7]), + _mm_aesimc_si128(keys[8]), + _mm_aesimc_si128(keys[9]), + _mm_aesimc_si128(keys[10]), + _mm_aesimc_si128(keys[11]), + keys[12], + ] +} diff --git a/vendor/aes/src/ni/aes256.rs b/vendor/aes/src/ni/aes256.rs new file mode 100644 index 00000000..bea090ab --- /dev/null +++ b/vendor/aes/src/ni/aes256.rs @@ -0,0 +1,196 @@ +use super::{arch::*, utils::*}; +use crate::{Block, Block8}; +use cipher::inout::InOut; +use core::mem; + +/// AES-192 round keys +pub(super) type RoundKeys = [__m128i; 15]; + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[0]); + b = _mm_aesenc_si128(b, keys[1]); + b = _mm_aesenc_si128(b, keys[2]); + b = _mm_aesenc_si128(b, keys[3]); + b = _mm_aesenc_si128(b, keys[4]); + b = _mm_aesenc_si128(b, keys[5]); + b = _mm_aesenc_si128(b, keys[6]); + b = _mm_aesenc_si128(b, keys[7]); + b = _mm_aesenc_si128(b, keys[8]); + b = _mm_aesenc_si128(b, keys[9]); + b = _mm_aesenc_si128(b, keys[10]); + b = _mm_aesenc_si128(b, keys[11]); + b = _mm_aesenc_si128(b, keys[12]); + b = _mm_aesenc_si128(b, keys[13]); + b = _mm_aesenclast_si128(b, keys[14]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn encrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[0]); + aesenc8(&mut b, keys[1]); + aesenc8(&mut b, keys[2]); + aesenc8(&mut b, keys[3]); + aesenc8(&mut b, keys[4]); + aesenc8(&mut b, keys[5]); + aesenc8(&mut b, keys[6]); + aesenc8(&mut b, keys[7]); + aesenc8(&mut b, keys[8]); + aesenc8(&mut b, keys[9]); + aesenc8(&mut b, keys[10]); + aesenc8(&mut b, keys[11]); + aesenc8(&mut b, keys[12]); + aesenc8(&mut b, keys[13]); + aesenclast8(&mut b, keys[14]); + store8(out_ptr, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt1(keys: &RoundKeys, block: InOut<'_, '_, Block>) { + let (in_ptr, out_ptr) = block.into_raw(); + let mut b = _mm_loadu_si128(in_ptr as *const __m128i); + b = _mm_xor_si128(b, keys[14]); + b = _mm_aesdec_si128(b, keys[13]); + b = _mm_aesdec_si128(b, keys[12]); + b = _mm_aesdec_si128(b, keys[11]); + b = _mm_aesdec_si128(b, keys[10]); + b = _mm_aesdec_si128(b, keys[9]); + b = _mm_aesdec_si128(b, keys[8]); + b = _mm_aesdec_si128(b, keys[7]); + b = _mm_aesdec_si128(b, keys[6]); + b = _mm_aesdec_si128(b, keys[5]); + b = _mm_aesdec_si128(b, keys[4]); + b = _mm_aesdec_si128(b, keys[3]); + b = _mm_aesdec_si128(b, keys[2]); + b = _mm_aesdec_si128(b, keys[1]); + b = _mm_aesdeclast_si128(b, keys[0]); + _mm_storeu_si128(out_ptr as *mut __m128i, b); +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn decrypt8(keys: &RoundKeys, blocks: InOut<'_, '_, Block8>) { + let (in_ptr, out_ptr) = blocks.into_raw(); + let mut b = load8(in_ptr); + xor8(&mut b, keys[14]); + aesdec8(&mut b, keys[13]); + aesdec8(&mut b, keys[12]); + aesdec8(&mut b, keys[11]); + aesdec8(&mut b, keys[10]); + aesdec8(&mut b, keys[9]); + aesdec8(&mut b, keys[8]); + aesdec8(&mut b, keys[7]); + aesdec8(&mut b, keys[6]); + aesdec8(&mut b, keys[5]); + aesdec8(&mut b, keys[4]); + aesdec8(&mut b, keys[3]); + aesdec8(&mut b, keys[2]); + aesdec8(&mut b, keys[1]); + aesdeclast8(&mut b, keys[0]); + store8(out_ptr, b); +} + +macro_rules! expand_round { + ($keys:expr, $pos:expr, $round:expr) => { + let mut t1 = $keys[$pos - 2]; + let mut t2; + let mut t3 = $keys[$pos - 1]; + let mut t4; + + t2 = _mm_aeskeygenassist_si128(t3, $round); + t2 = _mm_shuffle_epi32(t2, 0xff); + t4 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t1 = _mm_xor_si128(t1, t2); + + $keys[$pos] = t1; + + t4 = _mm_aeskeygenassist_si128(t1, 0x00); + t2 = _mm_shuffle_epi32(t4, 0xaa); + t4 = _mm_slli_si128(t3, 0x4); + t3 = _mm_xor_si128(t3, t4); + t4 = _mm_slli_si128(t4, 0x4); + t3 = _mm_xor_si128(t3, t4); + t4 = _mm_slli_si128(t4, 0x4); + t3 = _mm_xor_si128(t3, t4); + t3 = _mm_xor_si128(t3, t2); + + $keys[$pos + 1] = t3; + }; +} + +macro_rules! expand_round_last { + ($keys:expr, $pos:expr, $round:expr) => { + let mut t1 = $keys[$pos - 2]; + let mut t2; + let t3 = $keys[$pos - 1]; + let mut t4; + + t2 = _mm_aeskeygenassist_si128(t3, $round); + t2 = _mm_shuffle_epi32(t2, 0xff); + t4 = _mm_slli_si128(t1, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t4 = _mm_slli_si128(t4, 0x4); + t1 = _mm_xor_si128(t1, t4); + t1 = _mm_xor_si128(t1, t2); + + $keys[$pos] = t1; + }; +} + +#[inline(always)] +pub(super) unsafe fn expand_key(key: &[u8; 32]) -> RoundKeys { + // SAFETY: `RoundKeys` is a `[__m128i; 15]` which can be initialized + // with all zeroes. + let mut keys: RoundKeys = mem::zeroed(); + + let kp = key.as_ptr() as *const __m128i; + keys[0] = _mm_loadu_si128(kp); + keys[1] = _mm_loadu_si128(kp.add(1)); + + expand_round!(keys, 2, 0x01); + expand_round!(keys, 4, 0x02); + expand_round!(keys, 6, 0x04); + expand_round!(keys, 8, 0x08); + expand_round!(keys, 10, 0x10); + expand_round!(keys, 12, 0x20); + expand_round_last!(keys, 14, 0x40); + + keys +} + +#[inline] +#[target_feature(enable = "aes")] +pub(super) unsafe fn inv_expanded_keys(keys: &RoundKeys) -> RoundKeys { + [ + keys[0], + _mm_aesimc_si128(keys[1]), + _mm_aesimc_si128(keys[2]), + _mm_aesimc_si128(keys[3]), + _mm_aesimc_si128(keys[4]), + _mm_aesimc_si128(keys[5]), + _mm_aesimc_si128(keys[6]), + _mm_aesimc_si128(keys[7]), + _mm_aesimc_si128(keys[8]), + _mm_aesimc_si128(keys[9]), + _mm_aesimc_si128(keys[10]), + _mm_aesimc_si128(keys[11]), + _mm_aesimc_si128(keys[12]), + _mm_aesimc_si128(keys[13]), + keys[14], + ] +} diff --git a/vendor/aes/src/ni/hazmat.rs b/vendor/aes/src/ni/hazmat.rs new file mode 100644 index 00000000..a2a735a3 --- /dev/null +++ b/vendor/aes/src/ni/hazmat.rs @@ -0,0 +1,80 @@ +//! Low-level "hazmat" AES functions: AES-NI support. +//! +//! Note: this isn't actually used in the `Aes128`/`Aes192`/`Aes256` +//! implementations in this crate, but instead provides raw AES-NI accelerated +//! access to the AES round function gated under the `hazmat` crate feature. + +use super::{ + arch::*, + utils::{load8, store8}, +}; +use crate::{Block, Block8}; + +/// AES cipher (encrypt) round function. +#[target_feature(enable = "aes")] +pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) { + // Safety: `loadu` and `storeu` support unaligned access + let b = _mm_loadu_si128(block.as_ptr() as *const __m128i); + let k = _mm_loadu_si128(round_key.as_ptr() as *const __m128i); + let out = _mm_aesenc_si128(b, k); + _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, out); +} + +/// AES cipher (encrypt) round function: parallel version. +#[target_feature(enable = "aes")] +pub(crate) unsafe fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + let xmm_keys = load8(round_keys); + let mut xmm_blocks = load8(blocks); + + for i in 0..8 { + xmm_blocks[i] = _mm_aesenc_si128(xmm_blocks[i], xmm_keys[i]); + } + + store8(blocks, xmm_blocks); +} + +/// AES cipher (encrypt) round function. +#[target_feature(enable = "aes")] +pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + // Safety: `loadu` and `storeu` support unaligned access + let b = _mm_loadu_si128(block.as_ptr() as *const __m128i); + let k = _mm_loadu_si128(round_key.as_ptr() as *const __m128i); + let out = _mm_aesdec_si128(b, k); + _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, out); +} + +/// AES cipher (encrypt) round function: parallel version. +#[target_feature(enable = "aes")] +pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + let xmm_keys = load8(round_keys); + let mut xmm_blocks = load8(blocks); + + for i in 0..8 { + xmm_blocks[i] = _mm_aesdec_si128(xmm_blocks[i], xmm_keys[i]); + } + + store8(blocks, xmm_blocks); +} + +/// AES mix columns function. +#[target_feature(enable = "aes")] +pub(crate) unsafe fn mix_columns(block: &mut Block) { + // Safety: `loadu` and `storeu` support unaligned access + let mut state = _mm_loadu_si128(block.as_ptr() as *const __m128i); + + // Emulate mix columns by performing three inverse mix columns operations + state = _mm_aesimc_si128(state); + state = _mm_aesimc_si128(state); + state = _mm_aesimc_si128(state); + + _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, state); +} + +/// AES inverse mix columns function. +#[target_feature(enable = "aes")] +pub(crate) unsafe fn inv_mix_columns(block: &mut Block) { + // Safety: `loadu` and `storeu` support unaligned access + let b = _mm_loadu_si128(block.as_ptr() as *const __m128i); + let out = _mm_aesimc_si128(b); + _mm_storeu_si128(block.as_mut_ptr() as *mut __m128i, out); +} diff --git a/vendor/aes/src/ni/test_expand.rs b/vendor/aes/src/ni/test_expand.rs new file mode 100644 index 00000000..6ab87c5e --- /dev/null +++ b/vendor/aes/src/ni/test_expand.rs @@ -0,0 +1,275 @@ +use super::utils::check; +use hex_literal::hex; + +#[test] +fn aes128_expand_key_test() { + use super::aes128::expand_key; + + let keys = [0x00; 16]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0000000000000000, 0x0000000000000000], + [0x6263636362636363, 0x6263636362636363], + [0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa], + [0x90973450696ccffa, 0xf2f457330b0fac99], + [0xee06da7b876a1581, 0x759e42b27e91ee2b], + [0x7f2e2b88f8443e09, 0x8dda7cbbf34b9290], + [0xec614b851425758c, 0x99ff09376ab49ba7], + [0x217517873550620b, 0xacaf6b3cc61bf09b], + [0x0ef903333ba96138, 0x97060a04511dfa9f], + [0xb1d4d8e28a7db9da, 0x1d7bb3de4c664941], + [0xb4ef5bcb3e92e211, 0x23e951cf6f8f188e], + ], + ); + + let keys = [0xff; 16]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0xffffffffffffffff, 0xffffffffffffffff], + [0xe8e9e9e917161616, 0xe8e9e9e917161616], + [0xadaeae19bab8b80f, 0x525151e6454747f0], + [0x090e2277b3b69a78, 0xe1e7cb9ea4a08c6e], + [0xe16abd3e52dc2746, 0xb33becd8179b60b6], + [0xe5baf3ceb766d488, 0x045d385013c658e6], + [0x71d07db3c6b6a93b, 0xc2eb916bd12dc98d], + [0xe90d208d2fbb89b6, 0xed5018dd3c7dd150], + [0x96337366b988fad0, 0x54d8e20d68a5335d], + [0x8bf03f233278c5f3, 0x66a027fe0e0514a3], + [0xd60a3588e472f07b, 0x82d2d7858cd7c326], + ], + ); + + let keys = hex!("000102030405060708090a0b0c0d0e0f"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0001020304050607, 0x08090a0b0c0d0e0f], + [0xd6aa74fdd2af72fa, 0xdaa678f1d6ab76fe], + [0xb692cf0b643dbdf1, 0xbe9bc5006830b3fe], + [0xb6ff744ed2c2c9bf, 0x6c590cbf0469bf41], + [0x47f7f7bc95353e03, 0xf96c32bcfd058dfd], + [0x3caaa3e8a99f9deb, 0x50f3af57adf622aa], + [0x5e390f7df7a69296, 0xa7553dc10aa31f6b], + [0x14f9701ae35fe28c, 0x440adf4d4ea9c026], + [0x47438735a41c65b9, 0xe016baf4aebf7ad2], + [0x549932d1f0855768, 0x1093ed9cbe2c974e], + [0x13111d7fe3944a17, 0xf307a78b4d2b30c5], + ], + ); + + let keys = hex!("6920e299a5202a6d656e636869746f2a"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x6920e299a5202a6d, 0x656e636869746f2a], + [0xfa8807605fa82d0d, 0x3ac64e6553b2214f], + [0xcf75838d90ddae80, 0xaa1be0e5f9a9c1aa], + [0x180d2f1488d08194, 0x22cb6171db62a0db], + [0xbaed96ad323d1739, 0x10f67648cb94d693], + [0x881b4ab2ba265d8b, 0xaad02bc36144fd50], + [0xb34f195d096944d6, 0xa3b96f15c2fd9245], + [0xa7007778ae6933ae, 0x0dd05cbbcf2dcefe], + [0xff8bccf251e2ff5c, 0x5c32a3e7931f6d19], + [0x24b7182e7555e772, 0x29674495ba78298c], + [0xae127cdadb479ba8, 0xf220df3d4858f6b1], + ], + ); + + let keys = hex!("2b7e151628aed2a6abf7158809cf4f3c"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x2b7e151628aed2a6, 0xabf7158809cf4f3c], + [0xa0fafe1788542cb1, 0x23a339392a6c7605], + [0xf2c295f27a96b943, 0x5935807a7359f67f], + [0x3d80477d4716fe3e, 0x1e237e446d7a883b], + [0xef44a541a8525b7f, 0xb671253bdb0bad00], + [0xd4d1c6f87c839d87, 0xcaf2b8bc11f915bc], + [0x6d88a37a110b3efd, 0xdbf98641ca0093fd], + [0x4e54f70e5f5fc9f3, 0x84a64fb24ea6dc4f], + [0xead27321b58dbad2, 0x312bf5607f8d292f], + [0xac7766f319fadc21, 0x28d12941575c006e], + [0xd014f9a8c9ee2589, 0xe13f0cc8b6630ca6], + ], + ); +} + +#[test] +fn aes192_expand_key_test() { + use super::aes192::expand_key; + + let keys = [0x00; 24]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0000000000000000, 0x0000000000000000], + [0x0000000000000000, 0x6263636362636363], + [0x6263636362636363, 0x6263636362636363], + [0x9b9898c9f9fbfbaa, 0x9b9898c9f9fbfbaa], + [0x9b9898c9f9fbfbaa, 0x90973450696ccffa], + [0xf2f457330b0fac99, 0x90973450696ccffa], + [0xc81d19a9a171d653, 0x53858160588a2df9], + [0xc81d19a9a171d653, 0x7bebf49bda9a22c8], + [0x891fa3a8d1958e51, 0x198897f8b8f941ab], + [0xc26896f718f2b43f, 0x91ed1797407899c6], + [0x59f00e3ee1094f95, 0x83ecbc0f9b1e0830], + [0x0af31fa74a8b8661, 0x137b885ff272c7ca], + [0x432ac886d834c0b6, 0xd2c7df11984c5970], + ], + ); + + let keys = [0xff; 24]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0xffffffffffffffff, 0xffffffffffffffff], + [0xffffffffffffffff, 0xe8e9e9e917161616], + [0xe8e9e9e917161616, 0xe8e9e9e917161616], + [0xadaeae19bab8b80f, 0x525151e6454747f0], + [0xadaeae19bab8b80f, 0xc5c2d8ed7f7a60e2], + [0x2d2b3104686c76f4, 0xc5c2d8ed7f7a60e2], + [0x1712403f686820dd, 0x454311d92d2f672d], + [0xe8edbfc09797df22, 0x8f8cd3b7e7e4f36a], + [0xa2a7e2b38f88859e, 0x67653a5ef0f2e57c], + [0x2655c33bc1b13051, 0x6316d2e2ec9e577c], + [0x8bfb6d227b09885e, 0x67919b1aa620ab4b], + [0xc53679a929a82ed5, 0xa25343f7d95acba9], + [0x598e482fffaee364, 0x3a989acd1330b418], + ], + ); + + let keys = hex!("000102030405060708090a0b0c0d0e0f1011121314151617"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0001020304050607, 0x08090a0b0c0d0e0f], + [0x1011121314151617, 0x5846f2f95c43f4fe], + [0x544afef55847f0fa, 0x4856e2e95c43f4fe], + [0x40f949b31cbabd4d, 0x48f043b810b7b342], + [0x58e151ab04a2a555, 0x7effb5416245080c], + [0x2ab54bb43a02f8f6, 0x62e3a95d66410c08], + [0xf501857297448d7e, 0xbdf1c6ca87f33e3c], + [0xe510976183519b69, 0x34157c9ea351f1e0], + [0x1ea0372a99530916, 0x7c439e77ff12051e], + [0xdd7e0e887e2fff68, 0x608fc842f9dcc154], + [0x859f5f237a8d5a3d, 0xc0c02952beefd63a], + [0xde601e7827bcdf2c, 0xa223800fd8aeda32], + [0xa4970a331a78dc09, 0xc418c271e3a41d5d], + ], + ); + + let keys = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x8e73b0f7da0e6452, 0xc810f32b809079e5], + [0x62f8ead2522c6b7b, 0xfe0c91f72402f5a5], + [0xec12068e6c827f6b, 0x0e7a95b95c56fec2], + [0x4db7b4bd69b54118, 0x85a74796e92538fd], + [0xe75fad44bb095386, 0x485af05721efb14f], + [0xa448f6d94d6dce24, 0xaa326360113b30e6], + [0xa25e7ed583b1cf9a, 0x27f939436a94f767], + [0xc0a69407d19da4e1, 0xec1786eb6fa64971], + [0x485f703222cb8755, 0xe26d135233f0b7b3], + [0x40beeb282f18a259, 0x6747d26b458c553e], + [0xa7e1466c9411f1df, 0x821f750aad07d753], + [0xca4005388fcc5006, 0x282d166abc3ce7b5], + [0xe98ba06f448c773c, 0x8ecc720401002202], + ], + ); +} + +#[test] +fn aes256_expand_key_test() { + use super::aes256::expand_key; + + let keys = [0x00; 32]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0000000000000000, 0x0000000000000000], + [0x0000000000000000, 0x0000000000000000], + [0x6263636362636363, 0x6263636362636363], + [0xaafbfbfbaafbfbfb, 0xaafbfbfbaafbfbfb], + [0x6f6c6ccf0d0f0fac, 0x6f6c6ccf0d0f0fac], + [0x7d8d8d6ad7767691, 0x7d8d8d6ad7767691], + [0x5354edc15e5be26d, 0x31378ea23c38810e], + [0x968a81c141fcf750, 0x3c717a3aeb070cab], + [0x9eaa8f28c0f16d45, 0xf1c6e3e7cdfe62e9], + [0x2b312bdf6acddc8f, 0x56bca6b5bdbbaa1e], + [0x6406fd52a4f79017, 0x553173f098cf1119], + [0x6dbba90b07767584, 0x51cad331ec71792f], + [0xe7b0e89c4347788b, 0x16760b7b8eb91a62], + [0x74ed0ba1739b7e25, 0x2251ad14ce20d43b], + [0x10f80a1753bf729c, 0x45c979e7cb706385], + ], + ); + + let keys = [0xff; 32]; + check( + unsafe { &expand_key(&keys) }, + &[ + [0xffffffffffffffff, 0xffffffffffffffff], + [0xffffffffffffffff, 0xffffffffffffffff], + [0xe8e9e9e917161616, 0xe8e9e9e917161616], + [0x0fb8b8b8f0474747, 0x0fb8b8b8f0474747], + [0x4a4949655d5f5f73, 0xb5b6b69aa2a0a08c], + [0x355858dcc51f1f9b, 0xcaa7a7233ae0e064], + [0xafa80ae5f2f75596, 0x4741e30ce5e14380], + [0xeca0421129bf5d8a, 0xe318faa9d9f81acd], + [0xe60ab7d014fde246, 0x53bc014ab65d42ca], + [0xa2ec6e658b5333ef, 0x684bc946b1b3d38b], + [0x9b6c8a188f91685e, 0xdc2d69146a702bde], + [0xa0bd9f782beeac97, 0x43a565d1f216b65a], + [0xfc22349173b35ccf, 0xaf9e35dbc5ee1e05], + [0x0695ed132d7b4184, 0x6ede24559cc8920f], + [0x546d424f27de1e80, 0x88402b5b4dae355e], + ], + ); + + let keys = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x0001020304050607, 0x08090a0b0c0d0e0f], + [0x1011121314151617, 0x18191a1b1c1d1e1f], + [0xa573c29fa176c498, 0xa97fce93a572c09c], + [0x1651a8cd0244beda, 0x1a5da4c10640bade], + [0xae87dff00ff11b68, 0xa68ed5fb03fc1567], + [0x6de1f1486fa54f92, 0x75f8eb5373b8518d], + [0xc656827fc9a79917, 0x6f294cec6cd5598b], + [0x3de23a75524775e7, 0x27bf9eb45407cf39], + [0x0bdc905fc27b0948, 0xad5245a4c1871c2f], + [0x45f5a66017b2d387, 0x300d4d33640a820a], + [0x7ccff71cbeb4fe54, 0x13e6bbf0d261a7df], + [0xf01afafee7a82979, 0xd7a5644ab3afe640], + [0x2541fe719bf50025, 0x8813bbd55a721c0a], + [0x4e5a6699a9f24fe0, 0x7e572baacdf8cdea], + [0x24fc79ccbf0979e9, 0x371ac23c6d68de36], + ], + ); + + let keys = hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + check( + unsafe { &expand_key(&keys) }, + &[ + [0x603deb1015ca71be, 0x2b73aef0857d7781], + [0x1f352c073b6108d7, 0x2d9810a30914dff4], + [0x9ba354118e6925af, 0xa51a8b5f2067fcde], + [0xa8b09c1a93d194cd, 0xbe49846eb75d5b9a], + [0xd59aecb85bf3c917, 0xfee94248de8ebe96], + [0xb5a9328a2678a647, 0x983122292f6c79b3], + [0x812c81addadf48ba, 0x24360af2fab8b464], + [0x98c5bfc9bebd198e, 0x268c3ba709e04214], + [0x68007bacb2df3316, 0x96e939e46c518d80], + [0xc814e20476a9fb8a, 0x5025c02d59c58239], + [0xde1369676ccc5a71, 0xfa2563959674ee15], + [0x5886ca5d2e2f31d7, 0x7e0af1fa27cf73c3], + [0x749c47ab18501dda, 0xe2757e4f7401905a], + [0xcafaaae3e4d59b34, 0x9adf6acebd10190d], + [0xfe4890d1e6188d0b, 0x046df344706c631e], + ], + ); +} diff --git a/vendor/aes/src/ni/utils.rs b/vendor/aes/src/ni/utils.rs new file mode 100644 index 00000000..1bd6522d --- /dev/null +++ b/vendor/aes/src/ni/utils.rs @@ -0,0 +1,92 @@ +//! Utility functions + +// TODO(tarcieri): check performance impact / generated assembly changes +#![allow(clippy::needless_range_loop)] + +use super::arch::*; +use crate::{Block, Block8}; + +pub type U128x8 = [__m128i; 8]; + +#[cfg(test)] +pub(crate) fn check(a: &[__m128i], b: &[[u64; 2]]) { + for (v1, v2) in a.iter().zip(b) { + let t1: [u64; 2] = unsafe { core::mem::transmute(*v1) }; + let t2 = [v2[0].to_be(), v2[1].to_be()]; + assert_eq!(t1, t2); + } +} + +#[inline(always)] +pub(crate) fn load8(blocks: *const Block8) -> U128x8 { + unsafe { + let p = blocks as *const Block; + [ + _mm_loadu_si128(p.add(0) as *const __m128i), + _mm_loadu_si128(p.add(1) as *const __m128i), + _mm_loadu_si128(p.add(2) as *const __m128i), + _mm_loadu_si128(p.add(3) as *const __m128i), + _mm_loadu_si128(p.add(4) as *const __m128i), + _mm_loadu_si128(p.add(5) as *const __m128i), + _mm_loadu_si128(p.add(6) as *const __m128i), + _mm_loadu_si128(p.add(7) as *const __m128i), + ] + } +} + +#[inline(always)] +pub(crate) fn store8(blocks: *mut Block8, b: U128x8) { + unsafe { + let p = blocks as *mut Block; + _mm_storeu_si128(p.add(0) as *mut __m128i, b[0]); + _mm_storeu_si128(p.add(1) as *mut __m128i, b[1]); + _mm_storeu_si128(p.add(2) as *mut __m128i, b[2]); + _mm_storeu_si128(p.add(3) as *mut __m128i, b[3]); + _mm_storeu_si128(p.add(4) as *mut __m128i, b[4]); + _mm_storeu_si128(p.add(5) as *mut __m128i, b[5]); + _mm_storeu_si128(p.add(6) as *mut __m128i, b[6]); + _mm_storeu_si128(p.add(7) as *mut __m128i, b[7]); + } +} + +#[inline(always)] +pub(crate) fn xor8(b: &mut U128x8, key: __m128i) { + unsafe { + b[0] = _mm_xor_si128(b[0], key); + b[1] = _mm_xor_si128(b[1], key); + b[2] = _mm_xor_si128(b[2], key); + b[3] = _mm_xor_si128(b[3], key); + b[4] = _mm_xor_si128(b[4], key); + b[5] = _mm_xor_si128(b[5], key); + b[6] = _mm_xor_si128(b[6], key); + b[7] = _mm_xor_si128(b[7], key); + } +} + +#[inline(always)] +pub(crate) fn aesenc8(buffer: &mut U128x8, key: __m128i) { + for i in 0..8 { + buffer[i] = unsafe { _mm_aesenc_si128(buffer[i], key) }; + } +} + +#[inline(always)] +pub(crate) fn aesenclast8(buffer: &mut U128x8, key: __m128i) { + for i in 0..8 { + buffer[i] = unsafe { _mm_aesenclast_si128(buffer[i], key) }; + } +} + +#[inline(always)] +pub(crate) fn aesdec8(buffer: &mut U128x8, key: __m128i) { + for i in 0..8 { + buffer[i] = unsafe { _mm_aesdec_si128(buffer[i], key) }; + } +} + +#[inline(always)] +pub(crate) fn aesdeclast8(buffer: &mut U128x8, key: __m128i) { + for i in 0..8 { + buffer[i] = unsafe { _mm_aesdeclast_si128(buffer[i], key) }; + } +} diff --git a/vendor/aes/src/soft.rs b/vendor/aes/src/soft.rs new file mode 100644 index 00000000..5f90b1e2 --- /dev/null +++ b/vendor/aes/src/soft.rs @@ -0,0 +1,342 @@ +//! AES block cipher constant-time implementation. +//! +//! The implementation uses a technique called [fixslicing][1], an improved +//! form of bitslicing which represents ciphers in a way which enables +//! very efficient constant-time implementations in software. +//! +//! [1]: https://eprint.iacr.org/2020/1123.pdf + +#![deny(unsafe_code)] + +#[cfg_attr(not(target_pointer_width = "64"), path = "soft/fixslice32.rs")] +#[cfg_attr(target_pointer_width = "64", path = "soft/fixslice64.rs")] +pub(crate) mod fixslice; + +use crate::Block; +use cipher::{ + consts::{U16, U24, U32}, + inout::InOut, + AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, + BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, +}; +use core::fmt; +use fixslice::{BatchBlocks, FixsliceBlocks, FixsliceKeys128, FixsliceKeys192, FixsliceKeys256}; + +macro_rules! define_aes_impl { + ( + $name:tt, + $name_enc:ident, + $name_dec:ident, + $name_back_enc:ident, + $name_back_dec:ident, + $key_size:ty, + $fixslice_keys:ty, + $fixslice_key_schedule:path, + $fixslice_decrypt:path, + $fixslice_encrypt:path, + $doc:expr $(,)? + ) => { + #[doc=$doc] + #[doc = "block cipher"] + #[derive(Clone)] + pub struct $name { + keys: $fixslice_keys, + } + + impl $name { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + $name_back_enc(self) + } + + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + $name_back_dec(self) + } + } + + impl KeySizeUser for $name { + type KeySize = $key_size; + } + + impl KeyInit for $name { + #[inline] + fn new(key: &Key) -> Self { + Self { + keys: $fixslice_key_schedule(key.as_ref()), + } + } + } + + impl BlockSizeUser for $name { + type BlockSize = U16; + } + + impl BlockCipher for $name {} + + impl BlockEncrypt for $name { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl BlockDecrypt for $name { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()) + } + } + + impl From<$name_enc> for $name { + #[inline] + fn from(enc: $name_enc) -> $name { + enc.inner + } + } + + impl From<&$name_enc> for $name { + #[inline] + fn from(enc: &$name_enc) -> $name { + enc.inner.clone() + } + } + + impl fmt::Debug for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name), " { .. }")) + } + } + + impl AlgorithmName for $name { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name)) + } + } + + impl Drop for $name { + #[inline] + fn drop(&mut self) { + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut self.keys); + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name {} + + #[doc=$doc] + #[doc = "block cipher (encrypt-only)"] + #[derive(Clone)] + pub struct $name_enc { + inner: $name, + } + + impl $name_enc { + #[inline(always)] + pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { + self.inner.get_enc_backend() + } + } + + impl BlockCipher for $name_enc {} + + impl KeySizeUser for $name_enc { + type KeySize = $key_size; + } + + impl KeyInit for $name_enc { + #[inline(always)] + fn new(key: &Key) -> Self { + let inner = $name::new(key); + Self { inner } + } + } + + impl BlockSizeUser for $name_enc { + type BlockSize = U16; + } + + impl BlockEncrypt for $name_enc { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_enc_backend()) + } + } + + impl fmt::Debug for $name_enc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_enc), " { .. }")) + } + } + + impl AlgorithmName for $name_enc { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_enc)) + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_enc {} + + #[doc=$doc] + #[doc = "block cipher (decrypt-only)"] + #[derive(Clone)] + pub struct $name_dec { + inner: $name, + } + + impl $name_dec { + #[inline(always)] + pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { + self.inner.get_dec_backend() + } + } + + impl BlockCipher for $name_dec {} + + impl KeySizeUser for $name_dec { + type KeySize = $key_size; + } + + impl KeyInit for $name_dec { + #[inline(always)] + fn new(key: &Key) -> Self { + let inner = $name::new(key); + Self { inner } + } + } + + impl From<$name_enc> for $name_dec { + #[inline] + fn from(enc: $name_enc) -> $name_dec { + Self { inner: enc.inner } + } + } + + impl From<&$name_enc> for $name_dec { + #[inline] + fn from(enc: &$name_enc) -> $name_dec { + Self { + inner: enc.inner.clone(), + } + } + } + + impl BlockSizeUser for $name_dec { + type BlockSize = U16; + } + + impl BlockDecrypt for $name_dec { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + f.call(&mut self.get_dec_backend()); + } + } + + impl fmt::Debug for $name_dec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(concat!(stringify!($name_dec), " { .. }")) + } + } + + impl AlgorithmName for $name_dec { + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(stringify!($name_dec)) + } + } + + #[cfg(feature = "zeroize")] + impl zeroize::ZeroizeOnDrop for $name_dec {} + + pub(crate) struct $name_back_enc<'a>(&'a $name); + + impl<'a> BlockSizeUser for $name_back_enc<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { + type ParBlocksSize = FixsliceBlocks; + } + + impl<'a> BlockBackend for $name_back_enc<'a> { + #[inline(always)] + fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { + let mut blocks = BatchBlocks::default(); + blocks[0] = block.clone_in().into(); + let res = $fixslice_encrypt(&self.0.keys, &blocks); + *block.get_out() = res[0].into(); + } + + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, BatchBlocks>) { + let res = $fixslice_encrypt(&self.0.keys, blocks.get_in()); + *blocks.get_out() = res; + } + } + + pub(crate) struct $name_back_dec<'a>(&'a $name); + + impl<'a> BlockSizeUser for $name_back_dec<'a> { + type BlockSize = U16; + } + + impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { + type ParBlocksSize = FixsliceBlocks; + } + + impl<'a> BlockBackend for $name_back_dec<'a> { + #[inline(always)] + fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { + let mut blocks = BatchBlocks::default(); + blocks[0] = block.clone_in(); + let res = $fixslice_decrypt(&self.0.keys, &blocks); + *block.get_out() = res[0]; + } + + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, BatchBlocks>) { + let res = $fixslice_decrypt(&self.0.keys, blocks.get_in()); + *blocks.get_out() = res; + } + } + }; +} + +define_aes_impl!( + Aes128, + Aes128Enc, + Aes128Dec, + Aes128BackEnc, + Aes128BackDec, + U16, + FixsliceKeys128, + fixslice::aes128_key_schedule, + fixslice::aes128_decrypt, + fixslice::aes128_encrypt, + "AES-128", +); + +define_aes_impl!( + Aes192, + Aes192Enc, + Aes192Dec, + Aes192BackEnc, + Aes192BackDec, + U24, + FixsliceKeys192, + fixslice::aes192_key_schedule, + fixslice::aes192_decrypt, + fixslice::aes192_encrypt, + "AES-192", +); + +define_aes_impl!( + Aes256, + Aes256Enc, + Aes256Dec, + Aes256BackEnc, + Aes256BackDec, + U32, + FixsliceKeys256, + fixslice::aes256_key_schedule, + fixslice::aes256_decrypt, + fixslice::aes256_encrypt, + "AES-256", +); diff --git a/vendor/aes/src/soft/fixslice32.rs b/vendor/aes/src/soft/fixslice32.rs new file mode 100644 index 00000000..45b674d6 --- /dev/null +++ b/vendor/aes/src/soft/fixslice32.rs @@ -0,0 +1,1479 @@ +//! Fixsliced implementations of AES-128, AES-192 and AES-256 (32-bit) +//! adapted from the C implementation +//! +//! All implementations are fully bitsliced and do not rely on any +//! Look-Up Table (LUT). +//! +//! See the paper at for more details. +//! +//! # Author (original C code) +//! +//! Alexandre Adomnicai, Nanyang Technological University, Singapore +//! +//! +//! Originally licensed MIT. Relicensed as Apache 2.0+MIT with permission. + +#![allow(clippy::unreadable_literal)] + +use crate::Block; +use cipher::{consts::U2, generic_array::GenericArray}; + +/// AES block batch size for this implementation +pub(crate) type FixsliceBlocks = U2; + +pub(crate) type BatchBlocks = GenericArray; + +/// AES-128 round keys +pub(crate) type FixsliceKeys128 = [u32; 88]; + +/// AES-192 round keys +pub(crate) type FixsliceKeys192 = [u32; 104]; + +/// AES-256 round keys +pub(crate) type FixsliceKeys256 = [u32; 120]; + +/// 256-bit internal state +pub(crate) type State = [u32; 8]; + +/// Fully bitsliced AES-128 key schedule to match the fully-fixsliced representation. +pub(crate) fn aes128_key_schedule(key: &[u8; 16]) -> FixsliceKeys128 { + let mut rkeys = [0u32; 88]; + + bitslice(&mut rkeys[..8], key, key); + + let mut rk_off = 0; + for rcon in 0..10 { + memshift32(&mut rkeys, rk_off); + rk_off += 8; + + sub_bytes(&mut rkeys[rk_off..(rk_off + 8)]); + sub_bytes_nots(&mut rkeys[rk_off..(rk_off + 8)]); + + if rcon < 8 { + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon); + } else { + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 8); + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 7); + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 5); + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 4); + } + + xor_columns(&mut rkeys, rk_off, 8, ror_distance(1, 3)); + } + + // Adjust to match fixslicing format + #[cfg(aes_compact)] + { + for i in (8..88).step_by(16) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + } + } + #[cfg(not(aes_compact))] + { + for i in (8..72).step_by(32) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + inv_shift_rows_2(&mut rkeys[(i + 8)..(i + 16)]); + inv_shift_rows_3(&mut rkeys[(i + 16)..(i + 24)]); + } + inv_shift_rows_1(&mut rkeys[72..80]); + } + + // Account for NOTs removed from sub_bytes + for i in 1..11 { + sub_bytes_nots(&mut rkeys[(i * 8)..(i * 8 + 8)]); + } + + rkeys +} + +/// Fully bitsliced AES-192 key schedule to match the fully-fixsliced representation. +pub(crate) fn aes192_key_schedule(key: &[u8; 24]) -> FixsliceKeys192 { + let mut rkeys = [0u32; 104]; + let mut tmp = [0u32; 8]; + + bitslice(&mut rkeys[..8], &key[..16], &key[..16]); + bitslice(&mut tmp, &key[8..], &key[8..]); + + let mut rcon = 0; + let mut rk_off = 8; + + loop { + for i in 0..8 { + rkeys[rk_off + i] = + (0x0f0f0f0f & (tmp[i] >> 4)) | (0xf0f0f0f0 & (rkeys[(rk_off - 8) + i] << 4)); + } + + sub_bytes(&mut tmp); + sub_bytes_nots(&mut tmp); + + add_round_constant_bit(&mut tmp, rcon); + rcon += 1; + + for i in 0..8 { + let mut ti = rkeys[rk_off + i]; + ti ^= 0x30303030 & ror(tmp[i], ror_distance(1, 1)); + ti ^= 0xc0c0c0c0 & (ti << 2); + tmp[i] = ti; + } + rkeys[rk_off..(rk_off + 8)].copy_from_slice(&tmp); + rk_off += 8; + + for i in 0..8 { + let ui = tmp[i]; + let mut ti = (0x0f0f0f0f & (rkeys[(rk_off - 16) + i] >> 4)) | (0xf0f0f0f0 & (ui << 4)); + ti ^= 0x03030303 & (ui >> 6); + tmp[i] = + ti ^ (0xfcfcfcfc & (ti << 2)) ^ (0xf0f0f0f0 & (ti << 4)) ^ (0xc0c0c0c0 & (ti << 6)); + } + rkeys[rk_off..(rk_off + 8)].copy_from_slice(&tmp); + rk_off += 8; + + sub_bytes(&mut tmp); + sub_bytes_nots(&mut tmp); + + add_round_constant_bit(&mut tmp, rcon); + rcon += 1; + + for i in 0..8 { + let mut ti = (0x0f0f0f0f & (rkeys[(rk_off - 16) + i] >> 4)) + | (0xf0f0f0f0 & (rkeys[(rk_off - 8) + i] << 4)); + ti ^= 0x03030303 & ror(tmp[i], ror_distance(1, 3)); + rkeys[rk_off + i] = + ti ^ (0xfcfcfcfc & (ti << 2)) ^ (0xf0f0f0f0 & (ti << 4)) ^ (0xc0c0c0c0 & (ti << 6)); + } + rk_off += 8; + + if rcon >= 8 { + break; + } + + for i in 0..8 { + let ui = rkeys[(rk_off - 8) + i]; + let mut ti = rkeys[(rk_off - 16) + i]; + ti ^= 0x30303030 & (ui >> 2); + ti ^= 0xc0c0c0c0 & (ti << 2); + tmp[i] = ti; + } + } + + // Adjust to match fixslicing format + #[cfg(aes_compact)] + { + for i in (8..104).step_by(16) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + } + } + #[cfg(not(aes_compact))] + { + for i in (0..96).step_by(32) { + inv_shift_rows_1(&mut rkeys[(i + 8)..(i + 16)]); + inv_shift_rows_2(&mut rkeys[(i + 16)..(i + 24)]); + inv_shift_rows_3(&mut rkeys[(i + 24)..(i + 32)]); + } + } + + // Account for NOTs removed from sub_bytes + for i in 1..13 { + sub_bytes_nots(&mut rkeys[(i * 8)..(i * 8 + 8)]); + } + + rkeys +} + +/// Fully bitsliced AES-256 key schedule to match the fully-fixsliced representation. +pub(crate) fn aes256_key_schedule(key: &[u8; 32]) -> FixsliceKeys256 { + let mut rkeys = [0u32; 120]; + + bitslice(&mut rkeys[..8], &key[..16], &key[..16]); + bitslice(&mut rkeys[8..16], &key[16..], &key[16..]); + + let mut rk_off = 8; + + let mut rcon = 0; + loop { + memshift32(&mut rkeys, rk_off); + rk_off += 8; + + sub_bytes(&mut rkeys[rk_off..(rk_off + 8)]); + sub_bytes_nots(&mut rkeys[rk_off..(rk_off + 8)]); + + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon); + xor_columns(&mut rkeys, rk_off, 16, ror_distance(1, 3)); + rcon += 1; + + if rcon == 7 { + break; + } + + memshift32(&mut rkeys, rk_off); + rk_off += 8; + + sub_bytes(&mut rkeys[rk_off..(rk_off + 8)]); + sub_bytes_nots(&mut rkeys[rk_off..(rk_off + 8)]); + + xor_columns(&mut rkeys, rk_off, 16, ror_distance(0, 3)); + } + + // Adjust to match fixslicing format + #[cfg(aes_compact)] + { + for i in (8..120).step_by(16) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + } + } + #[cfg(not(aes_compact))] + { + for i in (8..104).step_by(32) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + inv_shift_rows_2(&mut rkeys[(i + 8)..(i + 16)]); + inv_shift_rows_3(&mut rkeys[(i + 16)..(i + 24)]); + } + inv_shift_rows_1(&mut rkeys[104..112]); + } + + // Account for NOTs removed from sub_bytes + for i in 1..15 { + sub_bytes_nots(&mut rkeys[(i * 8)..(i * 8 + 8)]); + } + + rkeys +} + +/// Fully-fixsliced AES-128 decryption (the InvShiftRows is completely omitted). +/// +/// Decrypts four blocks in-place and in parallel. +pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1]); + + add_round_key(&mut state, &rkeys[80..]); + inv_sub_bytes(&mut state); + + #[cfg(not(aes_compact))] + { + inv_shift_rows_2(&mut state); + } + + let mut rk_off = 72; + loop { + #[cfg(aes_compact)] + { + inv_shift_rows_2(&mut state); + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_1(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + if rk_off == 0 { + break; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_0(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + #[cfg(not(aes_compact))] + { + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_3(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_2(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + } + + add_round_key(&mut state, &rkeys[..8]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-128 encryption (the ShiftRows is completely omitted). +/// +/// Encrypts four blocks in-place and in parallel. +pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1]); + + add_round_key(&mut state, &rkeys[..8]); + + let mut rk_off = 8; + loop { + sub_bytes(&mut state); + mix_columns_1(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + #[cfg(aes_compact)] + { + shift_rows_2(&mut state); + } + + if rk_off == 80 { + break; + } + + #[cfg(not(aes_compact))] + { + sub_bytes(&mut state); + mix_columns_2(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + sub_bytes(&mut state); + mix_columns_3(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + sub_bytes(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + #[cfg(not(aes_compact))] + { + shift_rows_2(&mut state); + } + + sub_bytes(&mut state); + add_round_key(&mut state, &rkeys[80..]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-192 decryption (the InvShiftRows is completely omitted). +/// +/// Decrypts four blocks in-place and in parallel. +pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1]); + + add_round_key(&mut state, &rkeys[96..]); + inv_sub_bytes(&mut state); + + let mut rk_off = 88; + loop { + #[cfg(aes_compact)] + { + inv_shift_rows_2(&mut state); + } + #[cfg(not(aes_compact))] + { + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_3(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_2(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_1(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + if rk_off == 0 { + break; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_0(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + + add_round_key(&mut state, &rkeys[..8]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-192 encryption (the ShiftRows is completely omitted). +/// +/// Encrypts four blocks in-place and in parallel. +pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1]); + + add_round_key(&mut state, &rkeys[..8]); + + let mut rk_off = 8; + loop { + sub_bytes(&mut state); + mix_columns_1(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + #[cfg(aes_compact)] + { + shift_rows_2(&mut state); + } + #[cfg(not(aes_compact))] + { + sub_bytes(&mut state); + mix_columns_2(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + sub_bytes(&mut state); + mix_columns_3(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + if rk_off == 96 { + break; + } + + sub_bytes(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + sub_bytes(&mut state); + add_round_key(&mut state, &rkeys[96..]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-256 decryption (the InvShiftRows is completely omitted). +/// +/// Decrypts four blocks in-place and in parallel. +pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1]); + + add_round_key(&mut state, &rkeys[112..]); + inv_sub_bytes(&mut state); + + #[cfg(not(aes_compact))] + { + inv_shift_rows_2(&mut state); + } + + let mut rk_off = 104; + loop { + #[cfg(aes_compact)] + { + inv_shift_rows_2(&mut state); + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_1(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + if rk_off == 0 { + break; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_0(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + #[cfg(not(aes_compact))] + { + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_3(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_2(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + } + + add_round_key(&mut state, &rkeys[..8]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-256 encryption (the ShiftRows is completely omitted). +/// +/// Encrypts four blocks in-place and in parallel. +pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1]); + + add_round_key(&mut state, &rkeys[..8]); + + let mut rk_off = 8; + loop { + sub_bytes(&mut state); + mix_columns_1(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + #[cfg(aes_compact)] + { + shift_rows_2(&mut state); + } + + if rk_off == 112 { + break; + } + + #[cfg(not(aes_compact))] + { + sub_bytes(&mut state); + mix_columns_2(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + sub_bytes(&mut state); + mix_columns_3(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + sub_bytes(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + #[cfg(not(aes_compact))] + { + shift_rows_2(&mut state); + } + + sub_bytes(&mut state); + add_round_key(&mut state, &rkeys[112..]); + + inv_bitslice(&state) +} + +/// Note that the 4 bitwise NOT (^= 0xffffffff) are accounted for here so that it is a true +/// inverse of 'sub_bytes'. +fn inv_sub_bytes(state: &mut [u32]) { + debug_assert_eq!(state.len(), 8); + + // Scheduled using https://github.com/Ko-/aes-armcortexm/tree/public/scheduler + // Inline "stack" comments reflect suggested stores and loads (ARM Cortex-M3 and M4) + + let u7 = state[0]; + let u6 = state[1]; + let u5 = state[2]; + let u4 = state[3]; + let u3 = state[4]; + let u2 = state[5]; + let u1 = state[6]; + let u0 = state[7]; + + let t23 = u0 ^ u3; + let t8 = u1 ^ t23; + let m2 = t23 & t8; + let t4 = u4 ^ t8; + let t22 = u1 ^ u3; + let t2 = u0 ^ u1; + let t1 = u3 ^ u4; + // t23 -> stack + let t9 = u7 ^ t1; + // t8 -> stack + let m7 = t22 & t9; + // t9 -> stack + let t24 = u4 ^ u7; + // m7 -> stack + let t10 = t2 ^ t24; + // u4 -> stack + let m14 = t2 & t10; + let r5 = u6 ^ u7; + // m2 -> stack + let t3 = t1 ^ r5; + // t2 -> stack + let t13 = t2 ^ r5; + let t19 = t22 ^ r5; + // t3 -> stack + let t17 = u2 ^ t19; + // t4 -> stack + let t25 = u2 ^ t1; + let r13 = u1 ^ u6; + // t25 -> stack + let t20 = t24 ^ r13; + // t17 -> stack + let m9 = t20 & t17; + // t20 -> stack + let r17 = u2 ^ u5; + // t22 -> stack + let t6 = t22 ^ r17; + // t13 -> stack + let m1 = t13 & t6; + let y5 = u0 ^ r17; + let m4 = t19 & y5; + let m5 = m4 ^ m1; + let m17 = m5 ^ t24; + let r18 = u5 ^ u6; + let t27 = t1 ^ r18; + let t15 = t10 ^ t27; + // t6 -> stack + let m11 = t1 & t15; + let m15 = m14 ^ m11; + let m21 = m17 ^ m15; + // t1 -> stack + // t4 <- stack + let m12 = t4 & t27; + let m13 = m12 ^ m11; + let t14 = t10 ^ r18; + let m3 = t14 ^ m1; + // m2 <- stack + let m16 = m3 ^ m2; + let m20 = m16 ^ m13; + // u4 <- stack + let r19 = u2 ^ u4; + let t16 = r13 ^ r19; + // t3 <- stack + let t26 = t3 ^ t16; + let m6 = t3 & t16; + let m8 = t26 ^ m6; + // t10 -> stack + // m7 <- stack + let m18 = m8 ^ m7; + let m22 = m18 ^ m13; + let m25 = m22 & m20; + let m26 = m21 ^ m25; + let m10 = m9 ^ m6; + let m19 = m10 ^ m15; + // t25 <- stack + let m23 = m19 ^ t25; + let m28 = m23 ^ m25; + let m24 = m22 ^ m23; + let m30 = m26 & m24; + let m39 = m23 ^ m30; + let m48 = m39 & y5; + let m57 = m39 & t19; + // m48 -> stack + let m36 = m24 ^ m25; + let m31 = m20 & m23; + let m27 = m20 ^ m21; + let m32 = m27 & m31; + let m29 = m28 & m27; + let m37 = m21 ^ m29; + // m39 -> stack + let m42 = m37 ^ m39; + let m52 = m42 & t15; + // t27 -> stack + // t1 <- stack + let m61 = m42 & t1; + let p0 = m52 ^ m61; + let p16 = m57 ^ m61; + // m57 -> stack + // t20 <- stack + let m60 = m37 & t20; + // p16 -> stack + // t17 <- stack + let m51 = m37 & t17; + let m33 = m27 ^ m25; + let m38 = m32 ^ m33; + let m43 = m37 ^ m38; + let m49 = m43 & t16; + let p6 = m49 ^ m60; + let p13 = m49 ^ m51; + let m58 = m43 & t3; + // t9 <- stack + let m50 = m38 & t9; + // t22 <- stack + let m59 = m38 & t22; + // p6 -> stack + let p1 = m58 ^ m59; + let p7 = p0 ^ p1; + let m34 = m21 & m22; + let m35 = m24 & m34; + let m40 = m35 ^ m36; + let m41 = m38 ^ m40; + let m45 = m42 ^ m41; + // t27 <- stack + let m53 = m45 & t27; + let p8 = m50 ^ m53; + let p23 = p7 ^ p8; + // t4 <- stack + let m62 = m45 & t4; + let p14 = m49 ^ m62; + let s6 = p14 ^ p23; + // t10 <- stack + let m54 = m41 & t10; + let p2 = m54 ^ m62; + let p22 = p2 ^ p7; + let s0 = p13 ^ p22; + let p17 = m58 ^ p2; + let p15 = m54 ^ m59; + // t2 <- stack + let m63 = m41 & t2; + // m39 <- stack + let m44 = m39 ^ m40; + // p17 -> stack + // t6 <- stack + let m46 = m44 & t6; + let p5 = m46 ^ m51; + // p23 -> stack + let p18 = m63 ^ p5; + let p24 = p5 ^ p7; + // m48 <- stack + let p12 = m46 ^ m48; + let s3 = p12 ^ p22; + // t13 <- stack + let m55 = m44 & t13; + let p9 = m55 ^ m63; + // p16 <- stack + let s7 = p9 ^ p16; + // t8 <- stack + let m47 = m40 & t8; + let p3 = m47 ^ m50; + let p19 = p2 ^ p3; + let s5 = p19 ^ p24; + let p11 = p0 ^ p3; + let p26 = p9 ^ p11; + // t23 <- stack + let m56 = m40 & t23; + let p4 = m48 ^ m56; + // p6 <- stack + let p20 = p4 ^ p6; + let p29 = p15 ^ p20; + let s1 = p26 ^ p29; + // m57 <- stack + let p10 = m57 ^ p4; + let p27 = p10 ^ p18; + // p23 <- stack + let s4 = p23 ^ p27; + let p25 = p6 ^ p10; + let p28 = p11 ^ p25; + // p17 <- stack + let s2 = p17 ^ p28; + + state[0] = s7; + state[1] = s6; + state[2] = s5; + state[3] = s4; + state[4] = s3; + state[5] = s2; + state[6] = s1; + state[7] = s0; +} + +/// Bitsliced implementation of the AES Sbox based on Boyar, Peralta and Calik. +/// +/// See: +/// +/// Note that the 4 bitwise NOT (^= 0xffffffff) are moved to the key schedule. +fn sub_bytes(state: &mut [u32]) { + debug_assert_eq!(state.len(), 8); + + // Scheduled using https://github.com/Ko-/aes-armcortexm/tree/public/scheduler + // Inline "stack" comments reflect suggested stores and loads (ARM Cortex-M3 and M4) + + let u7 = state[0]; + let u6 = state[1]; + let u5 = state[2]; + let u4 = state[3]; + let u3 = state[4]; + let u2 = state[5]; + let u1 = state[6]; + let u0 = state[7]; + + let y14 = u3 ^ u5; + let y13 = u0 ^ u6; + let y12 = y13 ^ y14; + let t1 = u4 ^ y12; + let y15 = t1 ^ u5; + let t2 = y12 & y15; + let y6 = y15 ^ u7; + let y20 = t1 ^ u1; + // y12 -> stack + let y9 = u0 ^ u3; + // y20 -> stack + let y11 = y20 ^ y9; + // y9 -> stack + let t12 = y9 & y11; + // y6 -> stack + let y7 = u7 ^ y11; + let y8 = u0 ^ u5; + let t0 = u1 ^ u2; + let y10 = y15 ^ t0; + // y15 -> stack + let y17 = y10 ^ y11; + // y14 -> stack + let t13 = y14 & y17; + let t14 = t13 ^ t12; + // y17 -> stack + let y19 = y10 ^ y8; + // y10 -> stack + let t15 = y8 & y10; + let t16 = t15 ^ t12; + let y16 = t0 ^ y11; + // y11 -> stack + let y21 = y13 ^ y16; + // y13 -> stack + let t7 = y13 & y16; + // y16 -> stack + let y18 = u0 ^ y16; + let y1 = t0 ^ u7; + let y4 = y1 ^ u3; + // u7 -> stack + let t5 = y4 & u7; + let t6 = t5 ^ t2; + let t18 = t6 ^ t16; + let t22 = t18 ^ y19; + let y2 = y1 ^ u0; + let t10 = y2 & y7; + let t11 = t10 ^ t7; + let t20 = t11 ^ t16; + let t24 = t20 ^ y18; + let y5 = y1 ^ u6; + let t8 = y5 & y1; + let t9 = t8 ^ t7; + let t19 = t9 ^ t14; + let t23 = t19 ^ y21; + let y3 = y5 ^ y8; + // y6 <- stack + let t3 = y3 & y6; + let t4 = t3 ^ t2; + // y20 <- stack + let t17 = t4 ^ y20; + let t21 = t17 ^ t14; + let t26 = t21 & t23; + let t27 = t24 ^ t26; + let t31 = t22 ^ t26; + let t25 = t21 ^ t22; + // y4 -> stack + let t28 = t25 & t27; + let t29 = t28 ^ t22; + let z14 = t29 & y2; + let z5 = t29 & y7; + let t30 = t23 ^ t24; + let t32 = t31 & t30; + let t33 = t32 ^ t24; + let t35 = t27 ^ t33; + let t36 = t24 & t35; + let t38 = t27 ^ t36; + let t39 = t29 & t38; + let t40 = t25 ^ t39; + let t43 = t29 ^ t40; + // y16 <- stack + let z3 = t43 & y16; + let tc12 = z3 ^ z5; + // tc12 -> stack + // y13 <- stack + let z12 = t43 & y13; + let z13 = t40 & y5; + let z4 = t40 & y1; + let tc6 = z3 ^ z4; + let t34 = t23 ^ t33; + let t37 = t36 ^ t34; + let t41 = t40 ^ t37; + // y10 <- stack + let z8 = t41 & y10; + let z17 = t41 & y8; + let t44 = t33 ^ t37; + // y15 <- stack + let z0 = t44 & y15; + // z17 -> stack + // y12 <- stack + let z9 = t44 & y12; + let z10 = t37 & y3; + let z1 = t37 & y6; + let tc5 = z1 ^ z0; + let tc11 = tc6 ^ tc5; + // y4 <- stack + let z11 = t33 & y4; + let t42 = t29 ^ t33; + let t45 = t42 ^ t41; + // y17 <- stack + let z7 = t45 & y17; + let tc8 = z7 ^ tc6; + // y14 <- stack + let z16 = t45 & y14; + // y11 <- stack + let z6 = t42 & y11; + let tc16 = z6 ^ tc8; + // z14 -> stack + // y9 <- stack + let z15 = t42 & y9; + let tc20 = z15 ^ tc16; + let tc1 = z15 ^ z16; + let tc2 = z10 ^ tc1; + let tc21 = tc2 ^ z11; + let tc3 = z9 ^ tc2; + let s0 = tc3 ^ tc16; + let s3 = tc3 ^ tc11; + let s1 = s3 ^ tc16; + let tc13 = z13 ^ tc1; + // u7 <- stack + let z2 = t33 & u7; + let tc4 = z0 ^ z2; + let tc7 = z12 ^ tc4; + let tc9 = z8 ^ tc7; + let tc10 = tc8 ^ tc9; + // z14 <- stack + let tc17 = z14 ^ tc10; + let s5 = tc21 ^ tc17; + let tc26 = tc17 ^ tc20; + // z17 <- stack + let s2 = tc26 ^ z17; + // tc12 <- stack + let tc14 = tc4 ^ tc12; + let tc18 = tc13 ^ tc14; + let s6 = tc10 ^ tc18; + let s7 = z12 ^ tc18; + let s4 = tc14 ^ s3; + + state[0] = s7; + state[1] = s6; + state[2] = s5; + state[3] = s4; + state[4] = s3; + state[5] = s2; + state[6] = s1; + state[7] = s0; +} + +/// NOT operations that are omitted in S-box +#[inline] +fn sub_bytes_nots(state: &mut [u32]) { + debug_assert_eq!(state.len(), 8); + state[0] ^= 0xffffffff; + state[1] ^= 0xffffffff; + state[5] ^= 0xffffffff; + state[6] ^= 0xffffffff; +} + +/// Computation of the MixColumns transformation in the fixsliced representation, with different +/// rotations used according to the round number mod 4. +/// +/// Based on Käsper-Schwabe, similar to https://github.com/Ko-/aes-armcortexm. +macro_rules! define_mix_columns { + ( + $name:ident, + $name_inv:ident, + $first_rotate:path, + $second_rotate:path + ) => { + #[rustfmt::skip] + fn $name(state: &mut State) { + let (a0, a1, a2, a3, a4, a5, a6, a7) = ( + state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7] + ); + let (b0, b1, b2, b3, b4, b5, b6, b7) = ( + $first_rotate(a0), + $first_rotate(a1), + $first_rotate(a2), + $first_rotate(a3), + $first_rotate(a4), + $first_rotate(a5), + $first_rotate(a6), + $first_rotate(a7), + ); + let (c0, c1, c2, c3, c4, c5, c6, c7) = ( + a0 ^ b0, + a1 ^ b1, + a2 ^ b2, + a3 ^ b3, + a4 ^ b4, + a5 ^ b5, + a6 ^ b6, + a7 ^ b7, + ); + state[0] = b0 ^ c7 ^ $second_rotate(c0); + state[1] = b1 ^ c0 ^ c7 ^ $second_rotate(c1); + state[2] = b2 ^ c1 ^ $second_rotate(c2); + state[3] = b3 ^ c2 ^ c7 ^ $second_rotate(c3); + state[4] = b4 ^ c3 ^ c7 ^ $second_rotate(c4); + state[5] = b5 ^ c4 ^ $second_rotate(c5); + state[6] = b6 ^ c5 ^ $second_rotate(c6); + state[7] = b7 ^ c6 ^ $second_rotate(c7); + } + + #[rustfmt::skip] + fn $name_inv(state: &mut State) { + let (a0, a1, a2, a3, a4, a5, a6, a7) = ( + state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7] + ); + let (b0, b1, b2, b3, b4, b5, b6, b7) = ( + $first_rotate(a0), + $first_rotate(a1), + $first_rotate(a2), + $first_rotate(a3), + $first_rotate(a4), + $first_rotate(a5), + $first_rotate(a6), + $first_rotate(a7), + ); + let (c0, c1, c2, c3, c4, c5, c6, c7) = ( + a0 ^ b0, + a1 ^ b1, + a2 ^ b2, + a3 ^ b3, + a4 ^ b4, + a5 ^ b5, + a6 ^ b6, + a7 ^ b7, + ); + let (d0, d1, d2, d3, d4, d5, d6, d7) = ( + a0 ^ c7, + a1 ^ c0 ^ c7, + a2 ^ c1, + a3 ^ c2 ^ c7, + a4 ^ c3 ^ c7, + a5 ^ c4, + a6 ^ c5, + a7 ^ c6, + ); + let (e0, e1, e2, e3, e4, e5, e6, e7) = ( + c0 ^ d6, + c1 ^ d6 ^ d7, + c2 ^ d0 ^ d7, + c3 ^ d1 ^ d6, + c4 ^ d2 ^ d6 ^ d7, + c5 ^ d3 ^ d7, + c6 ^ d4, + c7 ^ d5, + ); + state[0] = d0 ^ e0 ^ $second_rotate(e0); + state[1] = d1 ^ e1 ^ $second_rotate(e1); + state[2] = d2 ^ e2 ^ $second_rotate(e2); + state[3] = d3 ^ e3 ^ $second_rotate(e3); + state[4] = d4 ^ e4 ^ $second_rotate(e4); + state[5] = d5 ^ e5 ^ $second_rotate(e5); + state[6] = d6 ^ e6 ^ $second_rotate(e6); + state[7] = d7 ^ e7 ^ $second_rotate(e7); + } + } +} + +define_mix_columns!( + mix_columns_0, + inv_mix_columns_0, + rotate_rows_1, + rotate_rows_2 +); + +define_mix_columns!( + mix_columns_1, + inv_mix_columns_1, + rotate_rows_and_columns_1_1, + rotate_rows_and_columns_2_2 +); + +#[cfg(not(aes_compact))] +define_mix_columns!( + mix_columns_2, + inv_mix_columns_2, + rotate_rows_and_columns_1_2, + rotate_rows_2 +); + +#[cfg(not(aes_compact))] +define_mix_columns!( + mix_columns_3, + inv_mix_columns_3, + rotate_rows_and_columns_1_3, + rotate_rows_and_columns_2_2 +); + +#[inline] +fn delta_swap_1(a: &mut u32, shift: u32, mask: u32) { + let t = (*a ^ ((*a) >> shift)) & mask; + *a ^= t ^ (t << shift); +} + +#[inline] +fn delta_swap_2(a: &mut u32, b: &mut u32, shift: u32, mask: u32) { + let t = (*a ^ ((*b) >> shift)) & mask; + *a ^= t; + *b ^= t << shift; +} + +/// Applies ShiftRows once on an AES state (or key). +#[cfg(any(not(aes_compact), feature = "hazmat"))] +#[inline] +fn shift_rows_1(state: &mut [u32]) { + debug_assert_eq!(state.len(), 8); + for x in state.iter_mut() { + delta_swap_1(x, 4, 0x0c0f0300); + delta_swap_1(x, 2, 0x33003300); + } +} + +/// Applies ShiftRows twice on an AES state (or key). +#[inline] +fn shift_rows_2(state: &mut [u32]) { + debug_assert_eq!(state.len(), 8); + for x in state.iter_mut() { + delta_swap_1(x, 4, 0x0f000f00); + } +} + +/// Applies ShiftRows three times on an AES state (or key). +#[inline] +fn shift_rows_3(state: &mut [u32]) { + debug_assert_eq!(state.len(), 8); + for x in state.iter_mut() { + delta_swap_1(x, 4, 0x030f0c00); + delta_swap_1(x, 2, 0x33003300); + } +} + +#[inline(always)] +fn inv_shift_rows_1(state: &mut [u32]) { + shift_rows_3(state); +} + +#[inline(always)] +fn inv_shift_rows_2(state: &mut [u32]) { + shift_rows_2(state); +} + +#[cfg(not(aes_compact))] +#[inline(always)] +fn inv_shift_rows_3(state: &mut [u32]) { + shift_rows_1(state); +} + +/// XOR the columns after the S-box during the key schedule round function. +/// +/// The `idx_xor` parameter refers to the index of the previous round key that is +/// involved in the XOR computation (should be 8 and 16 for AES-128 and AES-256, +/// respectively). +/// +/// The `idx_ror` parameter refers to the rotation value, which varies between the +/// different key schedules. +fn xor_columns(rkeys: &mut [u32], offset: usize, idx_xor: usize, idx_ror: u32) { + for i in 0..8 { + let off_i = offset + i; + let rk = rkeys[off_i - idx_xor] ^ (0x03030303 & ror(rkeys[off_i], idx_ror)); + rkeys[off_i] = + rk ^ (0xfcfcfcfc & (rk << 2)) ^ (0xf0f0f0f0 & (rk << 4)) ^ (0xc0c0c0c0 & (rk << 6)); + } +} + +/// Bitslice two 128-bit input blocks input0, input1 into a 256-bit internal state. +fn bitslice(output: &mut [u32], input0: &[u8], input1: &[u8]) { + debug_assert_eq!(output.len(), 8); + debug_assert_eq!(input0.len(), 16); + debug_assert_eq!(input1.len(), 16); + + // Bitslicing is a bit index manipulation. 256 bits of data means each bit is positioned at an + // 8-bit index. AES data is 2 blocks, each one a 4x4 column-major matrix of bytes, so the + // index is initially ([b]lock, [c]olumn, [r]ow, [p]osition): + // b0 c1 c0 r1 r0 p2 p1 p0 + // + // The desired bitsliced data groups first by bit position, then row, column, block: + // p2 p1 p0 r1 r0 c1 c0 b0 + + // Interleave the columns on input (note the order of input) + // b0 c1 c0 __ __ __ __ __ => c1 c0 b0 __ __ __ __ __ + let mut t0 = u32::from_le_bytes(input0[0x00..0x04].try_into().unwrap()); + let mut t2 = u32::from_le_bytes(input0[0x04..0x08].try_into().unwrap()); + let mut t4 = u32::from_le_bytes(input0[0x08..0x0c].try_into().unwrap()); + let mut t6 = u32::from_le_bytes(input0[0x0c..0x10].try_into().unwrap()); + let mut t1 = u32::from_le_bytes(input1[0x00..0x04].try_into().unwrap()); + let mut t3 = u32::from_le_bytes(input1[0x04..0x08].try_into().unwrap()); + let mut t5 = u32::from_le_bytes(input1[0x08..0x0c].try_into().unwrap()); + let mut t7 = u32::from_le_bytes(input1[0x0c..0x10].try_into().unwrap()); + + // Bit Index Swap 5 <-> 0: + // __ __ b0 __ __ __ __ p0 => __ __ p0 __ __ __ __ b0 + let m0 = 0x55555555; + delta_swap_2(&mut t1, &mut t0, 1, m0); + delta_swap_2(&mut t3, &mut t2, 1, m0); + delta_swap_2(&mut t5, &mut t4, 1, m0); + delta_swap_2(&mut t7, &mut t6, 1, m0); + + // Bit Index Swap 6 <-> 1: + // __ c0 __ __ __ __ p1 __ => __ p1 __ __ __ __ c0 __ + let m1 = 0x33333333; + delta_swap_2(&mut t2, &mut t0, 2, m1); + delta_swap_2(&mut t3, &mut t1, 2, m1); + delta_swap_2(&mut t6, &mut t4, 2, m1); + delta_swap_2(&mut t7, &mut t5, 2, m1); + + // Bit Index Swap 7 <-> 2: + // c1 __ __ __ __ p2 __ __ => p2 __ __ __ __ c1 __ __ + let m2 = 0x0f0f0f0f; + delta_swap_2(&mut t4, &mut t0, 4, m2); + delta_swap_2(&mut t5, &mut t1, 4, m2); + delta_swap_2(&mut t6, &mut t2, 4, m2); + delta_swap_2(&mut t7, &mut t3, 4, m2); + + // Final bitsliced bit index, as desired: + // p2 p1 p0 r1 r0 c1 c0 b0 + output[0] = t0; + output[1] = t1; + output[2] = t2; + output[3] = t3; + output[4] = t4; + output[5] = t5; + output[6] = t6; + output[7] = t7; +} + +/// Un-bitslice a 256-bit internal state into two 128-bit blocks of output. +fn inv_bitslice(input: &[u32]) -> BatchBlocks { + debug_assert_eq!(input.len(), 8); + + // Unbitslicing is a bit index manipulation. 256 bits of data means each bit is positioned at + // an 8-bit index. AES data is 2 blocks, each one a 4x4 column-major matrix of bytes, so the + // desired index for the output is ([b]lock, [c]olumn, [r]ow, [p]osition): + // b0 c1 c0 r1 r0 p2 p1 p0 + // + // The initially bitsliced data groups first by bit position, then row, column, block: + // p2 p1 p0 r1 r0 c1 c0 b0 + + let mut t0 = input[0]; + let mut t1 = input[1]; + let mut t2 = input[2]; + let mut t3 = input[3]; + let mut t4 = input[4]; + let mut t5 = input[5]; + let mut t6 = input[6]; + let mut t7 = input[7]; + + // TODO: these bit index swaps are identical to those in 'packing' + + // Bit Index Swap 5 <-> 0: + // __ __ p0 __ __ __ __ b0 => __ __ b0 __ __ __ __ p0 + let m0 = 0x55555555; + delta_swap_2(&mut t1, &mut t0, 1, m0); + delta_swap_2(&mut t3, &mut t2, 1, m0); + delta_swap_2(&mut t5, &mut t4, 1, m0); + delta_swap_2(&mut t7, &mut t6, 1, m0); + + // Bit Index Swap 6 <-> 1: + // __ p1 __ __ __ __ c0 __ => __ c0 __ __ __ __ p1 __ + let m1 = 0x33333333; + delta_swap_2(&mut t2, &mut t0, 2, m1); + delta_swap_2(&mut t3, &mut t1, 2, m1); + delta_swap_2(&mut t6, &mut t4, 2, m1); + delta_swap_2(&mut t7, &mut t5, 2, m1); + + // Bit Index Swap 7 <-> 2: + // p2 __ __ __ __ c1 __ __ => c1 __ __ __ __ p2 __ __ + let m2 = 0x0f0f0f0f; + delta_swap_2(&mut t4, &mut t0, 4, m2); + delta_swap_2(&mut t5, &mut t1, 4, m2); + delta_swap_2(&mut t6, &mut t2, 4, m2); + delta_swap_2(&mut t7, &mut t3, 4, m2); + + let mut output = BatchBlocks::default(); + // De-interleave the columns on output (note the order of output) + // c1 c0 b0 __ __ __ __ __ => b0 c1 c0 __ __ __ __ __ + output[0][0x00..0x04].copy_from_slice(&t0.to_le_bytes()); + output[0][0x04..0x08].copy_from_slice(&t2.to_le_bytes()); + output[0][0x08..0x0c].copy_from_slice(&t4.to_le_bytes()); + output[0][0x0c..0x10].copy_from_slice(&t6.to_le_bytes()); + output[1][0x00..0x04].copy_from_slice(&t1.to_le_bytes()); + output[1][0x04..0x08].copy_from_slice(&t3.to_le_bytes()); + output[1][0x08..0x0c].copy_from_slice(&t5.to_le_bytes()); + output[1][0x0c..0x10].copy_from_slice(&t7.to_le_bytes()); + + // Final AES bit index, as desired: + // b0 c1 c0 r1 r0 p2 p1 p0 + output +} + +/// Copy 32-bytes within the provided slice to an 8-byte offset +fn memshift32(buffer: &mut [u32], src_offset: usize) { + debug_assert_eq!(src_offset % 8, 0); + + let dst_offset = src_offset + 8; + debug_assert!(dst_offset + 8 <= buffer.len()); + + for i in (0..8).rev() { + buffer[dst_offset + i] = buffer[src_offset + i]; + } +} + +/// XOR the round key to the internal state. The round keys are expected to be +/// pre-computed and to be packed in the fixsliced representation. +#[inline] +fn add_round_key(state: &mut State, rkey: &[u32]) { + debug_assert_eq!(rkey.len(), 8); + for (a, b) in state.iter_mut().zip(rkey) { + *a ^= b; + } +} + +#[inline(always)] +fn add_round_constant_bit(state: &mut [u32], bit: usize) { + state[bit] ^= 0x0000c000; +} + +#[inline(always)] +fn ror(x: u32, y: u32) -> u32 { + x.rotate_right(y) +} + +#[inline(always)] +fn ror_distance(rows: u32, cols: u32) -> u32 { + (rows << 3) + (cols << 1) +} + +#[inline(always)] +fn rotate_rows_1(x: u32) -> u32 { + ror(x, ror_distance(1, 0)) +} + +#[inline(always)] +fn rotate_rows_2(x: u32) -> u32 { + ror(x, ror_distance(2, 0)) +} + +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_1_1(x: u32) -> u32 { + (ror(x, ror_distance(1, 1)) & 0x3f3f3f3f) | + (ror(x, ror_distance(0, 1)) & 0xc0c0c0c0) +} + +#[cfg(not(aes_compact))] +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_1_2(x: u32) -> u32 { + (ror(x, ror_distance(1, 2)) & 0x0f0f0f0f) | + (ror(x, ror_distance(0, 2)) & 0xf0f0f0f0) +} + +#[cfg(not(aes_compact))] +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_1_3(x: u32) -> u32 { + (ror(x, ror_distance(1, 3)) & 0x03030303) | + (ror(x, ror_distance(0, 3)) & 0xfcfcfcfc) +} + +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_2_2(x: u32) -> u32 { + (ror(x, ror_distance(2, 2)) & 0x0f0f0f0f) | + (ror(x, ror_distance(1, 2)) & 0xf0f0f0f0) +} + +/// Low-level "hazmat" AES functions. +/// +/// Note: this isn't actually used in the `Aes128`/`Aes192`/`Aes256` +/// implementations in this crate, but instead provides raw access to +/// the AES round function gated under the `hazmat` crate feature. +#[cfg(feature = "hazmat")] +pub(crate) mod hazmat { + use super::{ + bitslice, inv_bitslice, inv_mix_columns_0, inv_shift_rows_1, inv_sub_bytes, mix_columns_0, + shift_rows_1, sub_bytes, sub_bytes_nots, State, + }; + use crate::{Block, Block8}; + + /// XOR the `src` block into the `dst` block in-place. + fn xor_in_place(dst: &mut Block, src: &Block) { + for (a, b) in dst.iter_mut().zip(src.as_slice()) { + *a ^= *b; + } + } + + /// Perform a bitslice operation, loading a single block. + fn bitslice_block(block: &Block) -> State { + let mut state = State::default(); + bitslice(&mut state, block, block); + state + } + + /// Perform an inverse bitslice operation, extracting a single block. + fn inv_bitslice_block(block: &mut Block, state: &State) { + let out = inv_bitslice(state); + block.copy_from_slice(&out[0]); + } + + /// AES cipher (encrypt) round function. + #[inline] + pub(crate) fn cipher_round(block: &mut Block, round_key: &Block) { + let mut state = bitslice_block(block); + sub_bytes(&mut state); + sub_bytes_nots(&mut state); + shift_rows_1(&mut state); + mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + xor_in_place(block, round_key); + } + + /// AES cipher (encrypt) round function: parallel version. + #[inline] + pub(crate) fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + for (chunk, keys) in blocks.chunks_exact_mut(2).zip(round_keys.chunks_exact(2)) { + let mut state = State::default(); + bitslice(&mut state, &chunk[0], &chunk[1]); + sub_bytes(&mut state); + sub_bytes_nots(&mut state); + shift_rows_1(&mut state); + mix_columns_0(&mut state); + let res = inv_bitslice(&state); + + for i in 0..2 { + chunk[i] = res[i]; + xor_in_place(&mut chunk[i], &keys[i]); + } + } + } + + /// AES cipher (encrypt) round function. + #[inline] + pub(crate) fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + let mut state = bitslice_block(block); + sub_bytes_nots(&mut state); + inv_sub_bytes(&mut state); + inv_shift_rows_1(&mut state); + inv_mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + xor_in_place(block, round_key); + } + + /// AES cipher (encrypt) round function: parallel version. + #[inline] + pub(crate) fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + for (chunk, keys) in blocks.chunks_exact_mut(2).zip(round_keys.chunks_exact(2)) { + let mut state = State::default(); + bitslice(&mut state, &chunk[0], &chunk[1]); + sub_bytes_nots(&mut state); + inv_sub_bytes(&mut state); + inv_shift_rows_1(&mut state); + inv_mix_columns_0(&mut state); + let res = inv_bitslice(&state); + + for i in 0..2 { + chunk[i] = res[i]; + xor_in_place(&mut chunk[i], &keys[i]); + } + } + } + + /// AES mix columns function. + #[inline] + pub(crate) fn mix_columns(block: &mut Block) { + let mut state = bitslice_block(block); + mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + } + + /// AES inverse mix columns function. + #[inline] + pub(crate) fn inv_mix_columns(block: &mut Block) { + let mut state = bitslice_block(block); + inv_mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + } +} diff --git a/vendor/aes/src/soft/fixslice64.rs b/vendor/aes/src/soft/fixslice64.rs new file mode 100644 index 00000000..09dbcbe9 --- /dev/null +++ b/vendor/aes/src/soft/fixslice64.rs @@ -0,0 +1,1534 @@ +//! Fixsliced implementations of AES-128, AES-192 and AES-256 (64-bit) +//! adapted from the C implementation. +//! +//! All implementations are fully bitsliced and do not rely on any +//! Look-Up Table (LUT). +//! +//! See the paper at for more details. +//! +//! # Author (original C code) +//! +//! Alexandre Adomnicai, Nanyang Technological University, Singapore +//! +//! +//! Originally licensed MIT. Relicensed as Apache 2.0+MIT with permission. + +#![allow(clippy::unreadable_literal)] + +use crate::Block; +use cipher::{consts::U4, generic_array::GenericArray}; + +/// AES block batch size for this implementation +pub(crate) type FixsliceBlocks = U4; + +pub(crate) type BatchBlocks = GenericArray; + +/// AES-128 round keys +pub(crate) type FixsliceKeys128 = [u64; 88]; + +/// AES-192 round keys +pub(crate) type FixsliceKeys192 = [u64; 104]; + +/// AES-256 round keys +pub(crate) type FixsliceKeys256 = [u64; 120]; + +/// 512-bit internal state +pub(crate) type State = [u64; 8]; + +/// Fully bitsliced AES-128 key schedule to match the fully-fixsliced representation. +pub(crate) fn aes128_key_schedule(key: &[u8; 16]) -> FixsliceKeys128 { + let mut rkeys = [0u64; 88]; + + bitslice(&mut rkeys[..8], key, key, key, key); + + let mut rk_off = 0; + for rcon in 0..10 { + memshift32(&mut rkeys, rk_off); + rk_off += 8; + + sub_bytes(&mut rkeys[rk_off..(rk_off + 8)]); + sub_bytes_nots(&mut rkeys[rk_off..(rk_off + 8)]); + + if rcon < 8 { + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon); + } else { + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 8); + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 7); + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 5); + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon - 4); + } + + xor_columns(&mut rkeys, rk_off, 8, ror_distance(1, 3)); + } + + // Adjust to match fixslicing format + #[cfg(aes_compact)] + { + for i in (8..88).step_by(16) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + } + } + #[cfg(not(aes_compact))] + { + for i in (8..72).step_by(32) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + inv_shift_rows_2(&mut rkeys[(i + 8)..(i + 16)]); + inv_shift_rows_3(&mut rkeys[(i + 16)..(i + 24)]); + } + inv_shift_rows_1(&mut rkeys[72..80]); + } + + // Account for NOTs removed from sub_bytes + for i in 1..11 { + sub_bytes_nots(&mut rkeys[(i * 8)..(i * 8 + 8)]); + } + + rkeys +} + +/// Fully bitsliced AES-192 key schedule to match the fully-fixsliced representation. +pub(crate) fn aes192_key_schedule(key: &[u8; 24]) -> FixsliceKeys192 { + let mut rkeys = [0u64; 104]; + let mut tmp = [0u64; 8]; + + bitslice( + &mut rkeys[..8], + &key[..16], + &key[..16], + &key[..16], + &key[..16], + ); + bitslice(&mut tmp, &key[8..], &key[8..], &key[8..], &key[8..]); + + let mut rcon = 0; + let mut rk_off = 8; + + loop { + for i in 0..8 { + rkeys[rk_off + i] = (0x00ff00ff00ff00ff & (tmp[i] >> 8)) + | (0xff00ff00ff00ff00 & (rkeys[(rk_off - 8) + i] << 8)); + } + + sub_bytes(&mut tmp); + sub_bytes_nots(&mut tmp); + + add_round_constant_bit(&mut tmp, rcon); + rcon += 1; + + for i in 0..8 { + let mut ti = rkeys[rk_off + i]; + ti ^= 0x0f000f000f000f00 & ror(tmp[i], ror_distance(1, 1)); + ti ^= 0xf000f000f000f000 & (ti << 4); + tmp[i] = ti; + } + rkeys[rk_off..(rk_off + 8)].copy_from_slice(&tmp); + rk_off += 8; + + for i in 0..8 { + let ui = tmp[i]; + let mut ti = (0x00ff00ff00ff00ff & (rkeys[(rk_off - 16) + i] >> 8)) + | (0xff00ff00ff00ff00 & (ui << 8)); + ti ^= 0x000f000f000f000f & (ui >> 12); + tmp[i] = ti + ^ (0xfff0fff0fff0fff0 & (ti << 4)) + ^ (0xff00ff00ff00ff00 & (ti << 8)) + ^ (0xf000f000f000f000 & (ti << 12)); + } + rkeys[rk_off..(rk_off + 8)].copy_from_slice(&tmp); + rk_off += 8; + + sub_bytes(&mut tmp); + sub_bytes_nots(&mut tmp); + + add_round_constant_bit(&mut tmp, rcon); + rcon += 1; + + for i in 0..8 { + let mut ti = (0x00ff00ff00ff00ff & (rkeys[(rk_off - 16) + i] >> 8)) + | (0xff00ff00ff00ff00 & (rkeys[(rk_off - 8) + i] << 8)); + ti ^= 0x000f000f000f000f & ror(tmp[i], ror_distance(1, 3)); + rkeys[rk_off + i] = ti + ^ (0xfff0fff0fff0fff0 & (ti << 4)) + ^ (0xff00ff00ff00ff00 & (ti << 8)) + ^ (0xf000f000f000f000 & (ti << 12)); + } + rk_off += 8; + + if rcon >= 8 { + break; + } + + for i in 0..8 { + let ui = rkeys[(rk_off - 8) + i]; + let mut ti = rkeys[(rk_off - 16) + i]; + ti ^= 0x0f000f000f000f00 & (ui >> 4); + ti ^= 0xf000f000f000f000 & (ti << 4); + tmp[i] = ti; + } + } + + // Adjust to match fixslicing format + #[cfg(aes_compact)] + { + for i in (8..104).step_by(16) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + } + } + #[cfg(not(aes_compact))] + { + for i in (0..96).step_by(32) { + inv_shift_rows_1(&mut rkeys[(i + 8)..(i + 16)]); + inv_shift_rows_2(&mut rkeys[(i + 16)..(i + 24)]); + inv_shift_rows_3(&mut rkeys[(i + 24)..(i + 32)]); + } + } + + // Account for NOTs removed from sub_bytes + for i in 1..13 { + sub_bytes_nots(&mut rkeys[(i * 8)..(i * 8 + 8)]); + } + + rkeys +} + +/// Fully bitsliced AES-256 key schedule to match the fully-fixsliced representation. +pub(crate) fn aes256_key_schedule(key: &[u8; 32]) -> FixsliceKeys256 { + let mut rkeys = [0u64; 120]; + + bitslice( + &mut rkeys[..8], + &key[..16], + &key[..16], + &key[..16], + &key[..16], + ); + bitslice( + &mut rkeys[8..16], + &key[16..], + &key[16..], + &key[16..], + &key[16..], + ); + + let mut rk_off = 8; + + let mut rcon = 0; + loop { + memshift32(&mut rkeys, rk_off); + rk_off += 8; + + sub_bytes(&mut rkeys[rk_off..(rk_off + 8)]); + sub_bytes_nots(&mut rkeys[rk_off..(rk_off + 8)]); + + add_round_constant_bit(&mut rkeys[rk_off..(rk_off + 8)], rcon); + xor_columns(&mut rkeys, rk_off, 16, ror_distance(1, 3)); + rcon += 1; + + if rcon == 7 { + break; + } + + memshift32(&mut rkeys, rk_off); + rk_off += 8; + + sub_bytes(&mut rkeys[rk_off..(rk_off + 8)]); + sub_bytes_nots(&mut rkeys[rk_off..(rk_off + 8)]); + + xor_columns(&mut rkeys, rk_off, 16, ror_distance(0, 3)); + } + + // Adjust to match fixslicing format + #[cfg(aes_compact)] + { + for i in (8..120).step_by(16) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + } + } + #[cfg(not(aes_compact))] + { + for i in (8..104).step_by(32) { + inv_shift_rows_1(&mut rkeys[i..(i + 8)]); + inv_shift_rows_2(&mut rkeys[(i + 8)..(i + 16)]); + inv_shift_rows_3(&mut rkeys[(i + 16)..(i + 24)]); + } + inv_shift_rows_1(&mut rkeys[104..112]); + } + + // Account for NOTs removed from sub_bytes + for i in 1..15 { + sub_bytes_nots(&mut rkeys[(i * 8)..(i * 8 + 8)]); + } + + rkeys +} + +/// Fully-fixsliced AES-128 decryption (the InvShiftRows is completely omitted). +/// +/// Decrypts four blocks in-place and in parallel. +pub(crate) fn aes128_decrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); + + add_round_key(&mut state, &rkeys[80..]); + inv_sub_bytes(&mut state); + + #[cfg(not(aes_compact))] + { + inv_shift_rows_2(&mut state); + } + + let mut rk_off = 72; + loop { + #[cfg(aes_compact)] + { + inv_shift_rows_2(&mut state); + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_1(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + if rk_off == 0 { + break; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_0(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + #[cfg(not(aes_compact))] + { + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_3(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_2(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + } + + add_round_key(&mut state, &rkeys[..8]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-128 encryption (the ShiftRows is completely omitted). +/// +/// Encrypts four blocks in-place and in parallel. +pub(crate) fn aes128_encrypt(rkeys: &FixsliceKeys128, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); + + add_round_key(&mut state, &rkeys[..8]); + + let mut rk_off = 8; + loop { + sub_bytes(&mut state); + mix_columns_1(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + #[cfg(aes_compact)] + { + shift_rows_2(&mut state); + } + + if rk_off == 80 { + break; + } + + #[cfg(not(aes_compact))] + { + sub_bytes(&mut state); + mix_columns_2(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + sub_bytes(&mut state); + mix_columns_3(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + sub_bytes(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + #[cfg(not(aes_compact))] + { + shift_rows_2(&mut state); + } + + sub_bytes(&mut state); + add_round_key(&mut state, &rkeys[80..]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-192 decryption (the InvShiftRows is completely omitted). +/// +/// Decrypts four blocks in-place and in parallel. +pub(crate) fn aes192_decrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); + + add_round_key(&mut state, &rkeys[96..]); + inv_sub_bytes(&mut state); + + let mut rk_off = 88; + loop { + #[cfg(aes_compact)] + { + inv_shift_rows_2(&mut state); + } + #[cfg(not(aes_compact))] + { + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_3(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_2(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_1(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + if rk_off == 0 { + break; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_0(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + + add_round_key(&mut state, &rkeys[..8]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-192 encryption (the ShiftRows is completely omitted). +/// +/// Encrypts four blocks in-place and in parallel. +pub(crate) fn aes192_encrypt(rkeys: &FixsliceKeys192, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); + + add_round_key(&mut state, &rkeys[..8]); + + let mut rk_off = 8; + loop { + sub_bytes(&mut state); + mix_columns_1(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + #[cfg(aes_compact)] + { + shift_rows_2(&mut state); + } + #[cfg(not(aes_compact))] + { + sub_bytes(&mut state); + mix_columns_2(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + sub_bytes(&mut state); + mix_columns_3(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + if rk_off == 96 { + break; + } + + sub_bytes(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + sub_bytes(&mut state); + add_round_key(&mut state, &rkeys[96..]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-256 decryption (the InvShiftRows is completely omitted). +/// +/// Decrypts four blocks in-place and in parallel. +pub(crate) fn aes256_decrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); + + add_round_key(&mut state, &rkeys[112..]); + inv_sub_bytes(&mut state); + + #[cfg(not(aes_compact))] + { + inv_shift_rows_2(&mut state); + } + + let mut rk_off = 104; + loop { + #[cfg(aes_compact)] + { + inv_shift_rows_2(&mut state); + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_1(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + if rk_off == 0 { + break; + } + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_0(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + #[cfg(not(aes_compact))] + { + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_3(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + inv_mix_columns_2(&mut state); + inv_sub_bytes(&mut state); + rk_off -= 8; + } + } + + add_round_key(&mut state, &rkeys[..8]); + + inv_bitslice(&state) +} + +/// Fully-fixsliced AES-256 encryption (the ShiftRows is completely omitted). +/// +/// Encrypts four blocks in-place and in parallel. +pub(crate) fn aes256_encrypt(rkeys: &FixsliceKeys256, blocks: &BatchBlocks) -> BatchBlocks { + let mut state = State::default(); + + bitslice(&mut state, &blocks[0], &blocks[1], &blocks[2], &blocks[3]); + + add_round_key(&mut state, &rkeys[..8]); + + let mut rk_off = 8; + loop { + sub_bytes(&mut state); + mix_columns_1(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + #[cfg(aes_compact)] + { + shift_rows_2(&mut state); + } + + if rk_off == 112 { + break; + } + + #[cfg(not(aes_compact))] + { + sub_bytes(&mut state); + mix_columns_2(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + + sub_bytes(&mut state); + mix_columns_3(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + sub_bytes(&mut state); + mix_columns_0(&mut state); + add_round_key(&mut state, &rkeys[rk_off..(rk_off + 8)]); + rk_off += 8; + } + + #[cfg(not(aes_compact))] + { + shift_rows_2(&mut state); + } + + sub_bytes(&mut state); + add_round_key(&mut state, &rkeys[112..]); + + inv_bitslice(&state) +} + +/// Note that the 4 bitwise NOT (^= 0xffffffffffffffff) are accounted for here so that it is a true +/// inverse of 'sub_bytes'. +fn inv_sub_bytes(state: &mut [u64]) { + debug_assert_eq!(state.len(), 8); + + // Scheduled using https://github.com/Ko-/aes-armcortexm/tree/public/scheduler + // Inline "stack" comments reflect suggested stores and loads (ARM Cortex-M3 and M4) + + let u7 = state[0]; + let u6 = state[1]; + let u5 = state[2]; + let u4 = state[3]; + let u3 = state[4]; + let u2 = state[5]; + let u1 = state[6]; + let u0 = state[7]; + + let t23 = u0 ^ u3; + let t8 = u1 ^ t23; + let m2 = t23 & t8; + let t4 = u4 ^ t8; + let t22 = u1 ^ u3; + let t2 = u0 ^ u1; + let t1 = u3 ^ u4; + // t23 -> stack + let t9 = u7 ^ t1; + // t8 -> stack + let m7 = t22 & t9; + // t9 -> stack + let t24 = u4 ^ u7; + // m7 -> stack + let t10 = t2 ^ t24; + // u4 -> stack + let m14 = t2 & t10; + let r5 = u6 ^ u7; + // m2 -> stack + let t3 = t1 ^ r5; + // t2 -> stack + let t13 = t2 ^ r5; + let t19 = t22 ^ r5; + // t3 -> stack + let t17 = u2 ^ t19; + // t4 -> stack + let t25 = u2 ^ t1; + let r13 = u1 ^ u6; + // t25 -> stack + let t20 = t24 ^ r13; + // t17 -> stack + let m9 = t20 & t17; + // t20 -> stack + let r17 = u2 ^ u5; + // t22 -> stack + let t6 = t22 ^ r17; + // t13 -> stack + let m1 = t13 & t6; + let y5 = u0 ^ r17; + let m4 = t19 & y5; + let m5 = m4 ^ m1; + let m17 = m5 ^ t24; + let r18 = u5 ^ u6; + let t27 = t1 ^ r18; + let t15 = t10 ^ t27; + // t6 -> stack + let m11 = t1 & t15; + let m15 = m14 ^ m11; + let m21 = m17 ^ m15; + // t1 -> stack + // t4 <- stack + let m12 = t4 & t27; + let m13 = m12 ^ m11; + let t14 = t10 ^ r18; + let m3 = t14 ^ m1; + // m2 <- stack + let m16 = m3 ^ m2; + let m20 = m16 ^ m13; + // u4 <- stack + let r19 = u2 ^ u4; + let t16 = r13 ^ r19; + // t3 <- stack + let t26 = t3 ^ t16; + let m6 = t3 & t16; + let m8 = t26 ^ m6; + // t10 -> stack + // m7 <- stack + let m18 = m8 ^ m7; + let m22 = m18 ^ m13; + let m25 = m22 & m20; + let m26 = m21 ^ m25; + let m10 = m9 ^ m6; + let m19 = m10 ^ m15; + // t25 <- stack + let m23 = m19 ^ t25; + let m28 = m23 ^ m25; + let m24 = m22 ^ m23; + let m30 = m26 & m24; + let m39 = m23 ^ m30; + let m48 = m39 & y5; + let m57 = m39 & t19; + // m48 -> stack + let m36 = m24 ^ m25; + let m31 = m20 & m23; + let m27 = m20 ^ m21; + let m32 = m27 & m31; + let m29 = m28 & m27; + let m37 = m21 ^ m29; + // m39 -> stack + let m42 = m37 ^ m39; + let m52 = m42 & t15; + // t27 -> stack + // t1 <- stack + let m61 = m42 & t1; + let p0 = m52 ^ m61; + let p16 = m57 ^ m61; + // m57 -> stack + // t20 <- stack + let m60 = m37 & t20; + // p16 -> stack + // t17 <- stack + let m51 = m37 & t17; + let m33 = m27 ^ m25; + let m38 = m32 ^ m33; + let m43 = m37 ^ m38; + let m49 = m43 & t16; + let p6 = m49 ^ m60; + let p13 = m49 ^ m51; + let m58 = m43 & t3; + // t9 <- stack + let m50 = m38 & t9; + // t22 <- stack + let m59 = m38 & t22; + // p6 -> stack + let p1 = m58 ^ m59; + let p7 = p0 ^ p1; + let m34 = m21 & m22; + let m35 = m24 & m34; + let m40 = m35 ^ m36; + let m41 = m38 ^ m40; + let m45 = m42 ^ m41; + // t27 <- stack + let m53 = m45 & t27; + let p8 = m50 ^ m53; + let p23 = p7 ^ p8; + // t4 <- stack + let m62 = m45 & t4; + let p14 = m49 ^ m62; + let s6 = p14 ^ p23; + // t10 <- stack + let m54 = m41 & t10; + let p2 = m54 ^ m62; + let p22 = p2 ^ p7; + let s0 = p13 ^ p22; + let p17 = m58 ^ p2; + let p15 = m54 ^ m59; + // t2 <- stack + let m63 = m41 & t2; + // m39 <- stack + let m44 = m39 ^ m40; + // p17 -> stack + // t6 <- stack + let m46 = m44 & t6; + let p5 = m46 ^ m51; + // p23 -> stack + let p18 = m63 ^ p5; + let p24 = p5 ^ p7; + // m48 <- stack + let p12 = m46 ^ m48; + let s3 = p12 ^ p22; + // t13 <- stack + let m55 = m44 & t13; + let p9 = m55 ^ m63; + // p16 <- stack + let s7 = p9 ^ p16; + // t8 <- stack + let m47 = m40 & t8; + let p3 = m47 ^ m50; + let p19 = p2 ^ p3; + let s5 = p19 ^ p24; + let p11 = p0 ^ p3; + let p26 = p9 ^ p11; + // t23 <- stack + let m56 = m40 & t23; + let p4 = m48 ^ m56; + // p6 <- stack + let p20 = p4 ^ p6; + let p29 = p15 ^ p20; + let s1 = p26 ^ p29; + // m57 <- stack + let p10 = m57 ^ p4; + let p27 = p10 ^ p18; + // p23 <- stack + let s4 = p23 ^ p27; + let p25 = p6 ^ p10; + let p28 = p11 ^ p25; + // p17 <- stack + let s2 = p17 ^ p28; + + state[0] = s7; + state[1] = s6; + state[2] = s5; + state[3] = s4; + state[4] = s3; + state[5] = s2; + state[6] = s1; + state[7] = s0; +} + +/// Bitsliced implementation of the AES Sbox based on Boyar, Peralta and Calik. +/// +/// See: +/// +/// Note that the 4 bitwise NOT (^= 0xffffffffffffffff) are moved to the key schedule. +fn sub_bytes(state: &mut [u64]) { + debug_assert_eq!(state.len(), 8); + + // Scheduled using https://github.com/Ko-/aes-armcortexm/tree/public/scheduler + // Inline "stack" comments reflect suggested stores and loads (ARM Cortex-M3 and M4) + + let u7 = state[0]; + let u6 = state[1]; + let u5 = state[2]; + let u4 = state[3]; + let u3 = state[4]; + let u2 = state[5]; + let u1 = state[6]; + let u0 = state[7]; + + let y14 = u3 ^ u5; + let y13 = u0 ^ u6; + let y12 = y13 ^ y14; + let t1 = u4 ^ y12; + let y15 = t1 ^ u5; + let t2 = y12 & y15; + let y6 = y15 ^ u7; + let y20 = t1 ^ u1; + // y12 -> stack + let y9 = u0 ^ u3; + // y20 -> stack + let y11 = y20 ^ y9; + // y9 -> stack + let t12 = y9 & y11; + // y6 -> stack + let y7 = u7 ^ y11; + let y8 = u0 ^ u5; + let t0 = u1 ^ u2; + let y10 = y15 ^ t0; + // y15 -> stack + let y17 = y10 ^ y11; + // y14 -> stack + let t13 = y14 & y17; + let t14 = t13 ^ t12; + // y17 -> stack + let y19 = y10 ^ y8; + // y10 -> stack + let t15 = y8 & y10; + let t16 = t15 ^ t12; + let y16 = t0 ^ y11; + // y11 -> stack + let y21 = y13 ^ y16; + // y13 -> stack + let t7 = y13 & y16; + // y16 -> stack + let y18 = u0 ^ y16; + let y1 = t0 ^ u7; + let y4 = y1 ^ u3; + // u7 -> stack + let t5 = y4 & u7; + let t6 = t5 ^ t2; + let t18 = t6 ^ t16; + let t22 = t18 ^ y19; + let y2 = y1 ^ u0; + let t10 = y2 & y7; + let t11 = t10 ^ t7; + let t20 = t11 ^ t16; + let t24 = t20 ^ y18; + let y5 = y1 ^ u6; + let t8 = y5 & y1; + let t9 = t8 ^ t7; + let t19 = t9 ^ t14; + let t23 = t19 ^ y21; + let y3 = y5 ^ y8; + // y6 <- stack + let t3 = y3 & y6; + let t4 = t3 ^ t2; + // y20 <- stack + let t17 = t4 ^ y20; + let t21 = t17 ^ t14; + let t26 = t21 & t23; + let t27 = t24 ^ t26; + let t31 = t22 ^ t26; + let t25 = t21 ^ t22; + // y4 -> stack + let t28 = t25 & t27; + let t29 = t28 ^ t22; + let z14 = t29 & y2; + let z5 = t29 & y7; + let t30 = t23 ^ t24; + let t32 = t31 & t30; + let t33 = t32 ^ t24; + let t35 = t27 ^ t33; + let t36 = t24 & t35; + let t38 = t27 ^ t36; + let t39 = t29 & t38; + let t40 = t25 ^ t39; + let t43 = t29 ^ t40; + // y16 <- stack + let z3 = t43 & y16; + let tc12 = z3 ^ z5; + // tc12 -> stack + // y13 <- stack + let z12 = t43 & y13; + let z13 = t40 & y5; + let z4 = t40 & y1; + let tc6 = z3 ^ z4; + let t34 = t23 ^ t33; + let t37 = t36 ^ t34; + let t41 = t40 ^ t37; + // y10 <- stack + let z8 = t41 & y10; + let z17 = t41 & y8; + let t44 = t33 ^ t37; + // y15 <- stack + let z0 = t44 & y15; + // z17 -> stack + // y12 <- stack + let z9 = t44 & y12; + let z10 = t37 & y3; + let z1 = t37 & y6; + let tc5 = z1 ^ z0; + let tc11 = tc6 ^ tc5; + // y4 <- stack + let z11 = t33 & y4; + let t42 = t29 ^ t33; + let t45 = t42 ^ t41; + // y17 <- stack + let z7 = t45 & y17; + let tc8 = z7 ^ tc6; + // y14 <- stack + let z16 = t45 & y14; + // y11 <- stack + let z6 = t42 & y11; + let tc16 = z6 ^ tc8; + // z14 -> stack + // y9 <- stack + let z15 = t42 & y9; + let tc20 = z15 ^ tc16; + let tc1 = z15 ^ z16; + let tc2 = z10 ^ tc1; + let tc21 = tc2 ^ z11; + let tc3 = z9 ^ tc2; + let s0 = tc3 ^ tc16; + let s3 = tc3 ^ tc11; + let s1 = s3 ^ tc16; + let tc13 = z13 ^ tc1; + // u7 <- stack + let z2 = t33 & u7; + let tc4 = z0 ^ z2; + let tc7 = z12 ^ tc4; + let tc9 = z8 ^ tc7; + let tc10 = tc8 ^ tc9; + // z14 <- stack + let tc17 = z14 ^ tc10; + let s5 = tc21 ^ tc17; + let tc26 = tc17 ^ tc20; + // z17 <- stack + let s2 = tc26 ^ z17; + // tc12 <- stack + let tc14 = tc4 ^ tc12; + let tc18 = tc13 ^ tc14; + let s6 = tc10 ^ tc18; + let s7 = z12 ^ tc18; + let s4 = tc14 ^ s3; + + state[0] = s7; + state[1] = s6; + state[2] = s5; + state[3] = s4; + state[4] = s3; + state[5] = s2; + state[6] = s1; + state[7] = s0; +} + +/// NOT operations that are omitted in S-box +#[inline] +fn sub_bytes_nots(state: &mut [u64]) { + debug_assert_eq!(state.len(), 8); + state[0] ^= 0xffffffffffffffff; + state[1] ^= 0xffffffffffffffff; + state[5] ^= 0xffffffffffffffff; + state[6] ^= 0xffffffffffffffff; +} + +/// Computation of the MixColumns transformation in the fixsliced representation, with different +/// rotations used according to the round number mod 4. +/// +/// Based on Käsper-Schwabe, similar to https://github.com/Ko-/aes-armcortexm. +macro_rules! define_mix_columns { + ( + $name:ident, + $name_inv:ident, + $first_rotate:path, + $second_rotate:path + ) => { + #[rustfmt::skip] + fn $name(state: &mut State) { + let (a0, a1, a2, a3, a4, a5, a6, a7) = ( + state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7] + ); + let (b0, b1, b2, b3, b4, b5, b6, b7) = ( + $first_rotate(a0), + $first_rotate(a1), + $first_rotate(a2), + $first_rotate(a3), + $first_rotate(a4), + $first_rotate(a5), + $first_rotate(a6), + $first_rotate(a7), + ); + let (c0, c1, c2, c3, c4, c5, c6, c7) = ( + a0 ^ b0, + a1 ^ b1, + a2 ^ b2, + a3 ^ b3, + a4 ^ b4, + a5 ^ b5, + a6 ^ b6, + a7 ^ b7, + ); + state[0] = b0 ^ c7 ^ $second_rotate(c0); + state[1] = b1 ^ c0 ^ c7 ^ $second_rotate(c1); + state[2] = b2 ^ c1 ^ $second_rotate(c2); + state[3] = b3 ^ c2 ^ c7 ^ $second_rotate(c3); + state[4] = b4 ^ c3 ^ c7 ^ $second_rotate(c4); + state[5] = b5 ^ c4 ^ $second_rotate(c5); + state[6] = b6 ^ c5 ^ $second_rotate(c6); + state[7] = b7 ^ c6 ^ $second_rotate(c7); + } + + #[rustfmt::skip] + fn $name_inv(state: &mut State) { + let (a0, a1, a2, a3, a4, a5, a6, a7) = ( + state[0], state[1], state[2], state[3], state[4], state[5], state[6], state[7] + ); + let (b0, b1, b2, b3, b4, b5, b6, b7) = ( + $first_rotate(a0), + $first_rotate(a1), + $first_rotate(a2), + $first_rotate(a3), + $first_rotate(a4), + $first_rotate(a5), + $first_rotate(a6), + $first_rotate(a7), + ); + let (c0, c1, c2, c3, c4, c5, c6, c7) = ( + a0 ^ b0, + a1 ^ b1, + a2 ^ b2, + a3 ^ b3, + a4 ^ b4, + a5 ^ b5, + a6 ^ b6, + a7 ^ b7, + ); + let (d0, d1, d2, d3, d4, d5, d6, d7) = ( + a0 ^ c7, + a1 ^ c0 ^ c7, + a2 ^ c1, + a3 ^ c2 ^ c7, + a4 ^ c3 ^ c7, + a5 ^ c4, + a6 ^ c5, + a7 ^ c6, + ); + let (e0, e1, e2, e3, e4, e5, e6, e7) = ( + c0 ^ d6, + c1 ^ d6 ^ d7, + c2 ^ d0 ^ d7, + c3 ^ d1 ^ d6, + c4 ^ d2 ^ d6 ^ d7, + c5 ^ d3 ^ d7, + c6 ^ d4, + c7 ^ d5, + ); + state[0] = d0 ^ e0 ^ $second_rotate(e0); + state[1] = d1 ^ e1 ^ $second_rotate(e1); + state[2] = d2 ^ e2 ^ $second_rotate(e2); + state[3] = d3 ^ e3 ^ $second_rotate(e3); + state[4] = d4 ^ e4 ^ $second_rotate(e4); + state[5] = d5 ^ e5 ^ $second_rotate(e5); + state[6] = d6 ^ e6 ^ $second_rotate(e6); + state[7] = d7 ^ e7 ^ $second_rotate(e7); + } + } +} + +define_mix_columns!( + mix_columns_0, + inv_mix_columns_0, + rotate_rows_1, + rotate_rows_2 +); + +define_mix_columns!( + mix_columns_1, + inv_mix_columns_1, + rotate_rows_and_columns_1_1, + rotate_rows_and_columns_2_2 +); + +#[cfg(not(aes_compact))] +define_mix_columns!( + mix_columns_2, + inv_mix_columns_2, + rotate_rows_and_columns_1_2, + rotate_rows_2 +); + +#[cfg(not(aes_compact))] +define_mix_columns!( + mix_columns_3, + inv_mix_columns_3, + rotate_rows_and_columns_1_3, + rotate_rows_and_columns_2_2 +); + +#[inline] +fn delta_swap_1(a: &mut u64, shift: u32, mask: u64) { + let t = (*a ^ ((*a) >> shift)) & mask; + *a ^= t ^ (t << shift); +} + +#[inline] +fn delta_swap_2(a: &mut u64, b: &mut u64, shift: u32, mask: u64) { + let t = (*a ^ ((*b) >> shift)) & mask; + *a ^= t; + *b ^= t << shift; +} + +/// Applies ShiftRows once on an AES state (or key). +#[cfg(any(not(aes_compact), feature = "hazmat"))] +#[inline] +fn shift_rows_1(state: &mut [u64]) { + debug_assert_eq!(state.len(), 8); + for x in state.iter_mut() { + delta_swap_1(x, 8, 0x00f000ff000f0000); + delta_swap_1(x, 4, 0x0f0f00000f0f0000); + } +} + +/// Applies ShiftRows twice on an AES state (or key). +#[inline] +fn shift_rows_2(state: &mut [u64]) { + debug_assert_eq!(state.len(), 8); + for x in state.iter_mut() { + delta_swap_1(x, 8, 0x00ff000000ff0000); + } +} + +/// Applies ShiftRows three times on an AES state (or key). +#[inline] +fn shift_rows_3(state: &mut [u64]) { + debug_assert_eq!(state.len(), 8); + for x in state.iter_mut() { + delta_swap_1(x, 8, 0x000f00ff00f00000); + delta_swap_1(x, 4, 0x0f0f00000f0f0000); + } +} + +#[inline(always)] +fn inv_shift_rows_1(state: &mut [u64]) { + shift_rows_3(state); +} + +#[inline(always)] +fn inv_shift_rows_2(state: &mut [u64]) { + shift_rows_2(state); +} + +#[cfg(not(aes_compact))] +#[inline(always)] +fn inv_shift_rows_3(state: &mut [u64]) { + shift_rows_1(state); +} + +/// XOR the columns after the S-box during the key schedule round function. +/// +/// The `idx_xor` parameter refers to the index of the previous round key that is +/// involved in the XOR computation (should be 8 and 16 for AES-128 and AES-256, +/// respectively). +/// +/// The `idx_ror` parameter refers to the rotation value, which varies between the +/// different key schedules. +fn xor_columns(rkeys: &mut [u64], offset: usize, idx_xor: usize, idx_ror: u32) { + for i in 0..8 { + let off_i = offset + i; + let rk = rkeys[off_i - idx_xor] ^ (0x000f000f000f000f & ror(rkeys[off_i], idx_ror)); + rkeys[off_i] = rk + ^ (0xfff0fff0fff0fff0 & (rk << 4)) + ^ (0xff00ff00ff00ff00 & (rk << 8)) + ^ (0xf000f000f000f000 & (rk << 12)); + } +} + +/// Bitslice four 128-bit input blocks input0, input1, input2, input3 into a 512-bit internal state. +fn bitslice(output: &mut [u64], input0: &[u8], input1: &[u8], input2: &[u8], input3: &[u8]) { + debug_assert_eq!(output.len(), 8); + debug_assert_eq!(input0.len(), 16); + debug_assert_eq!(input1.len(), 16); + debug_assert_eq!(input2.len(), 16); + debug_assert_eq!(input3.len(), 16); + + // Bitslicing is a bit index manipulation. 512 bits of data means each bit is positioned at a + // 9-bit index. AES data is 4 blocks, each one a 4x4 column-major matrix of bytes, so the + // index is initially ([b]lock, [c]olumn, [r]ow, [p]osition): + // b1 b0 c1 c0 r1 r0 p2 p1 p0 + // + // The desired bitsliced data groups first by bit position, then row, column, block: + // p2 p1 p0 r1 r0 c1 c0 b1 b0 + + #[rustfmt::skip] + fn read_reordered(input: &[u8]) -> u64 { + (u64::from(input[0x0]) ) | + (u64::from(input[0x1]) << 0x10) | + (u64::from(input[0x2]) << 0x20) | + (u64::from(input[0x3]) << 0x30) | + (u64::from(input[0x8]) << 0x08) | + (u64::from(input[0x9]) << 0x18) | + (u64::from(input[0xa]) << 0x28) | + (u64::from(input[0xb]) << 0x38) + } + + // Reorder each block's bytes on input + // __ __ c1 c0 r1 r0 __ __ __ => __ __ c0 r1 r0 c1 __ __ __ + // Reorder by relabeling (note the order of input) + // b1 b0 c0 __ __ __ __ __ __ => c0 b1 b0 __ __ __ __ __ __ + let mut t0 = read_reordered(&input0[0x00..0x0c]); + let mut t4 = read_reordered(&input0[0x04..0x10]); + let mut t1 = read_reordered(&input1[0x00..0x0c]); + let mut t5 = read_reordered(&input1[0x04..0x10]); + let mut t2 = read_reordered(&input2[0x00..0x0c]); + let mut t6 = read_reordered(&input2[0x04..0x10]); + let mut t3 = read_reordered(&input3[0x00..0x0c]); + let mut t7 = read_reordered(&input3[0x04..0x10]); + + // Bit Index Swap 6 <-> 0: + // __ __ b0 __ __ __ __ __ p0 => __ __ p0 __ __ __ __ __ b0 + let m0 = 0x5555555555555555; + delta_swap_2(&mut t1, &mut t0, 1, m0); + delta_swap_2(&mut t3, &mut t2, 1, m0); + delta_swap_2(&mut t5, &mut t4, 1, m0); + delta_swap_2(&mut t7, &mut t6, 1, m0); + + // Bit Index Swap 7 <-> 1: + // __ b1 __ __ __ __ __ p1 __ => __ p1 __ __ __ __ __ b1 __ + let m1 = 0x3333333333333333; + delta_swap_2(&mut t2, &mut t0, 2, m1); + delta_swap_2(&mut t3, &mut t1, 2, m1); + delta_swap_2(&mut t6, &mut t4, 2, m1); + delta_swap_2(&mut t7, &mut t5, 2, m1); + + // Bit Index Swap 8 <-> 2: + // c0 __ __ __ __ __ p2 __ __ => p2 __ __ __ __ __ c0 __ __ + let m2 = 0x0f0f0f0f0f0f0f0f; + delta_swap_2(&mut t4, &mut t0, 4, m2); + delta_swap_2(&mut t5, &mut t1, 4, m2); + delta_swap_2(&mut t6, &mut t2, 4, m2); + delta_swap_2(&mut t7, &mut t3, 4, m2); + + // Final bitsliced bit index, as desired: + // p2 p1 p0 r1 r0 c1 c0 b1 b0 + output[0] = t0; + output[1] = t1; + output[2] = t2; + output[3] = t3; + output[4] = t4; + output[5] = t5; + output[6] = t6; + output[7] = t7; +} + +/// Un-bitslice a 512-bit internal state into four 128-bit blocks of output. +fn inv_bitslice(input: &[u64]) -> BatchBlocks { + debug_assert_eq!(input.len(), 8); + + // Unbitslicing is a bit index manipulation. 512 bits of data means each bit is positioned at + // a 9-bit index. AES data is 4 blocks, each one a 4x4 column-major matrix of bytes, so the + // desired index for the output is ([b]lock, [c]olumn, [r]ow, [p]osition): + // b1 b0 c1 c0 r1 r0 p2 p1 p0 + // + // The initially bitsliced data groups first by bit position, then row, column, block: + // p2 p1 p0 r1 r0 c1 c0 b1 b0 + + let mut t0 = input[0]; + let mut t1 = input[1]; + let mut t2 = input[2]; + let mut t3 = input[3]; + let mut t4 = input[4]; + let mut t5 = input[5]; + let mut t6 = input[6]; + let mut t7 = input[7]; + + // TODO: these bit index swaps are identical to those in 'packing' + + // Bit Index Swap 6 <-> 0: + // __ __ p0 __ __ __ __ __ b0 => __ __ b0 __ __ __ __ __ p0 + let m0 = 0x5555555555555555; + delta_swap_2(&mut t1, &mut t0, 1, m0); + delta_swap_2(&mut t3, &mut t2, 1, m0); + delta_swap_2(&mut t5, &mut t4, 1, m0); + delta_swap_2(&mut t7, &mut t6, 1, m0); + + // Bit Index Swap 7 <-> 1: + // __ p1 __ __ __ __ __ b1 __ => __ b1 __ __ __ __ __ p1 __ + let m1 = 0x3333333333333333; + delta_swap_2(&mut t2, &mut t0, 2, m1); + delta_swap_2(&mut t3, &mut t1, 2, m1); + delta_swap_2(&mut t6, &mut t4, 2, m1); + delta_swap_2(&mut t7, &mut t5, 2, m1); + + // Bit Index Swap 8 <-> 2: + // p2 __ __ __ __ __ c0 __ __ => c0 __ __ __ __ __ p2 __ __ + let m2 = 0x0f0f0f0f0f0f0f0f; + delta_swap_2(&mut t4, &mut t0, 4, m2); + delta_swap_2(&mut t5, &mut t1, 4, m2); + delta_swap_2(&mut t6, &mut t2, 4, m2); + delta_swap_2(&mut t7, &mut t3, 4, m2); + + #[rustfmt::skip] + fn write_reordered(columns: u64, output: &mut [u8]) { + output[0x0] = (columns ) as u8; + output[0x1] = (columns >> 0x10) as u8; + output[0x2] = (columns >> 0x20) as u8; + output[0x3] = (columns >> 0x30) as u8; + output[0x8] = (columns >> 0x08) as u8; + output[0x9] = (columns >> 0x18) as u8; + output[0xa] = (columns >> 0x28) as u8; + output[0xb] = (columns >> 0x38) as u8; + } + + let mut output = BatchBlocks::default(); + // Reorder by relabeling (note the order of output) + // c0 b1 b0 __ __ __ __ __ __ => b1 b0 c0 __ __ __ __ __ __ + // Reorder each block's bytes on output + // __ __ c0 r1 r0 c1 __ __ __ => __ __ c1 c0 r1 r0 __ __ __ + write_reordered(t0, &mut output[0][0x00..0x0c]); + write_reordered(t4, &mut output[0][0x04..0x10]); + write_reordered(t1, &mut output[1][0x00..0x0c]); + write_reordered(t5, &mut output[1][0x04..0x10]); + write_reordered(t2, &mut output[2][0x00..0x0c]); + write_reordered(t6, &mut output[2][0x04..0x10]); + write_reordered(t3, &mut output[3][0x00..0x0c]); + write_reordered(t7, &mut output[3][0x04..0x10]); + + // Final AES bit index, as desired: + // b1 b0 c1 c0 r1 r0 p2 p1 p0 + output +} + +/// Copy 32-bytes within the provided slice to an 8-byte offset +fn memshift32(buffer: &mut [u64], src_offset: usize) { + debug_assert_eq!(src_offset % 8, 0); + + let dst_offset = src_offset + 8; + debug_assert!(dst_offset + 8 <= buffer.len()); + + for i in (0..8).rev() { + buffer[dst_offset + i] = buffer[src_offset + i]; + } +} + +/// XOR the round key to the internal state. The round keys are expected to be +/// pre-computed and to be packed in the fixsliced representation. +#[inline] +fn add_round_key(state: &mut State, rkey: &[u64]) { + debug_assert_eq!(rkey.len(), 8); + for (a, b) in state.iter_mut().zip(rkey) { + *a ^= b; + } +} + +#[inline(always)] +fn add_round_constant_bit(state: &mut [u64], bit: usize) { + state[bit] ^= 0x00000000f0000000; +} + +#[inline(always)] +fn ror(x: u64, y: u32) -> u64 { + x.rotate_right(y) +} + +#[inline(always)] +fn ror_distance(rows: u32, cols: u32) -> u32 { + (rows << 4) + (cols << 2) +} + +#[inline(always)] +fn rotate_rows_1(x: u64) -> u64 { + ror(x, ror_distance(1, 0)) +} + +#[inline(always)] +fn rotate_rows_2(x: u64) -> u64 { + ror(x, ror_distance(2, 0)) +} + +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_1_1(x: u64) -> u64 { + (ror(x, ror_distance(1, 1)) & 0x0fff0fff0fff0fff) | + (ror(x, ror_distance(0, 1)) & 0xf000f000f000f000) +} + +#[cfg(not(aes_compact))] +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_1_2(x: u64) -> u64 { + (ror(x, ror_distance(1, 2)) & 0x00ff00ff00ff00ff) | + (ror(x, ror_distance(0, 2)) & 0xff00ff00ff00ff00) +} + +#[cfg(not(aes_compact))] +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_1_3(x: u64) -> u64 { + (ror(x, ror_distance(1, 3)) & 0x000f000f000f000f) | + (ror(x, ror_distance(0, 3)) & 0xfff0fff0fff0fff0) +} + +#[inline(always)] +#[rustfmt::skip] +fn rotate_rows_and_columns_2_2(x: u64) -> u64 { + (ror(x, ror_distance(2, 2)) & 0x00ff00ff00ff00ff) | + (ror(x, ror_distance(1, 2)) & 0xff00ff00ff00ff00) +} + +/// Low-level "hazmat" AES functions. +/// +/// Note: this isn't actually used in the `Aes128`/`Aes192`/`Aes256` +/// implementations in this crate, but instead provides raw access to +/// the AES round function gated under the `hazmat` crate feature. +#[cfg(feature = "hazmat")] +pub(crate) mod hazmat { + use super::{ + bitslice, inv_bitslice, inv_mix_columns_0, inv_shift_rows_1, inv_sub_bytes, mix_columns_0, + shift_rows_1, sub_bytes, sub_bytes_nots, State, + }; + use crate::{Block, Block8}; + + /// XOR the `src` block into the `dst` block in-place. + fn xor_in_place(dst: &mut Block, src: &Block) { + for (a, b) in dst.iter_mut().zip(src.as_slice()) { + *a ^= *b; + } + } + + /// Perform a bitslice operation, loading a single block. + fn bitslice_block(block: &Block) -> State { + let mut state = State::default(); + bitslice(&mut state, block, block, block, block); + state + } + + /// Perform an inverse bitslice operation, extracting a single block. + fn inv_bitslice_block(block: &mut Block, state: &State) { + block.copy_from_slice(&inv_bitslice(state)[0]); + } + + /// AES cipher (encrypt) round function. + #[inline] + pub(crate) fn cipher_round(block: &mut Block, round_key: &Block) { + let mut state = bitslice_block(block); + sub_bytes(&mut state); + sub_bytes_nots(&mut state); + shift_rows_1(&mut state); + mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + xor_in_place(block, round_key); + } + + /// AES cipher (encrypt) round function: parallel version. + #[inline] + pub(crate) fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + for (chunk, keys) in blocks.chunks_exact_mut(4).zip(round_keys.chunks_exact(4)) { + let mut state = State::default(); + bitslice(&mut state, &chunk[0], &chunk[1], &chunk[2], &chunk[3]); + sub_bytes(&mut state); + sub_bytes_nots(&mut state); + shift_rows_1(&mut state); + mix_columns_0(&mut state); + let res = inv_bitslice(&state); + + for i in 0..4 { + chunk[i] = res[i]; + xor_in_place(&mut chunk[i], &keys[i]); + } + } + } + + /// AES cipher (encrypt) round function. + #[inline] + pub(crate) fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { + let mut state = State::default(); + bitslice(&mut state, block, block, block, block); + sub_bytes_nots(&mut state); + inv_sub_bytes(&mut state); + inv_shift_rows_1(&mut state); + inv_mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + xor_in_place(block, round_key); + } + + /// AES cipher (encrypt) round function: parallel version. + #[inline] + pub(crate) fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { + for (chunk, keys) in blocks.chunks_exact_mut(4).zip(round_keys.chunks_exact(4)) { + let mut state = State::default(); + bitslice(&mut state, &chunk[0], &chunk[1], &chunk[2], &chunk[3]); + sub_bytes_nots(&mut state); + inv_sub_bytes(&mut state); + inv_shift_rows_1(&mut state); + inv_mix_columns_0(&mut state); + let res = inv_bitslice(&state); + + for i in 0..4 { + chunk[i] = res[i]; + xor_in_place(&mut chunk[i], &keys[i]); + } + } + } + + /// AES mix columns function. + #[inline] + pub(crate) fn mix_columns(block: &mut Block) { + let mut state = bitslice_block(block); + mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + } + + /// AES inverse mix columns function. + #[inline] + pub(crate) fn inv_mix_columns(block: &mut Block) { + let mut state = bitslice_block(block); + inv_mix_columns_0(&mut state); + inv_bitslice_block(block, &state); + } +} diff --git a/vendor/aes/tests/data/aes128.blb b/vendor/aes/tests/data/aes128.blb new file mode 100644 index 00000000..0accb99e Binary files /dev/null and b/vendor/aes/tests/data/aes128.blb differ diff --git a/vendor/aes/tests/data/aes192.blb b/vendor/aes/tests/data/aes192.blb new file mode 100644 index 00000000..b5f70fa0 Binary files /dev/null and b/vendor/aes/tests/data/aes192.blb differ diff --git a/vendor/aes/tests/data/aes256.blb b/vendor/aes/tests/data/aes256.blb new file mode 100644 index 00000000..2fa2e3ae Binary files /dev/null and b/vendor/aes/tests/data/aes256.blb differ diff --git a/vendor/aes/tests/hazmat.rs b/vendor/aes/tests/hazmat.rs new file mode 100644 index 00000000..ce0e8f82 --- /dev/null +++ b/vendor/aes/tests/hazmat.rs @@ -0,0 +1,155 @@ +//! Tests for low-level "hazmat" AES functions. + +// TODO(tarcieri): support for using the hazmat functions with the `soft` backend +#![cfg(feature = "hazmat")] + +use aes::{Block, Block8}; +use hex_literal::hex; + +/// Round function tests vectors. +struct RoundTestVector { + /// State at start of `round[r]`. + start: [u8; 16], + + /// Key schedule value for `round[r]`. + k_sch: [u8; 16], + + /// Cipher output. + output: [u8; 16], +} + +/// Cipher round function test vectors from FIPS 197 Appendix C.1. +const CIPHER_ROUND_TEST_VECTORS: &[RoundTestVector] = &[ + // round 1 + RoundTestVector { + start: hex!("00102030405060708090a0b0c0d0e0f0"), + k_sch: hex!("d6aa74fdd2af72fadaa678f1d6ab76fe"), + output: hex!("89d810e8855ace682d1843d8cb128fe4"), + }, + // round 2 + RoundTestVector { + start: hex!("89d810e8855ace682d1843d8cb128fe4"), + k_sch: hex!("b692cf0b643dbdf1be9bc5006830b3fe"), + output: hex!("4915598f55e5d7a0daca94fa1f0a63f7"), + }, + // round 3 + RoundTestVector { + start: hex!("4915598f55e5d7a0daca94fa1f0a63f7"), + k_sch: hex!("b6ff744ed2c2c9bf6c590cbf0469bf41"), + output: hex!("fa636a2825b339c940668a3157244d17"), + }, + // round 4 + RoundTestVector { + start: hex!("fa636a2825b339c940668a3157244d17"), + k_sch: hex!("47f7f7bc95353e03f96c32bcfd058dfd"), + output: hex!("247240236966b3fa6ed2753288425b6c"), + }, +]; + +/// Equivalent Inverse Cipher round function test vectors from FIPS 197 Appendix C.1. +const EQUIV_INV_CIPHER_ROUND_TEST_VECTORS: &[RoundTestVector] = &[ + // round 1 + RoundTestVector { + start: hex!("7ad5fda789ef4e272bca100b3d9ff59f"), + k_sch: hex!("13aa29be9c8faff6f770f58000f7bf03"), + output: hex!("54d990a16ba09ab596bbf40ea111702f"), + }, + // round 2 + RoundTestVector { + start: hex!("54d990a16ba09ab596bbf40ea111702f"), + k_sch: hex!("1362a4638f2586486bff5a76f7874a83"), + output: hex!("3e1c22c0b6fcbf768da85067f6170495"), + }, + // round 3 + RoundTestVector { + start: hex!("3e1c22c0b6fcbf768da85067f6170495"), + k_sch: hex!("8d82fc749c47222be4dadc3e9c7810f5"), + output: hex!("b458124c68b68a014b99f82e5f15554c"), + }, + // round 4 + RoundTestVector { + start: hex!("b458124c68b68a014b99f82e5f15554c"), + k_sch: hex!("72e3098d11c5de5f789dfe1578a2cccb"), + output: hex!("e8dab6901477d4653ff7f5e2e747dd4f"), + }, +]; + +#[test] +fn cipher_round_fips197_vectors() { + for vector in CIPHER_ROUND_TEST_VECTORS { + let mut block = Block::from(vector.start); + aes::hazmat::cipher_round(&mut block, &vector.k_sch.into()); + assert_eq!(block.as_slice(), &vector.output); + } +} + +#[test] +fn cipher_round_par_fips197_vectors() { + let mut blocks = Block8::default(); + let mut round_keys = Block8::default(); + + for i in 0..4 { + let vector = &CIPHER_ROUND_TEST_VECTORS[i]; + + blocks[i] = Block::from(vector.start); + blocks[i + 4] = Block::from(vector.start); + + round_keys[i] = Block::from(vector.k_sch); + round_keys[i + 4] = Block::from(vector.k_sch); + } + + aes::hazmat::cipher_round_par(&mut blocks, &round_keys); + + for i in 0..4 { + let vector = &CIPHER_ROUND_TEST_VECTORS[i]; + assert_eq!(blocks[i].as_slice(), &vector.output); + assert_eq!(blocks[i + 4].as_slice(), &vector.output); + } +} + +#[test] +fn equiv_inv_cipher_round_fips197_vectors() { + for vector in EQUIV_INV_CIPHER_ROUND_TEST_VECTORS { + let mut block = Block::from(vector.start); + aes::hazmat::equiv_inv_cipher_round(&mut block, &vector.k_sch.into()); + assert_eq!(block.as_slice(), &vector.output); + } +} + +#[test] +fn equiv_inv_cipher_round_par_fips197_vectors() { + let mut blocks = Block8::default(); + let mut round_keys = Block8::default(); + + for i in 0..4 { + let vector = &EQUIV_INV_CIPHER_ROUND_TEST_VECTORS[i]; + + blocks[i] = Block::from(vector.start); + blocks[i + 4] = Block::from(vector.start); + + round_keys[i] = Block::from(vector.k_sch); + round_keys[i + 4] = Block::from(vector.k_sch); + } + + aes::hazmat::equiv_inv_cipher_round_par(&mut blocks, &round_keys); + + for i in 0..4 { + let vector = &EQUIV_INV_CIPHER_ROUND_TEST_VECTORS[i]; + assert_eq!(blocks[i].as_slice(), &vector.output); + assert_eq!(blocks[i + 4].as_slice(), &vector.output); + } +} + +#[test] +fn mix_columns_fips197_vector() { + let mut block = Block::from(hex!("6353e08c0960e104cd70b751bacad0e7")); + aes::hazmat::mix_columns(&mut block); + assert_eq!(block.as_slice(), &hex!("5f72641557f5bc92f7be3b291db9f91a")) +} + +#[test] +fn inv_mix_columns_fips197_vector() { + let mut block = Block::from(hex!("bd6e7c3df2b5779e0b61216e8b10b689")); + aes::hazmat::inv_mix_columns(&mut block); + assert_eq!(block.as_slice(), &hex!("4773b91ff72f354361cb018ea1e6cf2c")) +} diff --git a/vendor/aes/tests/mod.rs b/vendor/aes/tests/mod.rs new file mode 100644 index 00000000..4164e4f2 --- /dev/null +++ b/vendor/aes/tests/mod.rs @@ -0,0 +1,6 @@ +//! Test vectors are from NESSIE: +//! https://www.cosic.esat.kuleuven.be/nessie/testvectors/ + +cipher::block_cipher_test!(aes128_test, "aes128", aes::Aes128); +cipher::block_cipher_test!(aes192_test, "aes192", aes::Aes192); +cipher::block_cipher_test!(aes256_test, "aes256", aes::Aes256); diff --git a/vendor/base64-0.21.5/.cargo-checksum.json b/vendor/base64-0.21.5/.cargo-checksum.json new file mode 100644 index 00000000..7aab19ce --- /dev/null +++ b/vendor/base64-0.21.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"3fcb2ea14aeaf0ebde20e464f0a735b2f58b0fecc99a20c11421ce47788911b8","Cargo.toml":"8a94eedc97a8458e7becfa780a67dfa2ea959bb5660c77dc8236fb7c6a9a64e6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"df01f5b4317d601e7de86743f9818aec9196abf9e298f5e47679b7a966ecd945","RELEASE-NOTES.md":"fa36233aeddb2e63dc0580ffc69a5a1cdbf24f962146ab2d6b817381e2f38cdd","benches/benchmarks.rs":"da4a49294a7fcaf718f2b062a52ed669ca096abce6c57b4025efdd24825048c2","clippy.toml":"b26be4d15ed059985ce6994f11817fd7562046f46e460a0dc64dbb71cfc246d1","examples/base64.rs":"8c48673029aeeb1e06a2ecfd237acf8ef24349990e97f6d2c4d0fa2af36c94b3","icon_CLion.svg":"cffa044ba75cb998ee3306991dc4a3755ec2f39ab95ddd4b74bc21988389020f","src/alphabet.rs":"f0cba9462692db0bc9572e3d03c01ac77ff705fa9e664db4162da1a279a871e1","src/chunked_encoder.rs":"edfdbb9a4329b80fb2c769ada81e234e00839e0fa85faaa70bacf40ce12e951c","src/decode.rs":"666ca75ccd975f0548d37312d2843ca4703b83697a044839bbefeba8f4f7874a","src/display.rs":"31bf3e19274a0b80dd8948a81ea535944f756ef5b88736124c940f5fe1e8c71c","src/encode.rs":"0c827067fced8a20723be2586ebbad94e4749e2cdad463091c4fd6899bd1d0e7","src/engine/general_purpose/decode.rs":"ba8a76d333ab96dd07b3f84bd6d405d690d2d17e84bd0878f05245a82dc16853","src/engine/general_purpose/decode_suffix.rs":"71ceb066b73e8cc833916e2cedbf0a01b07c2f16e30b2b2f63aff1c823874b51","src/engine/general_purpose/mod.rs":"9f49375fc03166a491acf464daa7a9e6540fdc2cca407da9a248e15640952c20","src/engine/mod.rs":"15210115e5f99e0d252a1240922deb1516778e318564f92a9d880a82fd82a55e","src/engine/naive.rs":"dc166010633e8de0fbff31e2f05d128506f3e0f34a6358c1a825b59a8ea1af0d","src/engine/tests.rs":"37bee2de07343bf5d37720f29cda291e8562f2363704e0ad91862d5991568d22","src/lib.rs":"c1eb62ba9f461dfa00b5297c9bc3d9f6c6702295806d43bb82e46ffb54ea61ed","src/prelude.rs":"c1587138e5301ac797c5c362cb3638649b33f79c20c16db6f38ad44330540752","src/read/decoder.rs":"cc87daa4c52a23d1275352bccf07468baf2b60e90b2ac14f89a94254697cb83c","src/read/decoder_tests.rs":"edeee377e70095532be1625d0148de2273b739e9069a05e616d3e67877d92f1d","src/read/mod.rs":"e0b714eda02d16b1ffa6f78fd09b2f963e01c881b1f7c17b39db4e904be5e746","src/tests.rs":"90cb9f8a1ccb7c4ddc4f8618208e0031fc97e0df0e5aa466d6a5cf45d25967d8","src/write/encoder.rs":"c889c853249220fe2ddaeb77ee6e2ee2945f7db88cd6658ef89ff71b81255ea8","src/write/encoder_string_writer.rs":"0326c9d120369b9bbc35697b5b9b141bed24283374c93d5af1052eb042e47799","src/write/encoder_tests.rs":"28695a485b17cf5db73656aae5d90127f726e02c6d70efd83e5ab53a4cc17b38","src/write/mod.rs":"73cd98dadc9d712b3fefd9449d97e825e097397441b90588e0051e4d3b0911b9","tests/encode.rs":"5309f4538b1df611436f7bfba7409c725161b6f841b1bbf8d9890ae185de7d88","tests/tests.rs":"78efcf0dc4bb6ae52f7a91fcad89e44e4dce578224c36b4e6c1c306459be8500"},"package":"35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"} \ No newline at end of file diff --git a/vendor/base64-0.21.5/Cargo.lock b/vendor/base64-0.21.5/Cargo.lock new file mode 100644 index 00000000..da628ba3 --- /dev/null +++ b/vendor/base64-0.21.5/Cargo.lock @@ -0,0 +1,817 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.5" +dependencies = [ + "criterion", + "lazy_static", + "rand", + "rstest", + "rstest_reuse", + "structopt", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap 0.11.0", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags", + "clap_lex", + "indexmap", + "textwrap 0.16.0", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap 3.2.25", + "criterion-plot", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rstest" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d912f35156a3f99a66ee3e11ac2e0b3f34ac85a07e05263d05a7e2c8810d616f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "rstest_reuse" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b29d3117bce27ea307d1fb7ce12c64ba11b3fd04311a42d32bc5f0072e6e3d4d" +dependencies = [ + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap 2.34.0", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/base64-0.21.5/Cargo.toml b/vendor/base64-0.21.5/Cargo.toml new file mode 100644 index 00000000..2de75ab2 --- /dev/null +++ b/vendor/base64-0.21.5/Cargo.toml @@ -0,0 +1,83 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.48.0" +name = "base64" +version = "0.21.5" +authors = [ + "Alice Maz ", + "Marshall Pierce ", +] +description = "encodes and decodes base64 as bytes or utf8" +documentation = "https://docs.rs/base64" +readme = "README.md" +keywords = [ + "base64", + "utf8", + "encode", + "decode", + "no_std", +] +categories = ["encoding"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/marshallpierce/rust-base64" + +[package.metadata.docs.rs] +rustdoc-args = ["--generate-link-to-definition"] + +[profile.bench] +debug = 2 + +[profile.test] +opt-level = 3 + +[[example]] +name = "base64" +required-features = ["std"] + +[[test]] +name = "tests" +required-features = ["alloc"] + +[[test]] +name = "encode" +required-features = ["alloc"] + +[[bench]] +name = "benchmarks" +harness = false +required-features = ["std"] + +[dev-dependencies.criterion] +version = "0.4.0" + +[dev-dependencies.lazy_static] +version = "1.4.0" + +[dev-dependencies.rand] +version = "0.8.5" +features = ["small_rng"] + +[dev-dependencies.rstest] +version = "0.12.0" + +[dev-dependencies.rstest_reuse] +version = "0.3.0" + +[dev-dependencies.structopt] +version = "0.3.26" + +[features] +alloc = [] +default = ["std"] +std = ["alloc"] diff --git a/vendor/base64-0.21.5/LICENSE-APACHE b/vendor/base64-0.21.5/LICENSE-APACHE new file mode 100644 index 00000000..16fe87b0 --- /dev/null +++ b/vendor/base64-0.21.5/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 [yyyy] [name of copyright owner] + +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/vendor/base64-0.21.5/LICENSE-MIT b/vendor/base64-0.21.5/LICENSE-MIT new file mode 100644 index 00000000..7bc10f80 --- /dev/null +++ b/vendor/base64-0.21.5/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Alice Maz + +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/vendor/base64-0.21.5/README.md b/vendor/base64-0.21.5/README.md new file mode 100644 index 00000000..f566756d --- /dev/null +++ b/vendor/base64-0.21.5/README.md @@ -0,0 +1,154 @@ +# [base64](https://crates.io/crates/base64) + +[![](https://img.shields.io/crates/v/base64.svg)](https://crates.io/crates/base64) [![Docs](https://docs.rs/base64/badge.svg)](https://docs.rs/base64) [![CircleCI](https://circleci.com/gh/marshallpierce/rust-base64/tree/master.svg?style=shield)](https://circleci.com/gh/marshallpierce/rust-base64/tree/master) [![codecov](https://codecov.io/gh/marshallpierce/rust-base64/branch/master/graph/badge.svg)](https://codecov.io/gh/marshallpierce/rust-base64) [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) + + + +Made with CLion. Thanks to JetBrains for supporting open source! + +It's base64. What more could anyone want? + +This library's goals are to be *correct* and *fast*. It's thoroughly tested and widely used. It exposes functionality at +multiple levels of abstraction so you can choose the level of convenience vs performance that you want, +e.g. `decode_engine_slice` decodes into an existing `&mut [u8]` and is pretty fast (2.6GiB/s for a 3 KiB input), +whereas `decode_engine` allocates a new `Vec` and returns it, which might be more convenient in some cases, but is +slower (although still fast enough for almost any purpose) at 2.1 GiB/s. + +See the [docs](https://docs.rs/base64) for all the details. + +## FAQ + +### I need to decode base64 with whitespace/null bytes/other random things interspersed in it. What should I do? + +Remove non-base64 characters from your input before decoding. + +If you have a `Vec` of base64, [retain](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain) can be used to +strip out whatever you need removed. + +If you have a `Read` (e.g. reading a file or network socket), there are various approaches. + +- Use [iter_read](https://crates.io/crates/iter-read) together with `Read`'s `bytes()` to filter out unwanted bytes. +- Implement `Read` with a `read()` impl that delegates to your actual `Read`, and then drops any bytes you don't want. + +### I need to line-wrap base64, e.g. for MIME/PEM. + +[line-wrap](https://crates.io/crates/line-wrap) does just that. + +### I want canonical base64 encoding/decoding. + +First, don't do this. You should no more expect Base64 to be canonical than you should expect compression algorithms to +produce canonical output across all usage in the wild (hint: they don't). +However, [people are drawn to their own destruction like moths to a flame](https://eprint.iacr.org/2022/361), so here we +are. + +There are two opportunities for non-canonical encoding (and thus, detection of the same during decoding): the final bits +of the last encoded token in two or three token suffixes, and the `=` token used to inflate the suffix to a full four +tokens. + +The trailing bits issue is unavoidable: with 6 bits available in each encoded token, 1 input byte takes 2 tokens, +with the second one having some bits unused. Same for two input bytes: 16 bits, but 3 tokens have 18 bits. Unless we +decide to stop shipping whole bytes around, we're stuck with those extra bits that a sneaky or buggy encoder might set +to 1 instead of 0. + +The `=` pad bytes, on the other hand, are entirely a self-own by the Base64 standard. They do not affect decoding other +than to provide an opportunity to say "that padding is incorrect". Exabytes of storage and transfer have no doubt been +wasted on pointless `=` bytes. Somehow we all seem to be quite comfortable with, say, hex-encoded data just stopping +when it's done rather than requiring a confirmation that the author of the encoder could count to four. Anyway, there +are two ways to make pad bytes predictable: require canonical padding to the next multiple of four bytes as per the RFC, +or, if you control all producers and consumers, save a few bytes by requiring no padding (especially applicable to the +url-safe alphabet). + +All `Engine` implementations must at a minimum support treating non-canonical padding of both types as an error, and +optionally may allow other behaviors. + +## Rust version compatibility + +The minimum supported Rust version is 1.48.0. + +# Contributing + +Contributions are very welcome. However, because this library is used widely, and in security-sensitive contexts, all +PRs will be carefully scrutinized. Beyond that, this sort of low level library simply needs to be 100% correct. Nobody +wants to chase bugs in encoding of any sort. + +All this means that it takes me a fair amount of time to review each PR, so it might take quite a while to carve out the +free time to give each PR the attention it deserves. I will get to everyone eventually! + +## Developing + +Benchmarks are in `benches/`. + +```bash +cargo bench +``` + +## no_std + +This crate supports no_std. By default the crate targets std via the `std` feature. You can deactivate +the `default-features` to target `core` instead. In that case you lose out on all the functionality revolving +around `std::io`, `std::error::Error`, and heap allocations. There is an additional `alloc` feature that you can activate +to bring back the support for heap allocations. + +## Profiling + +On Linux, you can use [perf](https://perf.wiki.kernel.org/index.php/Main_Page) for profiling. Then compile the +benchmarks with `cargo bench --no-run`. + +Run the benchmark binary with `perf` (shown here filtering to one particular benchmark, which will make the results +easier to read). `perf` is only available to the root user on most systems as it fiddles with event counters in your +CPU, so use `sudo`. We need to run the actual benchmark binary, hence the path into `target`. You can see the actual +full path with `cargo bench -v`; it will print out the commands it runs. If you use the exact path +that `bench` outputs, make sure you get the one that's for the benchmarks, not the tests. You may also want +to `cargo clean` so you have only one `benchmarks-` binary (they tend to accumulate). + +```bash +sudo perf record target/release/deps/benchmarks-* --bench decode_10mib_reuse +``` + +Then analyze the results, again with perf: + +```bash +sudo perf annotate -l +``` + +You'll see a bunch of interleaved rust source and assembly like this. The section with `lib.rs:327` is telling us that +4.02% of samples saw the `movzbl` aka bit shift as the active instruction. However, this percentage is not as exact as +it seems due to a phenomenon called *skid*. Basically, a consequence of how fancy modern CPUs are is that this sort of +instruction profiling is inherently inaccurate, especially in branch-heavy code. + +```text + lib.rs:322 0.70 : 10698: mov %rdi,%rax + 2.82 : 1069b: shr $0x38,%rax + : if morsel == decode_tables::INVALID_VALUE { + : bad_byte_index = input_index; + : break; + : }; + : accum = (morsel as u64) << 58; + lib.rs:327 4.02 : 1069f: movzbl (%r9,%rax,1),%r15d + : // fast loop of 8 bytes at a time + : while input_index < length_of_full_chunks { + : let mut accum: u64; + : + : let input_chunk = BigEndian::read_u64(&input_bytes[input_index..(input_index + 8)]); + : morsel = decode_table[(input_chunk >> 56) as usize]; + lib.rs:322 3.68 : 106a4: cmp $0xff,%r15 + : if morsel == decode_tables::INVALID_VALUE { + 0.00 : 106ab: je 1090e +``` + +## Fuzzing + +This uses [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). See `fuzz/fuzzers` for the available fuzzing scripts. +To run, use an invocation like these: + +```bash +cargo +nightly fuzz run roundtrip +cargo +nightly fuzz run roundtrip_no_pad +cargo +nightly fuzz run roundtrip_random_config -- -max_len=10240 +cargo +nightly fuzz run decode_random +``` + +## License + +This project is dual-licensed under MIT and Apache 2.0. + diff --git a/vendor/base64-0.21.5/RELEASE-NOTES.md b/vendor/base64-0.21.5/RELEASE-NOTES.md new file mode 100644 index 00000000..d6d94c5a --- /dev/null +++ b/vendor/base64-0.21.5/RELEASE-NOTES.md @@ -0,0 +1,253 @@ +# 0.21.5 + +- Add `Debug` and `Clone` impls for the general purpose Engine + +# 0.21.4 + +- Make `encoded_len` `const`, allowing the creation of arrays sized to encode compile-time-known data lengths + +# 0.21.3 + +- Implement `source` instead of `cause` on Error types +- Roll back MSRV to 1.48.0 so Debian can continue to live in a time warp +- Slightly faster chunked encoding for short inputs +- Decrease binary size + +# 0.21.2 + +- Rollback MSRV to 1.57.0 -- only dev dependencies need 1.60, not the main code + +# 0.21.1 + +- Remove the possibility of panicking during decoded length calculations +- `DecoderReader` no longer sometimes erroneously ignores + padding [#226](https://github.com/marshallpierce/rust-base64/issues/226) + +## Breaking changes + +- `Engine.internal_decode` return type changed +- Update MSRV to 1.60.0 + +# 0.21.0 + +## Migration + +### Functions + +| < 0.20 function | 0.21 equivalent | +|-------------------------|-------------------------------------------------------------------------------------| +| `encode()` | `engine::general_purpose::STANDARD.encode()` or `prelude::BASE64_STANDARD.encode()` | +| `encode_config()` | `engine.encode()` | +| `encode_config_buf()` | `engine.encode_string()` | +| `encode_config_slice()` | `engine.encode_slice()` | +| `decode()` | `engine::general_purpose::STANDARD.decode()` or `prelude::BASE64_STANDARD.decode()` | +| `decode_config()` | `engine.decode()` | +| `decode_config_buf()` | `engine.decode_vec()` | +| `decode_config_slice()` | `engine.decode_slice()` | + +The short-lived 0.20 functions were the 0.13 functions with `config` replaced with `engine`. + +### Padding + +If applicable, use the preset engines `engine::STANDARD`, `engine::STANDARD_NO_PAD`, `engine::URL_SAFE`, +or `engine::URL_SAFE_NO_PAD`. +The `NO_PAD` ones require that padding is absent when decoding, and the others require that +canonical padding is present . + +If you need the < 0.20 behavior that did not care about padding, or want to recreate < 0.20.0's predefined `Config`s +precisely, see the following table. + +| 0.13.1 Config | 0.20.0+ alphabet | `encode_padding` | `decode_padding_mode` | +|-----------------|------------------|------------------|-----------------------| +| STANDARD | STANDARD | true | Indifferent | +| STANDARD_NO_PAD | STANDARD | false | Indifferent | +| URL_SAFE | URL_SAFE | true | Indifferent | +| URL_SAFE_NO_PAD | URL_SAFE | false | Indifferent | + +# 0.21.0-rc.1 + +- Restore the ability to decode into a slice of precisely the correct length with `Engine.decode_slice_unchecked`. +- Add `Engine` as a `pub use` in `prelude`. + +# 0.21.0-beta.2 + +## Breaking changes + +- Re-exports of preconfigured engines in `engine` are removed in favor of `base64::prelude::...` that are better suited + to those who wish to `use` the entire path to a name. + +# 0.21.0-beta.1 + +## Breaking changes + +- `FastPortable` was only meant to be an interim name, and shouldn't have shipped in 0.20. It is now `GeneralPurpose` to + make its intended usage more clear. +- `GeneralPurpose` and its config are now `pub use`'d in the `engine` module for convenience. +- Change a few `from()` functions to be `new()`. `from()` causes confusing compiler errors because of confusion + with `From::from`, and is a little misleading because some of those invocations are not very cheap as one would + usually expect from a `from` call. +- `encode*` and `decode*` top level functions are now methods on `Engine`. +- `DEFAULT_ENGINE` was replaced by `engine::general_purpose::STANDARD` +- Predefined engine consts `engine::general_purpose::{STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD}` + - These are `pub use`d into `engine` as well +- The `*_slice` decode/encode functions now return an error instead of panicking when the output slice is too small + - As part of this, there isn't now a public way to decode into a slice _exactly_ the size needed for inputs that + aren't multiples of 4 tokens. If adding up to 2 bytes to always be a multiple of 3 bytes for the decode buffer is + a problem, file an issue. + +## Other changes + +- `decoded_len_estimate()` is provided to make it easy to size decode buffers correctly. + +# 0.20.0 + +## Breaking changes + +- Update MSRV to 1.57.0 +- Decoding can now either ignore padding, require correct padding, or require no padding. The default is to require + correct padding. + - The `NO_PAD` config now requires that padding be absent when decoding. + +## 0.20.0-alpha.1 + +### Breaking changes + +- Extended the `Config` concept into the `Engine` abstraction, allowing the user to pick different encoding / decoding + implementations. + - What was formerly the only algorithm is now the `FastPortable` engine, so named because it's portable (works on + any CPU) and relatively fast. + - This opens the door to a portable constant-time + implementation ([#153](https://github.com/marshallpierce/rust-base64/pull/153), + presumably `ConstantTimePortable`?) for security-sensitive applications that need side-channel resistance, and + CPU-specific SIMD implementations for more speed. + - Standard base64 per the RFC is available via `DEFAULT_ENGINE`. To use different alphabets or other settings ( + padding, etc), create your own engine instance. +- `CharacterSet` is now `Alphabet` (per the RFC), and allows creating custom alphabets. The corresponding tables that + were previously code-generated are now built dynamically. +- Since there are already multiple breaking changes, various functions are renamed to be more consistent and + discoverable. +- MSRV is now 1.47.0 to allow various things to use `const fn`. +- `DecoderReader` now owns its inner reader, and can expose it via `into_inner()`. For symmetry, `EncoderWriter` can do + the same with its writer. +- `encoded_len` is now public so you can size encode buffers precisely. + +# 0.13.1 + +- More precise decode buffer sizing, avoiding unnecessary allocation in `decode_config`. + +# 0.13.0 + +- Config methods are const +- Added `EncoderStringWriter` to allow encoding directly to a String +- `EncoderWriter` now owns its delegate writer rather than keeping a reference to it (though refs still work) + - As a consequence, it is now possible to extract the delegate writer from an `EncoderWriter` via `finish()`, which + returns `Result` instead of `Result<()>`. If you were calling `finish()` explicitly, you will now need to + use `let _ = foo.finish()` instead of just `foo.finish()` to avoid a warning about the unused value. +- When decoding input that has both an invalid length and an invalid symbol as the last byte, `InvalidByte` will be + emitted instead of `InvalidLength` to make the problem more obvious. + +# 0.12.2 + +- Add `BinHex` alphabet + +# 0.12.1 + +- Add `Bcrypt` alphabet + +# 0.12.0 + +- A `Read` implementation (`DecoderReader`) to let users transparently decoded data from a b64 input source +- IMAP's modified b64 alphabet +- Relaxed type restrictions to just `AsRef<[ut8]>` for main `encode*`/`decode*` functions +- A minor performance improvement in encoding + +# 0.11.0 + +- Minimum rust version 1.34.0 +- `no_std` is now supported via the two new features `alloc` and `std`. + +# 0.10.1 + +- Minimum rust version 1.27.2 +- Fix bug in streaming encoding ([#90](https://github.com/marshallpierce/rust-base64/pull/90)): if the underlying writer + didn't write all the bytes given to it, the remaining bytes would not be retried later. See the docs + on `EncoderWriter::write`. +- Make it configurable whether or not to return an error when decoding detects excess trailing bits. + +# 0.10.0 + +- Remove line wrapping. Line wrapping was never a great conceptual fit in this library, and other features (streaming + encoding, etc) either couldn't support it or could support only special cases of it with a great increase in + complexity. Line wrapping has been pulled out into a [line-wrap](https://crates.io/crates/line-wrap) crate, so it's + still available if you need it. + - `Base64Display` creation no longer uses a `Result` because it can't fail, which means its helper methods for + common + configs that `unwrap()` for you are no longer needed +- Add a streaming encoder `Write` impl to transparently base64 as you write. +- Remove the remaining `unsafe` code. +- Remove whitespace stripping to simplify `no_std` support. No out of the box configs use it, and it's trivial to do + yourself if needed: `filter(|b| !b" \n\t\r\x0b\x0c".contains(b)`. +- Detect invalid trailing symbols when decoding and return an error rather than silently ignoring them. + +# 0.9.3 + +- Update safemem + +# 0.9.2 + +- Derive `Clone` for `DecodeError`. + +# 0.9.1 + +- Add support for `crypt(3)`'s base64 variant. + +# 0.9.0 + +- `decode_config_slice` function for no-allocation decoding, analogous to `encode_config_slice` +- Decode performance optimization + +# 0.8.0 + +- `encode_config_slice` function for no-allocation encoding + +# 0.7.0 + +- `STANDARD_NO_PAD` config +- `Base64Display` heap-free wrapper for use in format strings, etc + +# 0.6.0 + +- Decode performance improvements +- Use `unsafe` in fewer places +- Added fuzzers + +# 0.5.2 + +- Avoid usize overflow when calculating length +- Better line wrapping performance + +# 0.5.1 + +- Temporarily disable line wrapping +- Add Apache 2.0 license + +# 0.5.0 + +- MIME support, including configurable line endings and line wrapping +- Removed `decode_ws` +- Renamed `Base64Error` to `DecodeError` + +# 0.4.1 + +- Allow decoding a `AsRef<[u8]>` instead of just a `&str` + +# 0.4.0 + +- Configurable padding +- Encode performance improvements + +# 0.3.0 + +- Added encode/decode functions that do not allocate their own storage +- Decode performance improvements +- Extraneous padding bytes are no longer ignored. Now, an error will be returned. diff --git a/vendor/base64-0.21.5/benches/benchmarks.rs b/vendor/base64-0.21.5/benches/benchmarks.rs new file mode 100644 index 00000000..802c8cca --- /dev/null +++ b/vendor/base64-0.21.5/benches/benchmarks.rs @@ -0,0 +1,239 @@ +#[macro_use] +extern crate criterion; + +use base64::{ + display, + engine::{general_purpose::STANDARD, Engine}, + write, +}; +use criterion::{black_box, Bencher, BenchmarkId, Criterion, Throughput}; +use rand::{Rng, SeedableRng}; +use std::io::{self, Read, Write}; + +fn do_decode_bench(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size * 3 / 4); + fill(&mut v); + let encoded = STANDARD.encode(&v); + + b.iter(|| { + let orig = STANDARD.decode(&encoded); + black_box(&orig); + }); +} + +fn do_decode_bench_reuse_buf(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size * 3 / 4); + fill(&mut v); + let encoded = STANDARD.encode(&v); + + let mut buf = Vec::new(); + b.iter(|| { + STANDARD.decode_vec(&encoded, &mut buf).unwrap(); + black_box(&buf); + buf.clear(); + }); +} + +fn do_decode_bench_slice(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size * 3 / 4); + fill(&mut v); + let encoded = STANDARD.encode(&v); + + let mut buf = vec![0; size]; + b.iter(|| { + STANDARD.decode_slice(&encoded, &mut buf).unwrap(); + black_box(&buf); + }); +} + +fn do_decode_bench_stream(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size * 3 / 4); + fill(&mut v); + let encoded = STANDARD.encode(&v); + + let mut buf = vec![0; size]; + buf.truncate(0); + + b.iter(|| { + let mut cursor = io::Cursor::new(&encoded[..]); + let mut decoder = base64::read::DecoderReader::new(&mut cursor, &STANDARD); + decoder.read_to_end(&mut buf).unwrap(); + buf.clear(); + black_box(&buf); + }); +} + +fn do_encode_bench(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + b.iter(|| { + let e = STANDARD.encode(&v); + black_box(&e); + }); +} + +fn do_encode_bench_display(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + b.iter(|| { + let e = format!("{}", display::Base64Display::new(&v, &STANDARD)); + black_box(&e); + }); +} + +fn do_encode_bench_reuse_buf(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + let mut buf = String::new(); + b.iter(|| { + STANDARD.encode_string(&v, &mut buf); + buf.clear(); + }); +} + +fn do_encode_bench_slice(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + // conservative estimate of encoded size + let mut buf = vec![0; v.len() * 2]; + b.iter(|| STANDARD.encode_slice(&v, &mut buf).unwrap()); +} + +fn do_encode_bench_stream(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + let mut buf = Vec::new(); + + buf.reserve(size * 2); + b.iter(|| { + buf.clear(); + let mut stream_enc = write::EncoderWriter::new(&mut buf, &STANDARD); + stream_enc.write_all(&v).unwrap(); + stream_enc.flush().unwrap(); + }); +} + +fn do_encode_bench_string_stream(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + + b.iter(|| { + let mut stream_enc = write::EncoderStringWriter::new(&STANDARD); + stream_enc.write_all(&v).unwrap(); + stream_enc.flush().unwrap(); + let _ = stream_enc.into_inner(); + }); +} + +fn do_encode_bench_string_reuse_buf_stream(b: &mut Bencher, &size: &usize) { + let mut v: Vec = Vec::with_capacity(size); + fill(&mut v); + + let mut buf = String::new(); + b.iter(|| { + buf.clear(); + let mut stream_enc = write::EncoderStringWriter::from_consumer(&mut buf, &STANDARD); + stream_enc.write_all(&v).unwrap(); + stream_enc.flush().unwrap(); + let _ = stream_enc.into_inner(); + }); +} + +fn fill(v: &mut Vec) { + let cap = v.capacity(); + // weak randomness is plenty; we just want to not be completely friendly to the branch predictor + let mut r = rand::rngs::SmallRng::from_entropy(); + while v.len() < cap { + v.push(r.gen::()); + } +} + +const BYTE_SIZES: [usize; 5] = [3, 50, 100, 500, 3 * 1024]; + +// Benchmarks over these byte sizes take longer so we will run fewer samples to +// keep the benchmark runtime reasonable. +const LARGE_BYTE_SIZES: [usize; 3] = [3 * 1024 * 1024, 10 * 1024 * 1024, 30 * 1024 * 1024]; + +fn encode_benchmarks(c: &mut Criterion, label: &str, byte_sizes: &[usize]) { + let mut group = c.benchmark_group(label); + group + .warm_up_time(std::time::Duration::from_millis(500)) + .measurement_time(std::time::Duration::from_secs(3)); + + for size in byte_sizes { + group + .throughput(Throughput::Bytes(*size as u64)) + .bench_with_input(BenchmarkId::new("encode", size), size, do_encode_bench) + .bench_with_input( + BenchmarkId::new("encode_display", size), + size, + do_encode_bench_display, + ) + .bench_with_input( + BenchmarkId::new("encode_reuse_buf", size), + size, + do_encode_bench_reuse_buf, + ) + .bench_with_input( + BenchmarkId::new("encode_slice", size), + size, + do_encode_bench_slice, + ) + .bench_with_input( + BenchmarkId::new("encode_reuse_buf_stream", size), + size, + do_encode_bench_stream, + ) + .bench_with_input( + BenchmarkId::new("encode_string_stream", size), + size, + do_encode_bench_string_stream, + ) + .bench_with_input( + BenchmarkId::new("encode_string_reuse_buf_stream", size), + size, + do_encode_bench_string_reuse_buf_stream, + ); + } + + group.finish(); +} + +fn decode_benchmarks(c: &mut Criterion, label: &str, byte_sizes: &[usize]) { + let mut group = c.benchmark_group(label); + + for size in byte_sizes { + group + .warm_up_time(std::time::Duration::from_millis(500)) + .measurement_time(std::time::Duration::from_secs(3)) + .throughput(Throughput::Bytes(*size as u64)) + .bench_with_input(BenchmarkId::new("decode", size), size, do_decode_bench) + .bench_with_input( + BenchmarkId::new("decode_reuse_buf", size), + size, + do_decode_bench_reuse_buf, + ) + .bench_with_input( + BenchmarkId::new("decode_slice", size), + size, + do_decode_bench_slice, + ) + .bench_with_input( + BenchmarkId::new("decode_stream", size), + size, + do_decode_bench_stream, + ); + } + + group.finish(); +} + +fn bench(c: &mut Criterion) { + encode_benchmarks(c, "encode_small_input", &BYTE_SIZES[..]); + encode_benchmarks(c, "encode_large_input", &LARGE_BYTE_SIZES[..]); + decode_benchmarks(c, "decode_small_input", &BYTE_SIZES[..]); + decode_benchmarks(c, "decode_large_input", &LARGE_BYTE_SIZES[..]); +} + +criterion_group!(benches, bench); +criterion_main!(benches); diff --git a/vendor/base64-0.21.5/clippy.toml b/vendor/base64-0.21.5/clippy.toml new file mode 100644 index 00000000..11d46a73 --- /dev/null +++ b/vendor/base64-0.21.5/clippy.toml @@ -0,0 +1 @@ +msrv = "1.48.0" diff --git a/vendor/base64-0.21.5/examples/base64.rs b/vendor/base64-0.21.5/examples/base64.rs new file mode 100644 index 00000000..0a214d28 --- /dev/null +++ b/vendor/base64-0.21.5/examples/base64.rs @@ -0,0 +1,89 @@ +use std::fs::File; +use std::io::{self, Read}; +use std::path::PathBuf; +use std::process; +use std::str::FromStr; + +use base64::{alphabet, engine, read, write}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +enum Alphabet { + Standard, + UrlSafe, +} + +impl Default for Alphabet { + fn default() -> Self { + Self::Standard + } +} + +impl FromStr for Alphabet { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "standard" => Ok(Self::Standard), + "urlsafe" => Ok(Self::UrlSafe), + _ => Err(format!("alphabet '{}' unrecognized", s)), + } + } +} + +/// Base64 encode or decode FILE (or standard input), to standard output. +#[derive(Debug, StructOpt)] +struct Opt { + /// decode data + #[structopt(short = "d", long = "decode")] + decode: bool, + /// The alphabet to choose. Defaults to the standard base64 alphabet. + /// Supported alphabets include "standard" and "urlsafe". + #[structopt(long = "alphabet")] + alphabet: Option, + /// The file to encode/decode. + #[structopt(parse(from_os_str))] + file: Option, +} + +fn main() { + let opt = Opt::from_args(); + let stdin; + let mut input: Box = match opt.file { + None => { + stdin = io::stdin(); + Box::new(stdin.lock()) + } + Some(ref f) if f.as_os_str() == "-" => { + stdin = io::stdin(); + Box::new(stdin.lock()) + } + Some(f) => Box::new(File::open(f).unwrap()), + }; + + let alphabet = opt.alphabet.unwrap_or_default(); + let engine = engine::GeneralPurpose::new( + &match alphabet { + Alphabet::Standard => alphabet::STANDARD, + Alphabet::UrlSafe => alphabet::URL_SAFE, + }, + engine::general_purpose::PAD, + ); + + let stdout = io::stdout(); + let mut stdout = stdout.lock(); + let r = if opt.decode { + let mut decoder = read::DecoderReader::new(&mut input, &engine); + io::copy(&mut decoder, &mut stdout) + } else { + let mut encoder = write::EncoderWriter::new(&mut stdout, &engine); + io::copy(&mut input, &mut encoder) + }; + if let Err(e) = r { + eprintln!( + "Base64 {} failed with {}", + if opt.decode { "decode" } else { "encode" }, + e + ); + process::exit(1); + } +} diff --git a/vendor/base64-0.21.5/icon_CLion.svg b/vendor/base64-0.21.5/icon_CLion.svg new file mode 100644 index 00000000..e9edb044 --- /dev/null +++ b/vendor/base64-0.21.5/icon_CLion.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + icon_CLion + + + + + + + + + + + + + diff --git a/vendor/base64-0.21.5/src/alphabet.rs b/vendor/base64-0.21.5/src/alphabet.rs new file mode 100644 index 00000000..f7cd8191 --- /dev/null +++ b/vendor/base64-0.21.5/src/alphabet.rs @@ -0,0 +1,272 @@ +//! Provides [Alphabet] and constants for alphabets commonly used in the wild. + +use crate::PAD_BYTE; +use core::{convert, fmt}; +#[cfg(any(feature = "std", test))] +use std::error; + +const ALPHABET_SIZE: usize = 64; + +/// An alphabet defines the 64 ASCII characters (symbols) used for base64. +/// +/// Common alphabets are provided as constants, and custom alphabets +/// can be made via `from_str` or the `TryFrom` implementation. +/// +/// # Examples +/// +/// Building and using a custom Alphabet: +/// +/// ``` +/// let custom = base64::alphabet::Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap(); +/// +/// let engine = base64::engine::GeneralPurpose::new( +/// &custom, +/// base64::engine::general_purpose::PAD); +/// ``` +/// +/// Building a const: +/// +/// ``` +/// use base64::alphabet::Alphabet; +/// +/// static CUSTOM: Alphabet = { +/// // Result::unwrap() isn't const yet, but panic!() is OK +/// match Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") { +/// Ok(x) => x, +/// Err(_) => panic!("creation of alphabet failed"), +/// } +/// }; +/// ``` +/// +/// Building a lazy_static: +/// +/// ``` +/// use base64::{ +/// alphabet::Alphabet, +/// engine::{general_purpose::GeneralPurpose, GeneralPurposeConfig}, +/// }; +/// +/// lazy_static::lazy_static! { +/// static ref CUSTOM: Alphabet = Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap(); +/// } +/// ``` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Alphabet { + pub(crate) symbols: [u8; ALPHABET_SIZE], +} + +impl Alphabet { + /// Performs no checks so that it can be const. + /// Used only for known-valid strings. + const fn from_str_unchecked(alphabet: &str) -> Self { + let mut symbols = [0_u8; ALPHABET_SIZE]; + let source_bytes = alphabet.as_bytes(); + + // a way to copy that's allowed in const fn + let mut index = 0; + while index < ALPHABET_SIZE { + symbols[index] = source_bytes[index]; + index += 1; + } + + Self { symbols } + } + + /// Create an `Alphabet` from a string of 64 unique printable ASCII bytes. + /// + /// The `=` byte is not allowed as it is used for padding. + pub const fn new(alphabet: &str) -> Result { + let bytes = alphabet.as_bytes(); + if bytes.len() != ALPHABET_SIZE { + return Err(ParseAlphabetError::InvalidLength); + } + + { + let mut index = 0; + while index < ALPHABET_SIZE { + let byte = bytes[index]; + + // must be ascii printable. 127 (DEL) is commonly considered printable + // for some reason but clearly unsuitable for base64. + if !(byte >= 32_u8 && byte <= 126_u8) { + return Err(ParseAlphabetError::UnprintableByte(byte)); + } + // = is assumed to be padding, so cannot be used as a symbol + if byte == PAD_BYTE { + return Err(ParseAlphabetError::ReservedByte(byte)); + } + + // Check for duplicates while staying within what const allows. + // It's n^2, but only over 64 hot bytes, and only once, so it's likely in the single digit + // microsecond range. + + let mut probe_index = 0; + while probe_index < ALPHABET_SIZE { + if probe_index == index { + probe_index += 1; + continue; + } + + let probe_byte = bytes[probe_index]; + + if byte == probe_byte { + return Err(ParseAlphabetError::DuplicatedByte(byte)); + } + + probe_index += 1; + } + + index += 1; + } + } + + Ok(Self::from_str_unchecked(alphabet)) + } +} + +impl convert::TryFrom<&str> for Alphabet { + type Error = ParseAlphabetError; + + fn try_from(value: &str) -> Result { + Self::new(value) + } +} + +/// Possible errors when constructing an [Alphabet] from a `str`. +#[derive(Debug, Eq, PartialEq)] +pub enum ParseAlphabetError { + /// Alphabets must be 64 ASCII bytes + InvalidLength, + /// All bytes must be unique + DuplicatedByte(u8), + /// All bytes must be printable (in the range `[32, 126]`). + UnprintableByte(u8), + /// `=` cannot be used + ReservedByte(u8), +} + +impl fmt::Display for ParseAlphabetError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidLength => write!(f, "Invalid length - must be 64 bytes"), + Self::DuplicatedByte(b) => write!(f, "Duplicated byte: {:#04x}", b), + Self::UnprintableByte(b) => write!(f, "Unprintable byte: {:#04x}", b), + Self::ReservedByte(b) => write!(f, "Reserved byte: {:#04x}", b), + } + } +} + +#[cfg(any(feature = "std", test))] +impl error::Error for ParseAlphabetError {} + +/// The standard alphabet (uses `+` and `/`). +/// +/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3). +pub const STANDARD: Alphabet = Alphabet::from_str_unchecked( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", +); + +/// The URL safe alphabet (uses `-` and `_`). +/// +/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4). +pub const URL_SAFE: Alphabet = Alphabet::from_str_unchecked( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", +); + +/// The `crypt(3)` alphabet (uses `.` and `/` as the first two values). +/// +/// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses. +pub const CRYPT: Alphabet = Alphabet::from_str_unchecked( + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", +); + +/// The bcrypt alphabet. +pub const BCRYPT: Alphabet = Alphabet::from_str_unchecked( + "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", +); + +/// The alphabet used in IMAP-modified UTF-7 (uses `+` and `,`). +/// +/// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3) +pub const IMAP_MUTF7: Alphabet = Alphabet::from_str_unchecked( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,", +); + +/// The alphabet used in BinHex 4.0 files. +/// +/// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt) +pub const BIN_HEX: Alphabet = Alphabet::from_str_unchecked( + "!\"#$%&'()*+,-0123456789@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdehijklmpqr", +); + +#[cfg(test)] +mod tests { + use crate::alphabet::*; + use core::convert::TryFrom as _; + + #[test] + fn detects_duplicate_start() { + assert_eq!( + ParseAlphabetError::DuplicatedByte(b'A'), + Alphabet::new("AACDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + .unwrap_err() + ); + } + + #[test] + fn detects_duplicate_end() { + assert_eq!( + ParseAlphabetError::DuplicatedByte(b'/'), + Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789//") + .unwrap_err() + ); + } + + #[test] + fn detects_duplicate_middle() { + assert_eq!( + ParseAlphabetError::DuplicatedByte(b'Z'), + Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZZbcdefghijklmnopqrstuvwxyz0123456789+/") + .unwrap_err() + ); + } + + #[test] + fn detects_length() { + assert_eq!( + ParseAlphabetError::InvalidLength, + Alphabet::new( + "xxxxxxxxxABCDEFGHIJKLMNOPQRSTUVWXYZZbcdefghijklmnopqrstuvwxyz0123456789+/", + ) + .unwrap_err() + ); + } + + #[test] + fn detects_padding() { + assert_eq!( + ParseAlphabetError::ReservedByte(b'='), + Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+=") + .unwrap_err() + ); + } + + #[test] + fn detects_unprintable() { + // form feed + assert_eq!( + ParseAlphabetError::UnprintableByte(0xc), + Alphabet::new("\x0cBCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + .unwrap_err() + ); + } + + #[test] + fn same_as_unchecked() { + assert_eq!( + STANDARD, + Alphabet::try_from("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + .unwrap() + ); + } +} diff --git a/vendor/base64-0.21.5/src/chunked_encoder.rs b/vendor/base64-0.21.5/src/chunked_encoder.rs new file mode 100644 index 00000000..817b339f --- /dev/null +++ b/vendor/base64-0.21.5/src/chunked_encoder.rs @@ -0,0 +1,172 @@ +use crate::{ + encode::add_padding, + engine::{Config, Engine}, +}; +#[cfg(any(feature = "alloc", test))] +use alloc::string::String; +#[cfg(any(feature = "alloc", test))] +use core::str; + +/// The output mechanism for ChunkedEncoder's encoded bytes. +pub trait Sink { + type Error; + + /// Handle a chunk of encoded base64 data (as UTF-8 bytes) + fn write_encoded_bytes(&mut self, encoded: &[u8]) -> Result<(), Self::Error>; +} + +/// A base64 encoder that emits encoded bytes in chunks without heap allocation. +pub struct ChunkedEncoder<'e, E: Engine + ?Sized> { + engine: &'e E, +} + +impl<'e, E: Engine + ?Sized> ChunkedEncoder<'e, E> { + pub fn new(engine: &'e E) -> ChunkedEncoder<'e, E> { + ChunkedEncoder { engine } + } + + pub fn encode(&self, bytes: &[u8], sink: &mut S) -> Result<(), S::Error> { + const BUF_SIZE: usize = 1024; + const CHUNK_SIZE: usize = BUF_SIZE / 4 * 3; + + let mut buf = [0; BUF_SIZE]; + for chunk in bytes.chunks(CHUNK_SIZE) { + let mut len = self.engine.internal_encode(chunk, &mut buf); + if chunk.len() != CHUNK_SIZE && self.engine.config().encode_padding() { + // Final, potentially partial, chunk. + // Only need to consider if padding is needed on a partial chunk since full chunk + // is a multiple of 3, which therefore won't be padded. + // Pad output to multiple of four bytes if required by config. + len += add_padding(len, &mut buf[len..]); + } + sink.write_encoded_bytes(&buf[..len])?; + } + + Ok(()) + } +} + +// A really simple sink that just appends to a string +#[cfg(any(feature = "alloc", test))] +pub(crate) struct StringSink<'a> { + string: &'a mut String, +} + +#[cfg(any(feature = "alloc", test))] +impl<'a> StringSink<'a> { + pub(crate) fn new(s: &mut String) -> StringSink { + StringSink { string: s } + } +} + +#[cfg(any(feature = "alloc", test))] +impl<'a> Sink for StringSink<'a> { + type Error = (); + + fn write_encoded_bytes(&mut self, s: &[u8]) -> Result<(), Self::Error> { + self.string.push_str(str::from_utf8(s).unwrap()); + + Ok(()) + } +} + +#[cfg(test)] +pub mod tests { + use rand::{ + distributions::{Distribution, Uniform}, + Rng, SeedableRng, + }; + + use crate::{ + alphabet::STANDARD, + engine::general_purpose::{GeneralPurpose, GeneralPurposeConfig, PAD}, + tests::random_engine, + }; + + use super::*; + + #[test] + fn chunked_encode_empty() { + assert_eq!("", chunked_encode_str(&[], PAD)); + } + + #[test] + fn chunked_encode_intermediate_fast_loop() { + // > 8 bytes input, will enter the pretty fast loop + assert_eq!("Zm9vYmFyYmF6cXV4", chunked_encode_str(b"foobarbazqux", PAD)); + } + + #[test] + fn chunked_encode_fast_loop() { + // > 32 bytes input, will enter the uber fast loop + assert_eq!( + "Zm9vYmFyYmF6cXV4cXV1eGNvcmdlZ3JhdWx0Z2FycGx5eg==", + chunked_encode_str(b"foobarbazquxquuxcorgegraultgarplyz", PAD) + ); + } + + #[test] + fn chunked_encode_slow_loop_only() { + // < 8 bytes input, slow loop only + assert_eq!("Zm9vYmFy", chunked_encode_str(b"foobar", PAD)); + } + + #[test] + fn chunked_encode_matches_normal_encode_random_string_sink() { + let helper = StringSinkTestHelper; + chunked_encode_matches_normal_encode_random(&helper); + } + + pub fn chunked_encode_matches_normal_encode_random(sink_test_helper: &S) { + let mut input_buf: Vec = Vec::new(); + let mut output_buf = String::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + let input_len_range = Uniform::new(1, 10_000); + + for _ in 0..20_000 { + input_buf.clear(); + output_buf.clear(); + + let buf_len = input_len_range.sample(&mut rng); + for _ in 0..buf_len { + input_buf.push(rng.gen()); + } + + let engine = random_engine(&mut rng); + + let chunk_encoded_string = sink_test_helper.encode_to_string(&engine, &input_buf); + engine.encode_string(&input_buf, &mut output_buf); + + assert_eq!(output_buf, chunk_encoded_string, "input len={}", buf_len); + } + } + + fn chunked_encode_str(bytes: &[u8], config: GeneralPurposeConfig) -> String { + let mut s = String::new(); + + let mut sink = StringSink::new(&mut s); + let engine = GeneralPurpose::new(&STANDARD, config); + let encoder = ChunkedEncoder::new(&engine); + encoder.encode(bytes, &mut sink).unwrap(); + + s + } + + // An abstraction around sinks so that we can have tests that easily to any sink implementation + pub trait SinkTestHelper { + fn encode_to_string(&self, engine: &E, bytes: &[u8]) -> String; + } + + struct StringSinkTestHelper; + + impl SinkTestHelper for StringSinkTestHelper { + fn encode_to_string(&self, engine: &E, bytes: &[u8]) -> String { + let encoder = ChunkedEncoder::new(engine); + let mut s = String::new(); + let mut sink = StringSink::new(&mut s); + encoder.encode(bytes, &mut sink).unwrap(); + + s + } + } +} diff --git a/vendor/base64-0.21.5/src/decode.rs b/vendor/base64-0.21.5/src/decode.rs new file mode 100644 index 00000000..5230fd3c --- /dev/null +++ b/vendor/base64-0.21.5/src/decode.rs @@ -0,0 +1,340 @@ +use crate::engine::{general_purpose::STANDARD, DecodeEstimate, Engine}; +#[cfg(any(feature = "alloc", test))] +use alloc::vec::Vec; +use core::fmt; +#[cfg(any(feature = "std", test))] +use std::error; + +/// Errors that can occur while decoding. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum DecodeError { + /// An invalid byte was found in the input. The offset and offending byte are provided. + /// Padding characters (`=`) interspersed in the encoded form will be treated as invalid bytes. + InvalidByte(usize, u8), + /// The length of the input is invalid. + /// A typical cause of this is stray trailing whitespace or other separator bytes. + /// In the case where excess trailing bytes have produced an invalid length *and* the last byte + /// is also an invalid base64 symbol (as would be the case for whitespace, etc), `InvalidByte` + /// will be emitted instead of `InvalidLength` to make the issue easier to debug. + InvalidLength, + /// The last non-padding input symbol's encoded 6 bits have nonzero bits that will be discarded. + /// This is indicative of corrupted or truncated Base64. + /// Unlike `InvalidByte`, which reports symbols that aren't in the alphabet, this error is for + /// symbols that are in the alphabet but represent nonsensical encodings. + InvalidLastSymbol(usize, u8), + /// The nature of the padding was not as configured: absent or incorrect when it must be + /// canonical, or present when it must be absent, etc. + InvalidPadding, +} + +impl fmt::Display for DecodeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::InvalidByte(index, byte) => write!(f, "Invalid byte {}, offset {}.", byte, index), + Self::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder."), + Self::InvalidLastSymbol(index, byte) => { + write!(f, "Invalid last symbol {}, offset {}.", byte, index) + } + Self::InvalidPadding => write!(f, "Invalid padding"), + } + } +} + +#[cfg(any(feature = "std", test))] +impl error::Error for DecodeError {} + +/// Errors that can occur while decoding into a slice. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum DecodeSliceError { + /// A [DecodeError] occurred + DecodeError(DecodeError), + /// The provided slice _may_ be too small. + /// + /// The check is conservative (assumes the last triplet of output bytes will all be needed). + OutputSliceTooSmall, +} + +impl fmt::Display for DecodeSliceError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::DecodeError(e) => write!(f, "DecodeError: {}", e), + Self::OutputSliceTooSmall => write!(f, "Output slice too small"), + } + } +} + +#[cfg(any(feature = "std", test))] +impl error::Error for DecodeSliceError { + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match self { + DecodeSliceError::DecodeError(e) => Some(e), + DecodeSliceError::OutputSliceTooSmall => None, + } + } +} + +impl From for DecodeSliceError { + fn from(e: DecodeError) -> Self { + DecodeSliceError::DecodeError(e) + } +} + +/// Decode base64 using the [`STANDARD` engine](STANDARD). +/// +/// See [Engine::decode]. +#[deprecated(since = "0.21.0", note = "Use Engine::decode")] +#[cfg(any(feature = "alloc", test))] +pub fn decode>(input: T) -> Result, DecodeError> { + STANDARD.decode(input) +} + +/// Decode from string reference as octets using the specified [Engine]. +/// +/// See [Engine::decode]. +///Returns a `Result` containing a `Vec`. +#[deprecated(since = "0.21.0", note = "Use Engine::decode")] +#[cfg(any(feature = "alloc", test))] +pub fn decode_engine>( + input: T, + engine: &E, +) -> Result, DecodeError> { + engine.decode(input) +} + +/// Decode from string reference as octets. +/// +/// See [Engine::decode_vec]. +#[cfg(any(feature = "alloc", test))] +#[deprecated(since = "0.21.0", note = "Use Engine::decode_vec")] +pub fn decode_engine_vec>( + input: T, + buffer: &mut Vec, + engine: &E, +) -> Result<(), DecodeError> { + engine.decode_vec(input, buffer) +} + +/// Decode the input into the provided output slice. +/// +/// See [Engine::decode_slice]. +#[deprecated(since = "0.21.0", note = "Use Engine::decode_slice")] +pub fn decode_engine_slice>( + input: T, + output: &mut [u8], + engine: &E, +) -> Result { + engine.decode_slice(input, output) +} + +/// Returns a conservative estimate of the decoded size of `encoded_len` base64 symbols (rounded up +/// to the next group of 3 decoded bytes). +/// +/// The resulting length will be a safe choice for the size of a decode buffer, but may have up to +/// 2 trailing bytes that won't end up being needed. +/// +/// # Examples +/// +/// ``` +/// use base64::decoded_len_estimate; +/// +/// assert_eq!(3, decoded_len_estimate(1)); +/// assert_eq!(3, decoded_len_estimate(2)); +/// assert_eq!(3, decoded_len_estimate(3)); +/// assert_eq!(3, decoded_len_estimate(4)); +/// // start of the next quad of encoded symbols +/// assert_eq!(6, decoded_len_estimate(5)); +/// ``` +pub fn decoded_len_estimate(encoded_len: usize) -> usize { + STANDARD + .internal_decoded_len_estimate(encoded_len) + .decoded_len_estimate() +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + alphabet, + engine::{general_purpose, Config, GeneralPurpose}, + tests::{assert_encode_sanity, random_engine}, + }; + use rand::{ + distributions::{Distribution, Uniform}, + Rng, SeedableRng, + }; + + #[test] + fn decode_into_nonempty_vec_doesnt_clobber_existing_prefix() { + let mut orig_data = Vec::new(); + let mut encoded_data = String::new(); + let mut decoded_with_prefix = Vec::new(); + let mut decoded_without_prefix = Vec::new(); + let mut prefix = Vec::new(); + + let prefix_len_range = Uniform::new(0, 1000); + let input_len_range = Uniform::new(0, 1000); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + orig_data.clear(); + encoded_data.clear(); + decoded_with_prefix.clear(); + decoded_without_prefix.clear(); + prefix.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + orig_data.push(rng.gen()); + } + + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut encoded_data); + assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len); + + let prefix_len = prefix_len_range.sample(&mut rng); + + // fill the buf with a prefix + for _ in 0..prefix_len { + prefix.push(rng.gen()); + } + + decoded_with_prefix.resize(prefix_len, 0); + decoded_with_prefix.copy_from_slice(&prefix); + + // decode into the non-empty buf + engine + .decode_vec(&encoded_data, &mut decoded_with_prefix) + .unwrap(); + // also decode into the empty buf + engine + .decode_vec(&encoded_data, &mut decoded_without_prefix) + .unwrap(); + + assert_eq!( + prefix_len + decoded_without_prefix.len(), + decoded_with_prefix.len() + ); + assert_eq!(orig_data, decoded_without_prefix); + + // append plain decode onto prefix + prefix.append(&mut decoded_without_prefix); + + assert_eq!(prefix, decoded_with_prefix); + } + } + + #[test] + fn decode_slice_doesnt_clobber_existing_prefix_or_suffix() { + do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| { + e.decode_slice(input, output).unwrap() + }) + } + + #[test] + fn decode_slice_unchecked_doesnt_clobber_existing_prefix_or_suffix() { + do_decode_slice_doesnt_clobber_existing_prefix_or_suffix(|e, input, output| { + e.decode_slice_unchecked(input, output).unwrap() + }) + } + + #[test] + fn decode_engine_estimation_works_for_various_lengths() { + let engine = GeneralPurpose::new(&alphabet::STANDARD, general_purpose::NO_PAD); + for num_prefix_quads in 0..100 { + for suffix in &["AA", "AAA", "AAAA"] { + let mut prefix = "AAAA".repeat(num_prefix_quads); + prefix.push_str(suffix); + // make sure no overflow (and thus a panic) occurs + let res = engine.decode(prefix); + assert!(res.is_ok()); + } + } + } + + #[test] + fn decode_slice_output_length_errors() { + for num_quads in 1..100 { + let input = "AAAA".repeat(num_quads); + let mut vec = vec![0; (num_quads - 1) * 3]; + assert_eq!( + DecodeSliceError::OutputSliceTooSmall, + STANDARD.decode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + assert_eq!( + DecodeSliceError::OutputSliceTooSmall, + STANDARD.decode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + assert_eq!( + DecodeSliceError::OutputSliceTooSmall, + STANDARD.decode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + // now it works + assert_eq!( + num_quads * 3, + STANDARD.decode_slice(&input, &mut vec).unwrap() + ); + } + } + + fn do_decode_slice_doesnt_clobber_existing_prefix_or_suffix< + F: Fn(&GeneralPurpose, &[u8], &mut [u8]) -> usize, + >( + call_decode: F, + ) { + let mut orig_data = Vec::new(); + let mut encoded_data = String::new(); + let mut decode_buf = Vec::new(); + let mut decode_buf_copy: Vec = Vec::new(); + + let input_len_range = Uniform::new(0, 1000); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + orig_data.clear(); + encoded_data.clear(); + decode_buf.clear(); + decode_buf_copy.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + orig_data.push(rng.gen()); + } + + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut encoded_data); + assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len); + + // fill the buffer with random garbage, long enough to have some room before and after + for _ in 0..5000 { + decode_buf.push(rng.gen()); + } + + // keep a copy for later comparison + decode_buf_copy.extend(decode_buf.iter()); + + let offset = 1000; + + // decode into the non-empty buf + let decode_bytes_written = + call_decode(&engine, encoded_data.as_bytes(), &mut decode_buf[offset..]); + + assert_eq!(orig_data.len(), decode_bytes_written); + assert_eq!( + orig_data, + &decode_buf[offset..(offset + decode_bytes_written)] + ); + assert_eq!(&decode_buf_copy[0..offset], &decode_buf[0..offset]); + assert_eq!( + &decode_buf_copy[offset + decode_bytes_written..], + &decode_buf[offset + decode_bytes_written..] + ); + } + } +} diff --git a/vendor/base64-0.21.5/src/display.rs b/vendor/base64-0.21.5/src/display.rs new file mode 100644 index 00000000..fc292f1b --- /dev/null +++ b/vendor/base64-0.21.5/src/display.rs @@ -0,0 +1,88 @@ +//! Enables base64'd output anywhere you might use a `Display` implementation, like a format string. +//! +//! ``` +//! use base64::{display::Base64Display, engine::general_purpose::STANDARD}; +//! +//! let data = vec![0x0, 0x1, 0x2, 0x3]; +//! let wrapper = Base64Display::new(&data, &STANDARD); +//! +//! assert_eq!("base64: AAECAw==", format!("base64: {}", wrapper)); +//! ``` + +use super::chunked_encoder::ChunkedEncoder; +use crate::engine::Engine; +use core::fmt::{Display, Formatter}; +use core::{fmt, str}; + +/// A convenience wrapper for base64'ing bytes into a format string without heap allocation. +pub struct Base64Display<'a, 'e, E: Engine> { + bytes: &'a [u8], + chunked_encoder: ChunkedEncoder<'e, E>, +} + +impl<'a, 'e, E: Engine> Base64Display<'a, 'e, E> { + /// Create a `Base64Display` with the provided engine. + pub fn new(bytes: &'a [u8], engine: &'e E) -> Base64Display<'a, 'e, E> { + Base64Display { + bytes, + chunked_encoder: ChunkedEncoder::new(engine), + } + } +} + +impl<'a, 'e, E: Engine> Display for Base64Display<'a, 'e, E> { + fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> { + let mut sink = FormatterSink { f: formatter }; + self.chunked_encoder.encode(self.bytes, &mut sink) + } +} + +struct FormatterSink<'a, 'b: 'a> { + f: &'a mut Formatter<'b>, +} + +impl<'a, 'b: 'a> super::chunked_encoder::Sink for FormatterSink<'a, 'b> { + type Error = fmt::Error; + + fn write_encoded_bytes(&mut self, encoded: &[u8]) -> Result<(), Self::Error> { + // Avoid unsafe. If max performance is needed, write your own display wrapper that uses + // unsafe here to gain about 10-15%. + self.f + .write_str(str::from_utf8(encoded).expect("base64 data was not utf8")) + } +} + +#[cfg(test)] +mod tests { + use super::super::chunked_encoder::tests::{ + chunked_encode_matches_normal_encode_random, SinkTestHelper, + }; + use super::*; + use crate::engine::general_purpose::STANDARD; + + #[test] + fn basic_display() { + assert_eq!( + "~$Zm9vYmFy#*", + format!("~${}#*", Base64Display::new(b"foobar", &STANDARD)) + ); + assert_eq!( + "~$Zm9vYmFyZg==#*", + format!("~${}#*", Base64Display::new(b"foobarf", &STANDARD)) + ); + } + + #[test] + fn display_encode_matches_normal_encode() { + let helper = DisplaySinkTestHelper; + chunked_encode_matches_normal_encode_random(&helper); + } + + struct DisplaySinkTestHelper; + + impl SinkTestHelper for DisplaySinkTestHelper { + fn encode_to_string(&self, engine: &E, bytes: &[u8]) -> String { + format!("{}", Base64Display::new(bytes, engine)) + } + } +} diff --git a/vendor/base64-0.21.5/src/encode.rs b/vendor/base64-0.21.5/src/encode.rs new file mode 100644 index 00000000..88e64992 --- /dev/null +++ b/vendor/base64-0.21.5/src/encode.rs @@ -0,0 +1,491 @@ +#[cfg(any(feature = "alloc", test))] +use alloc::string::String; +use core::fmt; +#[cfg(any(feature = "std", test))] +use std::error; + +#[cfg(any(feature = "alloc", test))] +use crate::engine::general_purpose::STANDARD; +use crate::engine::{Config, Engine}; +use crate::PAD_BYTE; + +/// Encode arbitrary octets as base64 using the [`STANDARD` engine](STANDARD). +/// +/// See [Engine::encode]. +#[allow(unused)] +#[deprecated(since = "0.21.0", note = "Use Engine::encode")] +#[cfg(any(feature = "alloc", test))] +pub fn encode>(input: T) -> String { + STANDARD.encode(input) +} + +///Encode arbitrary octets as base64 using the provided `Engine` into a new `String`. +/// +/// See [Engine::encode]. +#[allow(unused)] +#[deprecated(since = "0.21.0", note = "Use Engine::encode")] +#[cfg(any(feature = "alloc", test))] +pub fn encode_engine>(input: T, engine: &E) -> String { + engine.encode(input) +} + +///Encode arbitrary octets as base64 into a supplied `String`. +/// +/// See [Engine::encode_string]. +#[allow(unused)] +#[deprecated(since = "0.21.0", note = "Use Engine::encode_string")] +#[cfg(any(feature = "alloc", test))] +pub fn encode_engine_string>( + input: T, + output_buf: &mut String, + engine: &E, +) { + engine.encode_string(input, output_buf) +} + +/// Encode arbitrary octets as base64 into a supplied slice. +/// +/// See [Engine::encode_slice]. +#[allow(unused)] +#[deprecated(since = "0.21.0", note = "Use Engine::encode_slice")] +pub fn encode_engine_slice>( + input: T, + output_buf: &mut [u8], + engine: &E, +) -> Result { + engine.encode_slice(input, output_buf) +} + +/// B64-encode and pad (if configured). +/// +/// This helper exists to avoid recalculating encoded_size, which is relatively expensive on short +/// inputs. +/// +/// `encoded_size` is the encoded size calculated for `input`. +/// +/// `output` must be of size `encoded_size`. +/// +/// All bytes in `output` will be written to since it is exactly the size of the output. +pub(crate) fn encode_with_padding( + input: &[u8], + output: &mut [u8], + engine: &E, + expected_encoded_size: usize, +) { + debug_assert_eq!(expected_encoded_size, output.len()); + + let b64_bytes_written = engine.internal_encode(input, output); + + let padding_bytes = if engine.config().encode_padding() { + add_padding(b64_bytes_written, &mut output[b64_bytes_written..]) + } else { + 0 + }; + + let encoded_bytes = b64_bytes_written + .checked_add(padding_bytes) + .expect("usize overflow when calculating b64 length"); + + debug_assert_eq!(expected_encoded_size, encoded_bytes); +} + +/// Calculate the base64 encoded length for a given input length, optionally including any +/// appropriate padding bytes. +/// +/// Returns `None` if the encoded length can't be represented in `usize`. This will happen for +/// input lengths in approximately the top quarter of the range of `usize`. +pub const fn encoded_len(bytes_len: usize, padding: bool) -> Option { + let rem = bytes_len % 3; + + let complete_input_chunks = bytes_len / 3; + // `let Some(_) = _ else` requires 1.65.0, whereas this messier one works on 1.48 + let complete_chunk_output = + if let Some(complete_chunk_output) = complete_input_chunks.checked_mul(4) { + complete_chunk_output + } else { + return None; + }; + + if rem > 0 { + if padding { + complete_chunk_output.checked_add(4) + } else { + let encoded_rem = match rem { + 1 => 2, + // only other possible remainder is 2 + // can't use a separate _ => unreachable!() in const fns in ancient rust versions + _ => 3, + }; + complete_chunk_output.checked_add(encoded_rem) + } + } else { + Some(complete_chunk_output) + } +} + +/// Write padding characters. +/// `unpadded_output_len` is the size of the unpadded but base64 encoded data. +/// `output` is the slice where padding should be written, of length at least 2. +/// +/// Returns the number of padding bytes written. +pub(crate) fn add_padding(unpadded_output_len: usize, output: &mut [u8]) -> usize { + let pad_bytes = (4 - (unpadded_output_len % 4)) % 4; + // for just a couple bytes, this has better performance than using + // .fill(), or iterating over mutable refs, which call memset() + #[allow(clippy::needless_range_loop)] + for i in 0..pad_bytes { + output[i] = PAD_BYTE; + } + + pad_bytes +} + +/// Errors that can occur while encoding into a slice. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum EncodeSliceError { + /// The provided slice is too small. + OutputSliceTooSmall, +} + +impl fmt::Display for EncodeSliceError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::OutputSliceTooSmall => write!(f, "Output slice too small"), + } + } +} + +#[cfg(any(feature = "std", test))] +impl error::Error for EncodeSliceError {} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::{ + alphabet, + engine::general_purpose::{GeneralPurpose, NO_PAD, STANDARD}, + tests::{assert_encode_sanity, random_config, random_engine}, + }; + use rand::{ + distributions::{Distribution, Uniform}, + Rng, SeedableRng, + }; + use std::str; + + const URL_SAFE_NO_PAD_ENGINE: GeneralPurpose = GeneralPurpose::new(&alphabet::URL_SAFE, NO_PAD); + + #[test] + fn encoded_size_correct_standard() { + assert_encoded_length(0, 0, &STANDARD, true); + + assert_encoded_length(1, 4, &STANDARD, true); + assert_encoded_length(2, 4, &STANDARD, true); + assert_encoded_length(3, 4, &STANDARD, true); + + assert_encoded_length(4, 8, &STANDARD, true); + assert_encoded_length(5, 8, &STANDARD, true); + assert_encoded_length(6, 8, &STANDARD, true); + + assert_encoded_length(7, 12, &STANDARD, true); + assert_encoded_length(8, 12, &STANDARD, true); + assert_encoded_length(9, 12, &STANDARD, true); + + assert_encoded_length(54, 72, &STANDARD, true); + + assert_encoded_length(55, 76, &STANDARD, true); + assert_encoded_length(56, 76, &STANDARD, true); + assert_encoded_length(57, 76, &STANDARD, true); + + assert_encoded_length(58, 80, &STANDARD, true); + } + + #[test] + fn encoded_size_correct_no_pad() { + assert_encoded_length(0, 0, &URL_SAFE_NO_PAD_ENGINE, false); + + assert_encoded_length(1, 2, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(2, 3, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(3, 4, &URL_SAFE_NO_PAD_ENGINE, false); + + assert_encoded_length(4, 6, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(5, 7, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(6, 8, &URL_SAFE_NO_PAD_ENGINE, false); + + assert_encoded_length(7, 10, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(8, 11, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(9, 12, &URL_SAFE_NO_PAD_ENGINE, false); + + assert_encoded_length(54, 72, &URL_SAFE_NO_PAD_ENGINE, false); + + assert_encoded_length(55, 74, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(56, 75, &URL_SAFE_NO_PAD_ENGINE, false); + assert_encoded_length(57, 76, &URL_SAFE_NO_PAD_ENGINE, false); + + assert_encoded_length(58, 78, &URL_SAFE_NO_PAD_ENGINE, false); + } + + #[test] + fn encoded_size_overflow() { + assert_eq!(None, encoded_len(usize::MAX, true)); + } + + #[test] + fn encode_engine_string_into_nonempty_buffer_doesnt_clobber_prefix() { + let mut orig_data = Vec::new(); + let mut prefix = String::new(); + let mut encoded_data_no_prefix = String::new(); + let mut encoded_data_with_prefix = String::new(); + let mut decoded = Vec::new(); + + let prefix_len_range = Uniform::new(0, 1000); + let input_len_range = Uniform::new(0, 1000); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + orig_data.clear(); + prefix.clear(); + encoded_data_no_prefix.clear(); + encoded_data_with_prefix.clear(); + decoded.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + orig_data.push(rng.gen()); + } + + let prefix_len = prefix_len_range.sample(&mut rng); + for _ in 0..prefix_len { + // getting convenient random single-byte printable chars that aren't base64 is + // annoying + prefix.push('#'); + } + encoded_data_with_prefix.push_str(&prefix); + + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut encoded_data_no_prefix); + engine.encode_string(&orig_data, &mut encoded_data_with_prefix); + + assert_eq!( + encoded_data_no_prefix.len() + prefix_len, + encoded_data_with_prefix.len() + ); + assert_encode_sanity( + &encoded_data_no_prefix, + engine.config().encode_padding(), + input_len, + ); + assert_encode_sanity( + &encoded_data_with_prefix[prefix_len..], + engine.config().encode_padding(), + input_len, + ); + + // append plain encode onto prefix + prefix.push_str(&encoded_data_no_prefix); + + assert_eq!(prefix, encoded_data_with_prefix); + + engine + .decode_vec(&encoded_data_no_prefix, &mut decoded) + .unwrap(); + assert_eq!(orig_data, decoded); + } + } + + #[test] + fn encode_engine_slice_into_nonempty_buffer_doesnt_clobber_suffix() { + let mut orig_data = Vec::new(); + let mut encoded_data = Vec::new(); + let mut encoded_data_original_state = Vec::new(); + let mut decoded = Vec::new(); + + let input_len_range = Uniform::new(0, 1000); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + orig_data.clear(); + encoded_data.clear(); + encoded_data_original_state.clear(); + decoded.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + orig_data.push(rng.gen()); + } + + // plenty of existing garbage in the encoded buffer + for _ in 0..10 * input_len { + encoded_data.push(rng.gen()); + } + + encoded_data_original_state.extend_from_slice(&encoded_data); + + let engine = random_engine(&mut rng); + + let encoded_size = encoded_len(input_len, engine.config().encode_padding()).unwrap(); + + assert_eq!( + encoded_size, + engine.encode_slice(&orig_data, &mut encoded_data).unwrap() + ); + + assert_encode_sanity( + str::from_utf8(&encoded_data[0..encoded_size]).unwrap(), + engine.config().encode_padding(), + input_len, + ); + + assert_eq!( + &encoded_data[encoded_size..], + &encoded_data_original_state[encoded_size..] + ); + + engine + .decode_vec(&encoded_data[0..encoded_size], &mut decoded) + .unwrap(); + assert_eq!(orig_data, decoded); + } + } + + #[test] + fn encode_to_slice_random_valid_utf8() { + let mut input = Vec::new(); + let mut output = Vec::new(); + + let input_len_range = Uniform::new(0, 1000); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + input.clear(); + output.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + input.push(rng.gen()); + } + + let config = random_config(&mut rng); + let engine = random_engine(&mut rng); + + // fill up the output buffer with garbage + let encoded_size = encoded_len(input_len, config.encode_padding()).unwrap(); + for _ in 0..encoded_size { + output.push(rng.gen()); + } + + let orig_output_buf = output.clone(); + + let bytes_written = engine.internal_encode(&input, &mut output); + + // make sure the part beyond bytes_written is the same garbage it was before + assert_eq!(orig_output_buf[bytes_written..], output[bytes_written..]); + + // make sure the encoded bytes are UTF-8 + let _ = str::from_utf8(&output[0..bytes_written]).unwrap(); + } + } + + #[test] + fn encode_with_padding_random_valid_utf8() { + let mut input = Vec::new(); + let mut output = Vec::new(); + + let input_len_range = Uniform::new(0, 1000); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + input.clear(); + output.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + input.push(rng.gen()); + } + + let engine = random_engine(&mut rng); + + // fill up the output buffer with garbage + let encoded_size = encoded_len(input_len, engine.config().encode_padding()).unwrap(); + for _ in 0..encoded_size + 1000 { + output.push(rng.gen()); + } + + let orig_output_buf = output.clone(); + + encode_with_padding(&input, &mut output[0..encoded_size], &engine, encoded_size); + + // make sure the part beyond b64 is the same garbage it was before + assert_eq!(orig_output_buf[encoded_size..], output[encoded_size..]); + + // make sure the encoded bytes are UTF-8 + let _ = str::from_utf8(&output[0..encoded_size]).unwrap(); + } + } + + #[test] + fn add_padding_random_valid_utf8() { + let mut output = Vec::new(); + + let mut rng = rand::rngs::SmallRng::from_entropy(); + + // cover our bases for length % 4 + for unpadded_output_len in 0..20 { + output.clear(); + + // fill output with random + for _ in 0..100 { + output.push(rng.gen()); + } + + let orig_output_buf = output.clone(); + + let bytes_written = add_padding(unpadded_output_len, &mut output); + + // make sure the part beyond bytes_written is the same garbage it was before + assert_eq!(orig_output_buf[bytes_written..], output[bytes_written..]); + + // make sure the encoded bytes are UTF-8 + let _ = str::from_utf8(&output[0..bytes_written]).unwrap(); + } + } + + fn assert_encoded_length( + input_len: usize, + enc_len: usize, + engine: &E, + padded: bool, + ) { + assert_eq!(enc_len, encoded_len(input_len, padded).unwrap()); + + let mut bytes: Vec = Vec::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..input_len { + bytes.push(rng.gen()); + } + + let encoded = engine.encode(&bytes); + assert_encode_sanity(&encoded, padded, input_len); + + assert_eq!(enc_len, encoded.len()); + } + + #[test] + fn encode_imap() { + assert_eq!( + &GeneralPurpose::new(&alphabet::IMAP_MUTF7, NO_PAD).encode(b"\xFB\xFF"), + &GeneralPurpose::new(&alphabet::STANDARD, NO_PAD) + .encode(b"\xFB\xFF") + .replace('/', ",") + ); + } +} diff --git a/vendor/base64-0.21.5/src/engine/general_purpose/decode.rs b/vendor/base64-0.21.5/src/engine/general_purpose/decode.rs new file mode 100644 index 00000000..21a386fd --- /dev/null +++ b/vendor/base64-0.21.5/src/engine/general_purpose/decode.rs @@ -0,0 +1,383 @@ +use crate::{ + engine::{general_purpose::INVALID_VALUE, DecodeEstimate, DecodeMetadata, DecodePaddingMode}, + DecodeError, PAD_BYTE, +}; + +// decode logic operates on chunks of 8 input bytes without padding +const INPUT_CHUNK_LEN: usize = 8; +const DECODED_CHUNK_LEN: usize = 6; + +// we read a u64 and write a u64, but a u64 of input only yields 6 bytes of output, so the last +// 2 bytes of any output u64 should not be counted as written to (but must be available in a +// slice). +const DECODED_CHUNK_SUFFIX: usize = 2; + +// how many u64's of input to handle at a time +const CHUNKS_PER_FAST_LOOP_BLOCK: usize = 4; + +const INPUT_BLOCK_LEN: usize = CHUNKS_PER_FAST_LOOP_BLOCK * INPUT_CHUNK_LEN; + +// includes the trailing 2 bytes for the final u64 write +const DECODED_BLOCK_LEN: usize = + CHUNKS_PER_FAST_LOOP_BLOCK * DECODED_CHUNK_LEN + DECODED_CHUNK_SUFFIX; + +#[doc(hidden)] +pub struct GeneralPurposeEstimate { + /// Total number of decode chunks, including a possibly partial last chunk + num_chunks: usize, + decoded_len_estimate: usize, +} + +impl GeneralPurposeEstimate { + pub(crate) fn new(encoded_len: usize) -> Self { + // Formulas that won't overflow + Self { + num_chunks: encoded_len / INPUT_CHUNK_LEN + + (encoded_len % INPUT_CHUNK_LEN > 0) as usize, + decoded_len_estimate: (encoded_len / 4 + (encoded_len % 4 > 0) as usize) * 3, + } + } +} + +impl DecodeEstimate for GeneralPurposeEstimate { + fn decoded_len_estimate(&self) -> usize { + self.decoded_len_estimate + } +} + +/// Helper to avoid duplicating num_chunks calculation, which is costly on short inputs. +/// Returns the decode metadata, or an error. +// We're on the fragile edge of compiler heuristics here. If this is not inlined, slow. If this is +// inlined(always), a different slow. plain ol' inline makes the benchmarks happiest at the moment, +// but this is fragile and the best setting changes with only minor code modifications. +#[inline] +pub(crate) fn decode_helper( + input: &[u8], + estimate: GeneralPurposeEstimate, + output: &mut [u8], + decode_table: &[u8; 256], + decode_allow_trailing_bits: bool, + padding_mode: DecodePaddingMode, +) -> Result { + let remainder_len = input.len() % INPUT_CHUNK_LEN; + + // Because the fast decode loop writes in groups of 8 bytes (unrolled to + // CHUNKS_PER_FAST_LOOP_BLOCK times 8 bytes, where possible) and outputs 8 bytes at a time (of + // which only 6 are valid data), we need to be sure that we stop using the fast decode loop + // soon enough that there will always be 2 more bytes of valid data written after that loop. + let trailing_bytes_to_skip = match remainder_len { + // if input is a multiple of the chunk size, ignore the last chunk as it may have padding, + // and the fast decode logic cannot handle padding + 0 => INPUT_CHUNK_LEN, + // 1 and 5 trailing bytes are illegal: can't decode 6 bits of input into a byte + 1 | 5 => { + // trailing whitespace is so common that it's worth it to check the last byte to + // possibly return a better error message + if let Some(b) = input.last() { + if *b != PAD_BYTE && decode_table[*b as usize] == INVALID_VALUE { + return Err(DecodeError::InvalidByte(input.len() - 1, *b)); + } + } + + return Err(DecodeError::InvalidLength); + } + // This will decode to one output byte, which isn't enough to overwrite the 2 extra bytes + // written by the fast decode loop. So, we have to ignore both these 2 bytes and the + // previous chunk. + 2 => INPUT_CHUNK_LEN + 2, + // If this is 3 un-padded chars, then it would actually decode to 2 bytes. However, if this + // is an erroneous 2 chars + 1 pad char that would decode to 1 byte, then it should fail + // with an error, not panic from going past the bounds of the output slice, so we let it + // use stage 3 + 4. + 3 => INPUT_CHUNK_LEN + 3, + // This can also decode to one output byte because it may be 2 input chars + 2 padding + // chars, which would decode to 1 byte. + 4 => INPUT_CHUNK_LEN + 4, + // Everything else is a legal decode len (given that we don't require padding), and will + // decode to at least 2 bytes of output. + _ => remainder_len, + }; + + // rounded up to include partial chunks + let mut remaining_chunks = estimate.num_chunks; + + let mut input_index = 0; + let mut output_index = 0; + + { + let length_of_fast_decode_chunks = input.len().saturating_sub(trailing_bytes_to_skip); + + // Fast loop, stage 1 + // manual unroll to CHUNKS_PER_FAST_LOOP_BLOCK of u64s to amortize slice bounds checks + if let Some(max_start_index) = length_of_fast_decode_chunks.checked_sub(INPUT_BLOCK_LEN) { + while input_index <= max_start_index { + let input_slice = &input[input_index..(input_index + INPUT_BLOCK_LEN)]; + let output_slice = &mut output[output_index..(output_index + DECODED_BLOCK_LEN)]; + + decode_chunk( + &input_slice[0..], + input_index, + decode_table, + &mut output_slice[0..], + )?; + decode_chunk( + &input_slice[8..], + input_index + 8, + decode_table, + &mut output_slice[6..], + )?; + decode_chunk( + &input_slice[16..], + input_index + 16, + decode_table, + &mut output_slice[12..], + )?; + decode_chunk( + &input_slice[24..], + input_index + 24, + decode_table, + &mut output_slice[18..], + )?; + + input_index += INPUT_BLOCK_LEN; + output_index += DECODED_BLOCK_LEN - DECODED_CHUNK_SUFFIX; + remaining_chunks -= CHUNKS_PER_FAST_LOOP_BLOCK; + } + } + + // Fast loop, stage 2 (aka still pretty fast loop) + // 8 bytes at a time for whatever we didn't do in stage 1. + if let Some(max_start_index) = length_of_fast_decode_chunks.checked_sub(INPUT_CHUNK_LEN) { + while input_index < max_start_index { + decode_chunk( + &input[input_index..(input_index + INPUT_CHUNK_LEN)], + input_index, + decode_table, + &mut output + [output_index..(output_index + DECODED_CHUNK_LEN + DECODED_CHUNK_SUFFIX)], + )?; + + output_index += DECODED_CHUNK_LEN; + input_index += INPUT_CHUNK_LEN; + remaining_chunks -= 1; + } + } + } + + // Stage 3 + // If input length was such that a chunk had to be deferred until after the fast loop + // because decoding it would have produced 2 trailing bytes that wouldn't then be + // overwritten, we decode that chunk here. This way is slower but doesn't write the 2 + // trailing bytes. + // However, we still need to avoid the last chunk (partial or complete) because it could + // have padding, so we always do 1 fewer to avoid the last chunk. + for _ in 1..remaining_chunks { + decode_chunk_precise( + &input[input_index..], + input_index, + decode_table, + &mut output[output_index..(output_index + DECODED_CHUNK_LEN)], + )?; + + input_index += INPUT_CHUNK_LEN; + output_index += DECODED_CHUNK_LEN; + } + + // always have one more (possibly partial) block of 8 input + debug_assert!(input.len() - input_index > 1 || input.is_empty()); + debug_assert!(input.len() - input_index <= 8); + + super::decode_suffix::decode_suffix( + input, + input_index, + output, + output_index, + decode_table, + decode_allow_trailing_bits, + padding_mode, + ) +} + +/// Decode 8 bytes of input into 6 bytes of output. 8 bytes of output will be written, but only the +/// first 6 of those contain meaningful data. +/// +/// `input` is the bytes to decode, of which the first 8 bytes will be processed. +/// `index_at_start_of_input` is the offset in the overall input (used for reporting errors +/// accurately) +/// `decode_table` is the lookup table for the particular base64 alphabet. +/// `output` will have its first 8 bytes overwritten, of which only the first 6 are valid decoded +/// data. +// yes, really inline (worth 30-50% speedup) +#[inline(always)] +fn decode_chunk( + input: &[u8], + index_at_start_of_input: usize, + decode_table: &[u8; 256], + output: &mut [u8], +) -> Result<(), DecodeError> { + let morsel = decode_table[input[0] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte(index_at_start_of_input, input[0])); + } + let mut accum = (morsel as u64) << 58; + + let morsel = decode_table[input[1] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 1, + input[1], + )); + } + accum |= (morsel as u64) << 52; + + let morsel = decode_table[input[2] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 2, + input[2], + )); + } + accum |= (morsel as u64) << 46; + + let morsel = decode_table[input[3] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 3, + input[3], + )); + } + accum |= (morsel as u64) << 40; + + let morsel = decode_table[input[4] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 4, + input[4], + )); + } + accum |= (morsel as u64) << 34; + + let morsel = decode_table[input[5] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 5, + input[5], + )); + } + accum |= (morsel as u64) << 28; + + let morsel = decode_table[input[6] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 6, + input[6], + )); + } + accum |= (morsel as u64) << 22; + + let morsel = decode_table[input[7] as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 7, + input[7], + )); + } + accum |= (morsel as u64) << 16; + + write_u64(output, accum); + + Ok(()) +} + +/// Decode an 8-byte chunk, but only write the 6 bytes actually decoded instead of including 2 +/// trailing garbage bytes. +#[inline] +fn decode_chunk_precise( + input: &[u8], + index_at_start_of_input: usize, + decode_table: &[u8; 256], + output: &mut [u8], +) -> Result<(), DecodeError> { + let mut tmp_buf = [0_u8; 8]; + + decode_chunk( + input, + index_at_start_of_input, + decode_table, + &mut tmp_buf[..], + )?; + + output[0..6].copy_from_slice(&tmp_buf[0..6]); + + Ok(()) +} + +#[inline] +fn write_u64(output: &mut [u8], value: u64) { + output[..8].copy_from_slice(&value.to_be_bytes()); +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::engine::general_purpose::STANDARD; + + #[test] + fn decode_chunk_precise_writes_only_6_bytes() { + let input = b"Zm9vYmFy"; // "foobar" + let mut output = [0_u8, 1, 2, 3, 4, 5, 6, 7]; + + decode_chunk_precise(&input[..], 0, &STANDARD.decode_table, &mut output).unwrap(); + assert_eq!(&vec![b'f', b'o', b'o', b'b', b'a', b'r', 6, 7], &output); + } + + #[test] + fn decode_chunk_writes_8_bytes() { + let input = b"Zm9vYmFy"; // "foobar" + let mut output = [0_u8, 1, 2, 3, 4, 5, 6, 7]; + + decode_chunk(&input[..], 0, &STANDARD.decode_table, &mut output).unwrap(); + assert_eq!(&vec![b'f', b'o', b'o', b'b', b'a', b'r', 0, 0], &output); + } + + #[test] + fn estimate_short_lengths() { + for (range, (num_chunks, decoded_len_estimate)) in [ + (0..=0, (0, 0)), + (1..=4, (1, 3)), + (5..=8, (1, 6)), + (9..=12, (2, 9)), + (13..=16, (2, 12)), + (17..=20, (3, 15)), + ] { + for encoded_len in range { + let estimate = GeneralPurposeEstimate::new(encoded_len); + assert_eq!(num_chunks, estimate.num_chunks); + assert_eq!(decoded_len_estimate, estimate.decoded_len_estimate); + } + } + } + + #[test] + fn estimate_via_u128_inflation() { + // cover both ends of usize + (0..1000) + .chain(usize::MAX - 1000..=usize::MAX) + .for_each(|encoded_len| { + // inflate to 128 bit type to be able to safely use the easy formulas + let len_128 = encoded_len as u128; + + let estimate = GeneralPurposeEstimate::new(encoded_len); + assert_eq!( + ((len_128 + (INPUT_CHUNK_LEN - 1) as u128) / (INPUT_CHUNK_LEN as u128)) + as usize, + estimate.num_chunks + ); + assert_eq!( + ((len_128 + 3) / 4 * 3) as usize, + estimate.decoded_len_estimate + ); + }) + } +} diff --git a/vendor/base64-0.21.5/src/engine/general_purpose/decode_suffix.rs b/vendor/base64-0.21.5/src/engine/general_purpose/decode_suffix.rs new file mode 100644 index 00000000..e1e005d2 --- /dev/null +++ b/vendor/base64-0.21.5/src/engine/general_purpose/decode_suffix.rs @@ -0,0 +1,168 @@ +use crate::{ + engine::{general_purpose::INVALID_VALUE, DecodeMetadata, DecodePaddingMode}, + DecodeError, PAD_BYTE, +}; + +/// Decode the last 1-8 bytes, checking for trailing set bits and padding per the provided +/// parameters. +/// +/// Returns the decode metadata representing the total number of bytes decoded, including the ones +/// indicated as already written by `output_index`. +pub(crate) fn decode_suffix( + input: &[u8], + input_index: usize, + output: &mut [u8], + mut output_index: usize, + decode_table: &[u8; 256], + decode_allow_trailing_bits: bool, + padding_mode: DecodePaddingMode, +) -> Result { + // Decode any leftovers that aren't a complete input block of 8 bytes. + // Use a u64 as a stack-resident 8 byte buffer. + let mut leftover_bits: u64 = 0; + let mut morsels_in_leftover = 0; + let mut padding_bytes = 0; + let mut first_padding_index: usize = 0; + let mut last_symbol = 0_u8; + let start_of_leftovers = input_index; + + for (i, &b) in input[start_of_leftovers..].iter().enumerate() { + // '=' padding + if b == PAD_BYTE { + // There can be bad padding bytes in a few ways: + // 1 - Padding with non-padding characters after it + // 2 - Padding after zero or one characters in the current quad (should only + // be after 2 or 3 chars) + // 3 - More than two characters of padding. If 3 or 4 padding chars + // are in the same quad, that implies it will be caught by #2. + // If it spreads from one quad to another, it will be an invalid byte + // in the first quad. + // 4 - Non-canonical padding -- 1 byte when it should be 2, etc. + // Per config, non-canonical but still functional non- or partially-padded base64 + // may be treated as an error condition. + + if i % 4 < 2 { + // Check for case #2. + let bad_padding_index = start_of_leftovers + + if padding_bytes > 0 { + // If we've already seen padding, report the first padding index. + // This is to be consistent with the normal decode logic: it will report an + // error on the first padding character (since it doesn't expect to see + // anything but actual encoded data). + // This could only happen if the padding started in the previous quad since + // otherwise this case would have been hit at i % 4 == 0 if it was the same + // quad. + first_padding_index + } else { + // haven't seen padding before, just use where we are now + i + }; + return Err(DecodeError::InvalidByte(bad_padding_index, b)); + } + + if padding_bytes == 0 { + first_padding_index = i; + } + + padding_bytes += 1; + continue; + } + + // Check for case #1. + // To make '=' handling consistent with the main loop, don't allow + // non-suffix '=' in trailing chunk either. Report error as first + // erroneous padding. + if padding_bytes > 0 { + return Err(DecodeError::InvalidByte( + start_of_leftovers + first_padding_index, + PAD_BYTE, + )); + } + + last_symbol = b; + + // can use up to 8 * 6 = 48 bits of the u64, if last chunk has no padding. + // Pack the leftovers from left to right. + let shift = 64 - (morsels_in_leftover + 1) * 6; + let morsel = decode_table[b as usize]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte(start_of_leftovers + i, b)); + } + + leftover_bits |= (morsel as u64) << shift; + morsels_in_leftover += 1; + } + + match padding_mode { + DecodePaddingMode::Indifferent => { /* everything we care about was already checked */ } + DecodePaddingMode::RequireCanonical => { + if (padding_bytes + morsels_in_leftover) % 4 != 0 { + return Err(DecodeError::InvalidPadding); + } + } + DecodePaddingMode::RequireNone => { + if padding_bytes > 0 { + // check at the end to make sure we let the cases of padding that should be InvalidByte + // get hit + return Err(DecodeError::InvalidPadding); + } + } + } + + // When encoding 1 trailing byte (e.g. 0xFF), 2 base64 bytes ("/w") are needed. + // / is the symbol for 63 (0x3F, bottom 6 bits all set) and w is 48 (0x30, top 2 bits + // of bottom 6 bits set). + // When decoding two symbols back to one trailing byte, any final symbol higher than + // w would still decode to the original byte because we only care about the top two + // bits in the bottom 6, but would be a non-canonical encoding. So, we calculate a + // mask based on how many bits are used for just the canonical encoding, and optionally + // error if any other bits are set. In the example of one encoded byte -> 2 symbols, + // 2 symbols can technically encode 12 bits, but the last 4 are non canonical, and + // useless since there are no more symbols to provide the necessary 4 additional bits + // to finish the second original byte. + + let leftover_bits_ready_to_append = match morsels_in_leftover { + 0 => 0, + 2 => 8, + 3 => 16, + 4 => 24, + 6 => 32, + 7 => 40, + 8 => 48, + // can also be detected as case #2 bad padding above + _ => unreachable!( + "Impossible: must only have 0 to 8 input bytes in last chunk, with no invalid lengths" + ), + }; + + // if there are bits set outside the bits we care about, last symbol encodes trailing bits that + // will not be included in the output + let mask = !0 >> leftover_bits_ready_to_append; + if !decode_allow_trailing_bits && (leftover_bits & mask) != 0 { + // last morsel is at `morsels_in_leftover` - 1 + return Err(DecodeError::InvalidLastSymbol( + start_of_leftovers + morsels_in_leftover - 1, + last_symbol, + )); + } + + // TODO benchmark simply converting to big endian bytes + let mut leftover_bits_appended_to_buf = 0; + while leftover_bits_appended_to_buf < leftover_bits_ready_to_append { + // `as` simply truncates the higher bits, which is what we want here + let selected_bits = (leftover_bits >> (56 - leftover_bits_appended_to_buf)) as u8; + output[output_index] = selected_bits; + output_index += 1; + + leftover_bits_appended_to_buf += 8; + } + + Ok(DecodeMetadata::new( + output_index, + if padding_bytes > 0 { + Some(input_index + first_padding_index) + } else { + None + }, + )) +} diff --git a/vendor/base64-0.21.5/src/engine/general_purpose/mod.rs b/vendor/base64-0.21.5/src/engine/general_purpose/mod.rs new file mode 100644 index 00000000..e0227f3b --- /dev/null +++ b/vendor/base64-0.21.5/src/engine/general_purpose/mod.rs @@ -0,0 +1,352 @@ +//! Provides the [GeneralPurpose] engine and associated config types. +use crate::{ + alphabet, + alphabet::Alphabet, + engine::{Config, DecodeMetadata, DecodePaddingMode}, + DecodeError, +}; +use core::convert::TryInto; + +mod decode; +pub(crate) mod decode_suffix; + +pub use decode::GeneralPurposeEstimate; + +pub(crate) const INVALID_VALUE: u8 = 255; + +/// A general-purpose base64 engine. +/// +/// - It uses no vector CPU instructions, so it will work on any system. +/// - It is reasonably fast (~2-3GiB/s). +/// - It is not constant-time, though, so it is vulnerable to timing side-channel attacks. For loading cryptographic keys, etc, it is suggested to use the forthcoming constant-time implementation. + +#[derive(Debug, Clone)] +pub struct GeneralPurpose { + encode_table: [u8; 64], + decode_table: [u8; 256], + config: GeneralPurposeConfig, +} + +impl GeneralPurpose { + /// Create a `GeneralPurpose` engine from an [Alphabet]. + /// + /// While not very expensive to initialize, ideally these should be cached + /// if the engine will be used repeatedly. + pub const fn new(alphabet: &Alphabet, config: GeneralPurposeConfig) -> Self { + Self { + encode_table: encode_table(alphabet), + decode_table: decode_table(alphabet), + config, + } + } +} + +impl super::Engine for GeneralPurpose { + type Config = GeneralPurposeConfig; + type DecodeEstimate = GeneralPurposeEstimate; + + fn internal_encode(&self, input: &[u8], output: &mut [u8]) -> usize { + let mut input_index: usize = 0; + + const BLOCKS_PER_FAST_LOOP: usize = 4; + const LOW_SIX_BITS: u64 = 0x3F; + + // we read 8 bytes at a time (u64) but only actually consume 6 of those bytes. Thus, we need + // 2 trailing bytes to be available to read.. + let last_fast_index = input.len().saturating_sub(BLOCKS_PER_FAST_LOOP * 6 + 2); + let mut output_index = 0; + + if last_fast_index > 0 { + while input_index <= last_fast_index { + // Major performance wins from letting the optimizer do the bounds check once, mostly + // on the output side + let input_chunk = + &input[input_index..(input_index + (BLOCKS_PER_FAST_LOOP * 6 + 2))]; + let output_chunk = + &mut output[output_index..(output_index + BLOCKS_PER_FAST_LOOP * 8)]; + + // Hand-unrolling for 32 vs 16 or 8 bytes produces yields performance about equivalent + // to unsafe pointer code on a Xeon E5-1650v3. 64 byte unrolling was slightly better for + // large inputs but significantly worse for 50-byte input, unsurprisingly. I suspect + // that it's a not uncommon use case to encode smallish chunks of data (e.g. a 64-byte + // SHA-512 digest), so it would be nice if that fit in the unrolled loop at least once. + // Plus, single-digit percentage performance differences might well be quite different + // on different hardware. + + let input_u64 = read_u64(&input_chunk[0..]); + + output_chunk[0] = self.encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize]; + output_chunk[1] = self.encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize]; + output_chunk[2] = self.encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize]; + output_chunk[3] = self.encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize]; + output_chunk[4] = self.encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize]; + output_chunk[5] = self.encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize]; + output_chunk[6] = self.encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize]; + output_chunk[7] = self.encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize]; + + let input_u64 = read_u64(&input_chunk[6..]); + + output_chunk[8] = self.encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize]; + output_chunk[9] = self.encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize]; + output_chunk[10] = self.encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize]; + output_chunk[11] = self.encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize]; + output_chunk[12] = self.encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize]; + output_chunk[13] = self.encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize]; + output_chunk[14] = self.encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize]; + output_chunk[15] = self.encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize]; + + let input_u64 = read_u64(&input_chunk[12..]); + + output_chunk[16] = self.encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize]; + output_chunk[17] = self.encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize]; + output_chunk[18] = self.encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize]; + output_chunk[19] = self.encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize]; + output_chunk[20] = self.encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize]; + output_chunk[21] = self.encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize]; + output_chunk[22] = self.encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize]; + output_chunk[23] = self.encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize]; + + let input_u64 = read_u64(&input_chunk[18..]); + + output_chunk[24] = self.encode_table[((input_u64 >> 58) & LOW_SIX_BITS) as usize]; + output_chunk[25] = self.encode_table[((input_u64 >> 52) & LOW_SIX_BITS) as usize]; + output_chunk[26] = self.encode_table[((input_u64 >> 46) & LOW_SIX_BITS) as usize]; + output_chunk[27] = self.encode_table[((input_u64 >> 40) & LOW_SIX_BITS) as usize]; + output_chunk[28] = self.encode_table[((input_u64 >> 34) & LOW_SIX_BITS) as usize]; + output_chunk[29] = self.encode_table[((input_u64 >> 28) & LOW_SIX_BITS) as usize]; + output_chunk[30] = self.encode_table[((input_u64 >> 22) & LOW_SIX_BITS) as usize]; + output_chunk[31] = self.encode_table[((input_u64 >> 16) & LOW_SIX_BITS) as usize]; + + output_index += BLOCKS_PER_FAST_LOOP * 8; + input_index += BLOCKS_PER_FAST_LOOP * 6; + } + } + + // Encode what's left after the fast loop. + + const LOW_SIX_BITS_U8: u8 = 0x3F; + + let rem = input.len() % 3; + let start_of_rem = input.len() - rem; + + // start at the first index not handled by fast loop, which may be 0. + + while input_index < start_of_rem { + let input_chunk = &input[input_index..(input_index + 3)]; + let output_chunk = &mut output[output_index..(output_index + 4)]; + + output_chunk[0] = self.encode_table[(input_chunk[0] >> 2) as usize]; + output_chunk[1] = self.encode_table + [((input_chunk[0] << 4 | input_chunk[1] >> 4) & LOW_SIX_BITS_U8) as usize]; + output_chunk[2] = self.encode_table + [((input_chunk[1] << 2 | input_chunk[2] >> 6) & LOW_SIX_BITS_U8) as usize]; + output_chunk[3] = self.encode_table[(input_chunk[2] & LOW_SIX_BITS_U8) as usize]; + + input_index += 3; + output_index += 4; + } + + if rem == 2 { + output[output_index] = self.encode_table[(input[start_of_rem] >> 2) as usize]; + output[output_index + 1] = + self.encode_table[((input[start_of_rem] << 4 | input[start_of_rem + 1] >> 4) + & LOW_SIX_BITS_U8) as usize]; + output[output_index + 2] = + self.encode_table[((input[start_of_rem + 1] << 2) & LOW_SIX_BITS_U8) as usize]; + output_index += 3; + } else if rem == 1 { + output[output_index] = self.encode_table[(input[start_of_rem] >> 2) as usize]; + output[output_index + 1] = + self.encode_table[((input[start_of_rem] << 4) & LOW_SIX_BITS_U8) as usize]; + output_index += 2; + } + + output_index + } + + fn internal_decoded_len_estimate(&self, input_len: usize) -> Self::DecodeEstimate { + GeneralPurposeEstimate::new(input_len) + } + + fn internal_decode( + &self, + input: &[u8], + output: &mut [u8], + estimate: Self::DecodeEstimate, + ) -> Result { + decode::decode_helper( + input, + estimate, + output, + &self.decode_table, + self.config.decode_allow_trailing_bits, + self.config.decode_padding_mode, + ) + } + + fn config(&self) -> &Self::Config { + &self.config + } +} + +/// Returns a table mapping a 6-bit index to the ASCII byte encoding of the index +pub(crate) const fn encode_table(alphabet: &Alphabet) -> [u8; 64] { + // the encode table is just the alphabet: + // 6-bit index lookup -> printable byte + let mut encode_table = [0_u8; 64]; + { + let mut index = 0; + while index < 64 { + encode_table[index] = alphabet.symbols[index]; + index += 1; + } + } + + encode_table +} + +/// Returns a table mapping base64 bytes as the lookup index to either: +/// - [INVALID_VALUE] for bytes that aren't members of the alphabet +/// - a byte whose lower 6 bits are the value that was encoded into the index byte +pub(crate) const fn decode_table(alphabet: &Alphabet) -> [u8; 256] { + let mut decode_table = [INVALID_VALUE; 256]; + + // Since the table is full of `INVALID_VALUE` already, we only need to overwrite + // the parts that are valid. + let mut index = 0; + while index < 64 { + // The index in the alphabet is the 6-bit value we care about. + // Since the index is in 0-63, it is safe to cast to u8. + decode_table[alphabet.symbols[index] as usize] = index as u8; + index += 1; + } + + decode_table +} + +#[inline] +fn read_u64(s: &[u8]) -> u64 { + u64::from_be_bytes(s[..8].try_into().unwrap()) +} + +/// Contains configuration parameters for base64 encoding and decoding. +/// +/// ``` +/// # use base64::engine::GeneralPurposeConfig; +/// let config = GeneralPurposeConfig::new() +/// .with_encode_padding(false); +/// // further customize using `.with_*` methods as needed +/// ``` +/// +/// The constants [PAD] and [NO_PAD] cover most use cases. +/// +/// To specify the characters used, see [Alphabet]. +#[derive(Clone, Copy, Debug)] +pub struct GeneralPurposeConfig { + encode_padding: bool, + decode_allow_trailing_bits: bool, + decode_padding_mode: DecodePaddingMode, +} + +impl GeneralPurposeConfig { + /// Create a new config with `padding` = `true`, `decode_allow_trailing_bits` = `false`, and + /// `decode_padding_mode = DecodePaddingMode::RequireCanonicalPadding`. + /// + /// This probably matches most people's expectations, but consider disabling padding to save + /// a few bytes unless you specifically need it for compatibility with some legacy system. + pub const fn new() -> Self { + Self { + // RFC states that padding must be applied by default + encode_padding: true, + decode_allow_trailing_bits: false, + decode_padding_mode: DecodePaddingMode::RequireCanonical, + } + } + + /// Create a new config based on `self` with an updated `padding` setting. + /// + /// If `padding` is `true`, encoding will append either 1 or 2 `=` padding characters as needed + /// to produce an output whose length is a multiple of 4. + /// + /// Padding is not needed for correct decoding and only serves to waste bytes, but it's in the + /// [spec](https://datatracker.ietf.org/doc/html/rfc4648#section-3.2). + /// + /// For new applications, consider not using padding if the decoders you're using don't require + /// padding to be present. + pub const fn with_encode_padding(self, padding: bool) -> Self { + Self { + encode_padding: padding, + ..self + } + } + + /// Create a new config based on `self` with an updated `decode_allow_trailing_bits` setting. + /// + /// Most users will not need to configure this. It's useful if you need to decode base64 + /// produced by a buggy encoder that has bits set in the unused space on the last base64 + /// character as per [forgiving-base64 decode](https://infra.spec.whatwg.org/#forgiving-base64-decode). + /// If invalid trailing bits are present and this is `true`, those bits will + /// be silently ignored, else `DecodeError::InvalidLastSymbol` will be emitted. + pub const fn with_decode_allow_trailing_bits(self, allow: bool) -> Self { + Self { + decode_allow_trailing_bits: allow, + ..self + } + } + + /// Create a new config based on `self` with an updated `decode_padding_mode` setting. + /// + /// Padding is not useful in terms of representing encoded data -- it makes no difference to + /// the decoder if padding is present or not, so if you have some un-padded input to decode, it + /// is perfectly fine to use `DecodePaddingMode::Indifferent` to prevent errors from being + /// emitted. + /// + /// However, since in practice + /// [people who learned nothing from BER vs DER seem to expect base64 to have one canonical encoding](https://eprint.iacr.org/2022/361), + /// the default setting is the stricter `DecodePaddingMode::RequireCanonicalPadding`. + /// + /// Or, if "canonical" in your circumstance means _no_ padding rather than padding to the + /// next multiple of four, there's `DecodePaddingMode::RequireNoPadding`. + pub const fn with_decode_padding_mode(self, mode: DecodePaddingMode) -> Self { + Self { + decode_padding_mode: mode, + ..self + } + } +} + +impl Default for GeneralPurposeConfig { + /// Delegates to [GeneralPurposeConfig::new]. + fn default() -> Self { + Self::new() + } +} + +impl Config for GeneralPurposeConfig { + fn encode_padding(&self) -> bool { + self.encode_padding + } +} + +/// A [GeneralPurpose] engine using the [alphabet::STANDARD] base64 alphabet and [PAD] config. +pub const STANDARD: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, PAD); + +/// A [GeneralPurpose] engine using the [alphabet::STANDARD] base64 alphabet and [NO_PAD] config. +pub const STANDARD_NO_PAD: GeneralPurpose = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD); + +/// A [GeneralPurpose] engine using the [alphabet::URL_SAFE] base64 alphabet and [PAD] config. +pub const URL_SAFE: GeneralPurpose = GeneralPurpose::new(&alphabet::URL_SAFE, PAD); + +/// A [GeneralPurpose] engine using the [alphabet::URL_SAFE] base64 alphabet and [NO_PAD] config. +pub const URL_SAFE_NO_PAD: GeneralPurpose = GeneralPurpose::new(&alphabet::URL_SAFE, NO_PAD); + +/// Include padding bytes when encoding, and require that they be present when decoding. +/// +/// This is the standard per the base64 RFC, but consider using [NO_PAD] instead as padding serves +/// little purpose in practice. +pub const PAD: GeneralPurposeConfig = GeneralPurposeConfig::new(); + +/// Don't add padding when encoding, and require no padding when decoding. +pub const NO_PAD: GeneralPurposeConfig = GeneralPurposeConfig::new() + .with_encode_padding(false) + .with_decode_padding_mode(DecodePaddingMode::RequireNone); diff --git a/vendor/base64-0.21.5/src/engine/mod.rs b/vendor/base64-0.21.5/src/engine/mod.rs new file mode 100644 index 00000000..16c05d75 --- /dev/null +++ b/vendor/base64-0.21.5/src/engine/mod.rs @@ -0,0 +1,466 @@ +//! Provides the [Engine] abstraction and out of the box implementations. +#[cfg(any(feature = "alloc", test))] +use crate::chunked_encoder; +use crate::{ + encode::{encode_with_padding, EncodeSliceError}, + encoded_len, DecodeError, DecodeSliceError, +}; +#[cfg(any(feature = "alloc", test))] +use alloc::vec::Vec; + +#[cfg(any(feature = "alloc", test))] +use alloc::{string::String, vec}; + +pub mod general_purpose; + +#[cfg(test)] +mod naive; + +#[cfg(test)] +mod tests; + +pub use general_purpose::{GeneralPurpose, GeneralPurposeConfig}; + +/// An `Engine` provides low-level encoding and decoding operations that all other higher-level parts of the API use. Users of the library will generally not need to implement this. +/// +/// Different implementations offer different characteristics. The library currently ships with +/// [GeneralPurpose] that offers good speed and works on any CPU, with more choices +/// coming later, like a constant-time one when side channel resistance is called for, and vendor-specific vectorized ones for more speed. +/// +/// See [general_purpose::STANDARD_NO_PAD] if you just want standard base64. Otherwise, when possible, it's +/// recommended to store the engine in a `const` so that references to it won't pose any lifetime +/// issues, and to avoid repeating the cost of engine setup. +/// +/// Since almost nobody will need to implement `Engine`, docs for internal methods are hidden. +// When adding an implementation of Engine, include them in the engine test suite: +// - add an implementation of [engine::tests::EngineWrapper] +// - add the implementation to the `all_engines` macro +// All tests run on all engines listed in the macro. +pub trait Engine: Send + Sync { + /// The config type used by this engine + type Config: Config; + /// The decode estimate used by this engine + type DecodeEstimate: DecodeEstimate; + + /// This is not meant to be called directly; it is only for `Engine` implementors. + /// See the other `encode*` functions on this trait. + /// + /// Encode the `input` bytes into the `output` buffer based on the mapping in `encode_table`. + /// + /// `output` will be long enough to hold the encoded data. + /// + /// Returns the number of bytes written. + /// + /// No padding should be written; that is handled separately. + /// + /// Must not write any bytes into the output slice other than the encoded data. + #[doc(hidden)] + fn internal_encode(&self, input: &[u8], output: &mut [u8]) -> usize; + + /// This is not meant to be called directly; it is only for `Engine` implementors. + /// + /// As an optimization to prevent the decoded length from being calculated twice, it is + /// sometimes helpful to have a conservative estimate of the decoded size before doing the + /// decoding, so this calculation is done separately and passed to [Engine::decode()] as needed. + #[doc(hidden)] + fn internal_decoded_len_estimate(&self, input_len: usize) -> Self::DecodeEstimate; + + /// This is not meant to be called directly; it is only for `Engine` implementors. + /// See the other `decode*` functions on this trait. + /// + /// Decode `input` base64 bytes into the `output` buffer. + /// + /// `decode_estimate` is the result of [Engine::internal_decoded_len_estimate()], which is passed in to avoid + /// calculating it again (expensive on short inputs).` + /// + /// Each complete 4-byte chunk of encoded data decodes to 3 bytes of decoded data, but this + /// function must also handle the final possibly partial chunk. + /// If the input length is not a multiple of 4, or uses padding bytes to reach a multiple of 4, + /// the trailing 2 or 3 bytes must decode to 1 or 2 bytes, respectively, as per the + /// [RFC](https://tools.ietf.org/html/rfc4648#section-3.5). + /// + /// Decoding must not write any bytes into the output slice other than the decoded data. + /// + /// Non-canonical trailing bits in the final tokens or non-canonical padding must be reported as + /// errors unless the engine is configured otherwise. + /// + /// # Panics + /// + /// Panics if `output` is too small. + #[doc(hidden)] + fn internal_decode( + &self, + input: &[u8], + output: &mut [u8], + decode_estimate: Self::DecodeEstimate, + ) -> Result; + + /// Returns the config for this engine. + fn config(&self) -> &Self::Config; + + /// Encode arbitrary octets as base64 using the provided `Engine`. + /// Returns a `String`. + /// + /// # Example + /// + /// ```rust + /// use base64::{Engine as _, engine::{self, general_purpose}, alphabet}; + /// + /// let b64 = general_purpose::STANDARD.encode(b"hello world~"); + /// println!("{}", b64); + /// + /// const CUSTOM_ENGINE: engine::GeneralPurpose = + /// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD); + /// + /// let b64_url = CUSTOM_ENGINE.encode(b"hello internet~"); + #[cfg(any(feature = "alloc", test))] + #[inline] + fn encode>(&self, input: T) -> String { + fn inner(engine: &E, input_bytes: &[u8]) -> String + where + E: Engine + ?Sized, + { + let encoded_size = encoded_len(input_bytes.len(), engine.config().encode_padding()) + .expect("integer overflow when calculating buffer size"); + + let mut buf = vec![0; encoded_size]; + + encode_with_padding(input_bytes, &mut buf[..], engine, encoded_size); + + String::from_utf8(buf).expect("Invalid UTF8") + } + + inner(self, input.as_ref()) + } + + /// Encode arbitrary octets as base64 into a supplied `String`. + /// Writes into the supplied `String`, which may allocate if its internal buffer isn't big enough. + /// + /// # Example + /// + /// ```rust + /// use base64::{Engine as _, engine::{self, general_purpose}, alphabet}; + /// const CUSTOM_ENGINE: engine::GeneralPurpose = + /// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD); + /// + /// fn main() { + /// let mut buf = String::new(); + /// general_purpose::STANDARD.encode_string(b"hello world~", &mut buf); + /// println!("{}", buf); + /// + /// buf.clear(); + /// CUSTOM_ENGINE.encode_string(b"hello internet~", &mut buf); + /// println!("{}", buf); + /// } + /// ``` + #[cfg(any(feature = "alloc", test))] + #[inline] + fn encode_string>(&self, input: T, output_buf: &mut String) { + fn inner(engine: &E, input_bytes: &[u8], output_buf: &mut String) + where + E: Engine + ?Sized, + { + let mut sink = chunked_encoder::StringSink::new(output_buf); + + chunked_encoder::ChunkedEncoder::new(engine) + .encode(input_bytes, &mut sink) + .expect("Writing to a String shouldn't fail"); + } + + inner(self, input.as_ref(), output_buf) + } + + /// Encode arbitrary octets as base64 into a supplied slice. + /// Writes into the supplied output buffer. + /// + /// This is useful if you wish to avoid allocation entirely (e.g. encoding into a stack-resident + /// or statically-allocated buffer). + /// + /// # Example + /// + #[cfg_attr(feature = "alloc", doc = "```")] + #[cfg_attr(not(feature = "alloc"), doc = "```ignore")] + /// use base64::{Engine as _, engine::general_purpose}; + /// let s = b"hello internet!"; + /// let mut buf = Vec::new(); + /// // make sure we'll have a slice big enough for base64 + padding + /// buf.resize(s.len() * 4 / 3 + 4, 0); + /// + /// let bytes_written = general_purpose::STANDARD.encode_slice(s, &mut buf).unwrap(); + /// + /// // shorten our vec down to just what was written + /// buf.truncate(bytes_written); + /// + /// assert_eq!(s, general_purpose::STANDARD.decode(&buf).unwrap().as_slice()); + /// ``` + #[inline] + fn encode_slice>( + &self, + input: T, + output_buf: &mut [u8], + ) -> Result { + fn inner( + engine: &E, + input_bytes: &[u8], + output_buf: &mut [u8], + ) -> Result + where + E: Engine + ?Sized, + { + let encoded_size = encoded_len(input_bytes.len(), engine.config().encode_padding()) + .expect("usize overflow when calculating buffer size"); + + if output_buf.len() < encoded_size { + return Err(EncodeSliceError::OutputSliceTooSmall); + } + + let b64_output = &mut output_buf[0..encoded_size]; + + encode_with_padding(input_bytes, b64_output, engine, encoded_size); + + Ok(encoded_size) + } + + inner(self, input.as_ref(), output_buf) + } + + /// Decode the input into a new `Vec`. + /// + /// # Example + /// + /// ```rust + /// use base64::{Engine as _, alphabet, engine::{self, general_purpose}}; + /// + /// let bytes = general_purpose::STANDARD + /// .decode("aGVsbG8gd29ybGR+Cg==").unwrap(); + /// println!("{:?}", bytes); + /// + /// // custom engine setup + /// let bytes_url = engine::GeneralPurpose::new( + /// &alphabet::URL_SAFE, + /// general_purpose::NO_PAD) + /// .decode("aGVsbG8gaW50ZXJuZXR-Cg").unwrap(); + /// println!("{:?}", bytes_url); + /// ``` + #[cfg(any(feature = "alloc", test))] + #[inline] + fn decode>(&self, input: T) -> Result, DecodeError> { + fn inner(engine: &E, input_bytes: &[u8]) -> Result, DecodeError> + where + E: Engine + ?Sized, + { + let estimate = engine.internal_decoded_len_estimate(input_bytes.len()); + let mut buffer = vec![0; estimate.decoded_len_estimate()]; + + let bytes_written = engine + .internal_decode(input_bytes, &mut buffer, estimate)? + .decoded_len; + + buffer.truncate(bytes_written); + + Ok(buffer) + } + + inner(self, input.as_ref()) + } + + /// Decode the `input` into the supplied `buffer`. + /// + /// Writes into the supplied `Vec`, which may allocate if its internal buffer isn't big enough. + /// Returns a `Result` containing an empty tuple, aka `()`. + /// + /// # Example + /// + /// ```rust + /// use base64::{Engine as _, alphabet, engine::{self, general_purpose}}; + /// const CUSTOM_ENGINE: engine::GeneralPurpose = + /// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::PAD); + /// + /// fn main() { + /// use base64::Engine; + /// let mut buffer = Vec::::new(); + /// // with the default engine + /// general_purpose::STANDARD + /// .decode_vec("aGVsbG8gd29ybGR+Cg==", &mut buffer,).unwrap(); + /// println!("{:?}", buffer); + /// + /// buffer.clear(); + /// + /// // with a custom engine + /// CUSTOM_ENGINE.decode_vec( + /// "aGVsbG8gaW50ZXJuZXR-Cg==", + /// &mut buffer, + /// ).unwrap(); + /// println!("{:?}", buffer); + /// } + /// ``` + #[cfg(any(feature = "alloc", test))] + #[inline] + fn decode_vec>( + &self, + input: T, + buffer: &mut Vec, + ) -> Result<(), DecodeError> { + fn inner(engine: &E, input_bytes: &[u8], buffer: &mut Vec) -> Result<(), DecodeError> + where + E: Engine + ?Sized, + { + let starting_output_len = buffer.len(); + let estimate = engine.internal_decoded_len_estimate(input_bytes.len()); + + let total_len_estimate = estimate + .decoded_len_estimate() + .checked_add(starting_output_len) + .expect("Overflow when calculating output buffer length"); + + buffer.resize(total_len_estimate, 0); + + let buffer_slice = &mut buffer.as_mut_slice()[starting_output_len..]; + + let bytes_written = engine + .internal_decode(input_bytes, buffer_slice, estimate)? + .decoded_len; + + buffer.truncate(starting_output_len + bytes_written); + + Ok(()) + } + + inner(self, input.as_ref(), buffer) + } + + /// Decode the input into the provided output slice. + /// + /// Returns the number of bytes written to the slice, or an error if `output` is smaller than + /// the estimated decoded length. + /// + /// This will not write any bytes past exactly what is decoded (no stray garbage bytes at the end). + /// + /// See [crate::decoded_len_estimate] for calculating buffer sizes. + /// + /// See [Engine::decode_slice_unchecked] for a version that panics instead of returning an error + /// if the output buffer is too small. + #[inline] + fn decode_slice>( + &self, + input: T, + output: &mut [u8], + ) -> Result { + fn inner( + engine: &E, + input_bytes: &[u8], + output: &mut [u8], + ) -> Result + where + E: Engine + ?Sized, + { + let estimate = engine.internal_decoded_len_estimate(input_bytes.len()); + + if output.len() < estimate.decoded_len_estimate() { + return Err(DecodeSliceError::OutputSliceTooSmall); + } + + engine + .internal_decode(input_bytes, output, estimate) + .map_err(|e| e.into()) + .map(|dm| dm.decoded_len) + } + + inner(self, input.as_ref(), output) + } + + /// Decode the input into the provided output slice. + /// + /// Returns the number of bytes written to the slice. + /// + /// This will not write any bytes past exactly what is decoded (no stray garbage bytes at the end). + /// + /// See [crate::decoded_len_estimate] for calculating buffer sizes. + /// + /// See [Engine::decode_slice] for a version that returns an error instead of panicking if the output + /// buffer is too small. + /// + /// # Panics + /// + /// Panics if the provided output buffer is too small for the decoded data. + #[inline] + fn decode_slice_unchecked>( + &self, + input: T, + output: &mut [u8], + ) -> Result { + fn inner(engine: &E, input_bytes: &[u8], output: &mut [u8]) -> Result + where + E: Engine + ?Sized, + { + engine + .internal_decode( + input_bytes, + output, + engine.internal_decoded_len_estimate(input_bytes.len()), + ) + .map(|dm| dm.decoded_len) + } + + inner(self, input.as_ref(), output) + } +} + +/// The minimal level of configuration that engines must support. +pub trait Config { + /// Returns `true` if padding should be added after the encoded output. + /// + /// Padding is added outside the engine's encode() since the engine may be used + /// to encode only a chunk of the overall output, so it can't always know when + /// the output is "done" and would therefore need padding (if configured). + // It could be provided as a separate parameter when encoding, but that feels like + // leaking an implementation detail to the user, and it's hopefully more convenient + // to have to only pass one thing (the engine) to any part of the API. + fn encode_padding(&self) -> bool; +} + +/// The decode estimate used by an engine implementation. Users do not need to interact with this; +/// it is only for engine implementors. +/// +/// Implementors may store relevant data here when constructing this to avoid having to calculate +/// them again during actual decoding. +pub trait DecodeEstimate { + /// Returns a conservative (err on the side of too big) estimate of the decoded length to use + /// for pre-allocating buffers, etc. + /// + /// The estimate must be no larger than the next largest complete triple of decoded bytes. + /// That is, the final quad of tokens to decode may be assumed to be complete with no padding. + fn decoded_len_estimate(&self) -> usize; +} + +/// Controls how pad bytes are handled when decoding. +/// +/// Each [Engine] must support at least the behavior indicated by +/// [DecodePaddingMode::RequireCanonical], and may support other modes. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum DecodePaddingMode { + /// Canonical padding is allowed, but any fewer padding bytes than that is also allowed. + Indifferent, + /// Padding must be canonical (0, 1, or 2 `=` as needed to produce a 4 byte suffix). + RequireCanonical, + /// Padding must be absent -- for when you want predictable padding, without any wasted bytes. + RequireNone, +} + +/// Metadata about the result of a decode operation +#[derive(PartialEq, Eq, Debug)] +pub struct DecodeMetadata { + /// Number of decoded bytes output + pub(crate) decoded_len: usize, + /// Offset of the first padding byte in the input, if any + pub(crate) padding_offset: Option, +} + +impl DecodeMetadata { + pub(crate) fn new(decoded_bytes: usize, padding_index: Option) -> Self { + Self { + decoded_len: decoded_bytes, + padding_offset: padding_index, + } + } +} diff --git a/vendor/base64-0.21.5/src/engine/naive.rs b/vendor/base64-0.21.5/src/engine/naive.rs new file mode 100644 index 00000000..6a50cbed --- /dev/null +++ b/vendor/base64-0.21.5/src/engine/naive.rs @@ -0,0 +1,218 @@ +use crate::{ + alphabet::Alphabet, + engine::{ + general_purpose::{self, decode_table, encode_table}, + Config, DecodeEstimate, DecodeMetadata, DecodePaddingMode, Engine, + }, + DecodeError, PAD_BYTE, +}; +use std::ops::{BitAnd, BitOr, Shl, Shr}; + +/// Comparatively simple implementation that can be used as something to compare against in tests +pub struct Naive { + encode_table: [u8; 64], + decode_table: [u8; 256], + config: NaiveConfig, +} + +impl Naive { + const ENCODE_INPUT_CHUNK_SIZE: usize = 3; + const DECODE_INPUT_CHUNK_SIZE: usize = 4; + + pub const fn new(alphabet: &Alphabet, config: NaiveConfig) -> Self { + Self { + encode_table: encode_table(alphabet), + decode_table: decode_table(alphabet), + config, + } + } + + fn decode_byte_into_u32(&self, offset: usize, byte: u8) -> Result { + let decoded = self.decode_table[byte as usize]; + + if decoded == general_purpose::INVALID_VALUE { + return Err(DecodeError::InvalidByte(offset, byte)); + } + + Ok(decoded as u32) + } +} + +impl Engine for Naive { + type Config = NaiveConfig; + type DecodeEstimate = NaiveEstimate; + + fn internal_encode(&self, input: &[u8], output: &mut [u8]) -> usize { + // complete chunks first + + const LOW_SIX_BITS: u32 = 0x3F; + + let rem = input.len() % Self::ENCODE_INPUT_CHUNK_SIZE; + // will never underflow + let complete_chunk_len = input.len() - rem; + + let mut input_index = 0_usize; + let mut output_index = 0_usize; + if let Some(last_complete_chunk_index) = + complete_chunk_len.checked_sub(Self::ENCODE_INPUT_CHUNK_SIZE) + { + while input_index <= last_complete_chunk_index { + let chunk = &input[input_index..input_index + Self::ENCODE_INPUT_CHUNK_SIZE]; + + // populate low 24 bits from 3 bytes + let chunk_int: u32 = + (chunk[0] as u32).shl(16) | (chunk[1] as u32).shl(8) | (chunk[2] as u32); + // encode 4x 6-bit output bytes + output[output_index] = self.encode_table[chunk_int.shr(18) as usize]; + output[output_index + 1] = + self.encode_table[chunk_int.shr(12_u8).bitand(LOW_SIX_BITS) as usize]; + output[output_index + 2] = + self.encode_table[chunk_int.shr(6_u8).bitand(LOW_SIX_BITS) as usize]; + output[output_index + 3] = + self.encode_table[chunk_int.bitand(LOW_SIX_BITS) as usize]; + + input_index += Self::ENCODE_INPUT_CHUNK_SIZE; + output_index += 4; + } + } + + // then leftovers + if rem == 2 { + let chunk = &input[input_index..input_index + 2]; + + // high six bits of chunk[0] + output[output_index] = self.encode_table[chunk[0].shr(2) as usize]; + // bottom 2 bits of [0], high 4 bits of [1] + output[output_index + 1] = + self.encode_table[(chunk[0].shl(4_u8).bitor(chunk[1].shr(4_u8)) as u32) + .bitand(LOW_SIX_BITS) as usize]; + // bottom 4 bits of [1], with the 2 bottom bits as zero + output[output_index + 2] = + self.encode_table[(chunk[1].shl(2_u8) as u32).bitand(LOW_SIX_BITS) as usize]; + + output_index += 3; + } else if rem == 1 { + let byte = input[input_index]; + output[output_index] = self.encode_table[byte.shr(2) as usize]; + output[output_index + 1] = + self.encode_table[(byte.shl(4_u8) as u32).bitand(LOW_SIX_BITS) as usize]; + output_index += 2; + } + + output_index + } + + fn internal_decoded_len_estimate(&self, input_len: usize) -> Self::DecodeEstimate { + NaiveEstimate::new(input_len) + } + + fn internal_decode( + &self, + input: &[u8], + output: &mut [u8], + estimate: Self::DecodeEstimate, + ) -> Result { + if estimate.rem == 1 { + // trailing whitespace is so common that it's worth it to check the last byte to + // possibly return a better error message + if let Some(b) = input.last() { + if *b != PAD_BYTE + && self.decode_table[*b as usize] == general_purpose::INVALID_VALUE + { + return Err(DecodeError::InvalidByte(input.len() - 1, *b)); + } + } + + return Err(DecodeError::InvalidLength); + } + + let mut input_index = 0_usize; + let mut output_index = 0_usize; + const BOTTOM_BYTE: u32 = 0xFF; + + // can only use the main loop on non-trailing chunks + if input.len() > Self::DECODE_INPUT_CHUNK_SIZE { + // skip the last chunk, whether it's partial or full, since it might + // have padding, and start at the beginning of the chunk before that + let last_complete_chunk_start_index = estimate.complete_chunk_len + - if estimate.rem == 0 { + // Trailing chunk is also full chunk, so there must be at least 2 chunks, and + // this won't underflow + Self::DECODE_INPUT_CHUNK_SIZE * 2 + } else { + // Trailing chunk is partial, so it's already excluded in + // complete_chunk_len + Self::DECODE_INPUT_CHUNK_SIZE + }; + + while input_index <= last_complete_chunk_start_index { + let chunk = &input[input_index..input_index + Self::DECODE_INPUT_CHUNK_SIZE]; + let decoded_int: u32 = self.decode_byte_into_u32(input_index, chunk[0])?.shl(18) + | self + .decode_byte_into_u32(input_index + 1, chunk[1])? + .shl(12) + | self.decode_byte_into_u32(input_index + 2, chunk[2])?.shl(6) + | self.decode_byte_into_u32(input_index + 3, chunk[3])?; + + output[output_index] = decoded_int.shr(16_u8).bitand(BOTTOM_BYTE) as u8; + output[output_index + 1] = decoded_int.shr(8_u8).bitand(BOTTOM_BYTE) as u8; + output[output_index + 2] = decoded_int.bitand(BOTTOM_BYTE) as u8; + + input_index += Self::DECODE_INPUT_CHUNK_SIZE; + output_index += 3; + } + } + + general_purpose::decode_suffix::decode_suffix( + input, + input_index, + output, + output_index, + &self.decode_table, + self.config.decode_allow_trailing_bits, + self.config.decode_padding_mode, + ) + } + + fn config(&self) -> &Self::Config { + &self.config + } +} + +pub struct NaiveEstimate { + /// remainder from dividing input by `Naive::DECODE_CHUNK_SIZE` + rem: usize, + /// Length of input that is in complete `Naive::DECODE_CHUNK_SIZE`-length chunks + complete_chunk_len: usize, +} + +impl NaiveEstimate { + fn new(input_len: usize) -> Self { + let rem = input_len % Naive::DECODE_INPUT_CHUNK_SIZE; + let complete_chunk_len = input_len - rem; + + Self { + rem, + complete_chunk_len, + } + } +} + +impl DecodeEstimate for NaiveEstimate { + fn decoded_len_estimate(&self) -> usize { + ((self.complete_chunk_len / 4) + ((self.rem > 0) as usize)) * 3 + } +} + +#[derive(Clone, Copy, Debug)] +pub struct NaiveConfig { + pub encode_padding: bool, + pub decode_allow_trailing_bits: bool, + pub decode_padding_mode: DecodePaddingMode, +} + +impl Config for NaiveConfig { + fn encode_padding(&self) -> bool { + self.encode_padding + } +} diff --git a/vendor/base64-0.21.5/src/engine/tests.rs b/vendor/base64-0.21.5/src/engine/tests.rs new file mode 100644 index 00000000..b0480055 --- /dev/null +++ b/vendor/base64-0.21.5/src/engine/tests.rs @@ -0,0 +1,1717 @@ +// rstest_reuse template functions have unused variables +#![allow(unused_variables)] + +use rand::{ + self, + distributions::{self, Distribution as _}, + rngs, Rng as _, SeedableRng as _, +}; +use rstest::rstest; +use rstest_reuse::{apply, template}; +use std::{collections, fmt, io::Read as _}; + +use crate::{ + alphabet::{Alphabet, STANDARD}, + encode::add_padding, + encoded_len, + engine::{ + general_purpose, naive, Config, DecodeEstimate, DecodeMetadata, DecodePaddingMode, Engine, + }, + read::DecoderReader, + tests::{assert_encode_sanity, random_alphabet, random_config}, + DecodeError, PAD_BYTE, +}; + +// the case::foo syntax includes the "foo" in the generated test method names +#[template] +#[rstest(engine_wrapper, +case::general_purpose(GeneralPurposeWrapper {}), +case::naive(NaiveWrapper {}), +case::decoder_reader(DecoderReaderEngineWrapper {}), +)] +fn all_engines(engine_wrapper: E) {} + +/// Some decode tests don't make sense for use with `DecoderReader` as they are difficult to +/// reason about or otherwise inapplicable given how DecoderReader slice up its input along +/// chunk boundaries. +#[template] +#[rstest(engine_wrapper, +case::general_purpose(GeneralPurposeWrapper {}), +case::naive(NaiveWrapper {}), +)] +fn all_engines_except_decoder_reader(engine_wrapper: E) {} + +#[apply(all_engines)] +fn rfc_test_vectors_std_alphabet(engine_wrapper: E) { + let data = vec![ + ("", ""), + ("f", "Zg=="), + ("fo", "Zm8="), + ("foo", "Zm9v"), + ("foob", "Zm9vYg=="), + ("fooba", "Zm9vYmE="), + ("foobar", "Zm9vYmFy"), + ]; + + let engine = E::standard(); + let engine_no_padding = E::standard_unpadded(); + + for (orig, encoded) in &data { + let encoded_without_padding = encoded.trim_end_matches('='); + + // unpadded + { + let mut encode_buf = [0_u8; 8]; + let mut decode_buf = [0_u8; 6]; + + let encode_len = + engine_no_padding.internal_encode(orig.as_bytes(), &mut encode_buf[..]); + assert_eq!( + &encoded_without_padding, + &std::str::from_utf8(&encode_buf[0..encode_len]).unwrap() + ); + let decode_len = engine_no_padding + .decode_slice_unchecked(encoded_without_padding.as_bytes(), &mut decode_buf[..]) + .unwrap(); + assert_eq!(orig.len(), decode_len); + + assert_eq!( + orig, + &std::str::from_utf8(&decode_buf[0..decode_len]).unwrap() + ); + + // if there was any padding originally, the no padding engine won't decode it + if encoded.as_bytes().contains(&PAD_BYTE) { + assert_eq!( + Err(DecodeError::InvalidPadding), + engine_no_padding.decode(encoded) + ) + } + } + + // padded + { + let mut encode_buf = [0_u8; 8]; + let mut decode_buf = [0_u8; 6]; + + let encode_len = engine.internal_encode(orig.as_bytes(), &mut encode_buf[..]); + assert_eq!( + // doesn't have padding added yet + &encoded_without_padding, + &std::str::from_utf8(&encode_buf[0..encode_len]).unwrap() + ); + let pad_len = add_padding(encode_len, &mut encode_buf[encode_len..]); + assert_eq!(encoded.as_bytes(), &encode_buf[..encode_len + pad_len]); + + let decode_len = engine + .decode_slice_unchecked(encoded.as_bytes(), &mut decode_buf[..]) + .unwrap(); + assert_eq!(orig.len(), decode_len); + + assert_eq!( + orig, + &std::str::from_utf8(&decode_buf[0..decode_len]).unwrap() + ); + + // if there was (canonical) padding, and we remove it, the standard engine won't decode + if encoded.as_bytes().contains(&PAD_BYTE) { + assert_eq!( + Err(DecodeError::InvalidPadding), + engine.decode(encoded_without_padding) + ) + } + } + } +} + +#[apply(all_engines)] +fn roundtrip_random(engine_wrapper: E) { + let mut rng = seeded_rng(); + + let mut orig_data = Vec::::new(); + let mut encode_buf = Vec::::new(); + let mut decode_buf = Vec::::new(); + + let len_range = distributions::Uniform::new(1, 1_000); + + for _ in 0..10_000 { + let engine = E::random(&mut rng); + + orig_data.clear(); + encode_buf.clear(); + decode_buf.clear(); + + let (orig_len, _, encoded_len) = generate_random_encoded_data( + &engine, + &mut orig_data, + &mut encode_buf, + &mut rng, + &len_range, + ); + + // exactly the right size + decode_buf.resize(orig_len, 0); + + let dec_len = engine + .decode_slice_unchecked(&encode_buf[0..encoded_len], &mut decode_buf[..]) + .unwrap(); + + assert_eq!(orig_len, dec_len); + assert_eq!(&orig_data[..], &decode_buf[..dec_len]); + } +} + +#[apply(all_engines)] +fn encode_doesnt_write_extra_bytes(engine_wrapper: E) { + let mut rng = seeded_rng(); + + let mut orig_data = Vec::::new(); + let mut encode_buf = Vec::::new(); + let mut encode_buf_backup = Vec::::new(); + + let input_len_range = distributions::Uniform::new(0, 1000); + + for _ in 0..10_000 { + let engine = E::random(&mut rng); + let padded = engine.config().encode_padding(); + + orig_data.clear(); + encode_buf.clear(); + encode_buf_backup.clear(); + + let orig_len = fill_rand(&mut orig_data, &mut rng, &input_len_range); + + let prefix_len = 1024; + // plenty of prefix and suffix + fill_rand_len(&mut encode_buf, &mut rng, prefix_len * 2 + orig_len * 2); + encode_buf_backup.extend_from_slice(&encode_buf[..]); + + let expected_encode_len_no_pad = encoded_len(orig_len, false).unwrap(); + + let encoded_len_no_pad = + engine.internal_encode(&orig_data[..], &mut encode_buf[prefix_len..]); + assert_eq!(expected_encode_len_no_pad, encoded_len_no_pad); + + // no writes past what it claimed to write + assert_eq!(&encode_buf_backup[..prefix_len], &encode_buf[..prefix_len]); + assert_eq!( + &encode_buf_backup[(prefix_len + encoded_len_no_pad)..], + &encode_buf[(prefix_len + encoded_len_no_pad)..] + ); + + let encoded_data = &encode_buf[prefix_len..(prefix_len + encoded_len_no_pad)]; + assert_encode_sanity( + std::str::from_utf8(encoded_data).unwrap(), + // engines don't pad + false, + orig_len, + ); + + // pad so we can decode it in case our random engine requires padding + let pad_len = if padded { + add_padding( + encoded_len_no_pad, + &mut encode_buf[prefix_len + encoded_len_no_pad..], + ) + } else { + 0 + }; + + assert_eq!( + orig_data, + engine + .decode(&encode_buf[prefix_len..(prefix_len + encoded_len_no_pad + pad_len)],) + .unwrap() + ); + } +} + +#[apply(all_engines)] +fn encode_engine_slice_fits_into_precisely_sized_slice(engine_wrapper: E) { + let mut orig_data = Vec::new(); + let mut encoded_data = Vec::new(); + let mut decoded = Vec::new(); + + let input_len_range = distributions::Uniform::new(0, 1000); + + let mut rng = rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + orig_data.clear(); + encoded_data.clear(); + decoded.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + orig_data.push(rng.gen()); + } + + let engine = E::random(&mut rng); + + let encoded_size = encoded_len(input_len, engine.config().encode_padding()).unwrap(); + + encoded_data.resize(encoded_size, 0); + + assert_eq!( + encoded_size, + engine.encode_slice(&orig_data, &mut encoded_data).unwrap() + ); + + assert_encode_sanity( + std::str::from_utf8(&encoded_data[0..encoded_size]).unwrap(), + engine.config().encode_padding(), + input_len, + ); + + engine + .decode_vec(&encoded_data[0..encoded_size], &mut decoded) + .unwrap(); + assert_eq!(orig_data, decoded); + } +} + +#[apply(all_engines)] +fn decode_doesnt_write_extra_bytes(engine_wrapper: E) +where + E: EngineWrapper, + <::Engine as Engine>::Config: fmt::Debug, +{ + let mut rng = seeded_rng(); + + let mut orig_data = Vec::::new(); + let mut encode_buf = Vec::::new(); + let mut decode_buf = Vec::::new(); + let mut decode_buf_backup = Vec::::new(); + + let len_range = distributions::Uniform::new(1, 1_000); + + for _ in 0..10_000 { + let engine = E::random(&mut rng); + + orig_data.clear(); + encode_buf.clear(); + decode_buf.clear(); + decode_buf_backup.clear(); + + let orig_len = fill_rand(&mut orig_data, &mut rng, &len_range); + encode_buf.resize(orig_len * 2 + 100, 0); + + let encoded_len = engine + .encode_slice(&orig_data[..], &mut encode_buf[..]) + .unwrap(); + encode_buf.truncate(encoded_len); + + // oversize decode buffer so we can easily tell if it writes anything more than + // just the decoded data + let prefix_len = 1024; + // plenty of prefix and suffix + fill_rand_len(&mut decode_buf, &mut rng, prefix_len * 2 + orig_len * 2); + decode_buf_backup.extend_from_slice(&decode_buf[..]); + + let dec_len = engine + .decode_slice_unchecked(&encode_buf, &mut decode_buf[prefix_len..]) + .unwrap(); + + assert_eq!(orig_len, dec_len); + assert_eq!( + &orig_data[..], + &decode_buf[prefix_len..prefix_len + dec_len] + ); + assert_eq!(&decode_buf_backup[..prefix_len], &decode_buf[..prefix_len]); + assert_eq!( + &decode_buf_backup[prefix_len + dec_len..], + &decode_buf[prefix_len + dec_len..] + ); + } +} + +#[apply(all_engines)] +fn decode_detect_invalid_last_symbol(engine_wrapper: E) { + // 0xFF -> "/w==", so all letters > w, 0-9, and '+', '/' should get InvalidLastSymbol + let engine = E::standard(); + + assert_eq!(Ok(vec![0x89, 0x85]), engine.decode("iYU=")); + assert_eq!(Ok(vec![0xFF]), engine.decode("/w==")); + + for (suffix, offset) in vec![ + // suffix, offset of bad byte from start of suffix + ("/x==", 1_usize), + ("/z==", 1_usize), + ("/0==", 1_usize), + ("/9==", 1_usize), + ("/+==", 1_usize), + ("//==", 1_usize), + // trailing 01 + ("iYV=", 2_usize), + // trailing 10 + ("iYW=", 2_usize), + // trailing 11 + ("iYX=", 2_usize), + ] { + for prefix_quads in 0..256 { + let mut encoded = "AAAA".repeat(prefix_quads); + encoded.push_str(suffix); + + assert_eq!( + Err(DecodeError::InvalidLastSymbol( + encoded.len() - 4 + offset, + suffix.as_bytes()[offset], + )), + engine.decode(encoded.as_str()) + ); + } + } +} + +#[apply(all_engines)] +fn decode_detect_invalid_last_symbol_when_length_is_also_invalid( + engine_wrapper: E, +) { + let mut rng = seeded_rng(); + + // check across enough lengths that it would likely cover any implementation's various internal + // small/large input division + for len in (0_usize..256).map(|len| len * 4 + 1) { + let engine = E::random_alphabet(&mut rng, &STANDARD); + + let mut input = vec![b'A'; len]; + + // with a valid last char, it's InvalidLength + assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&input)); + // after mangling the last char, it's InvalidByte + input[len - 1] = b'"'; + assert_eq!( + Err(DecodeError::InvalidByte(len - 1, b'"')), + engine.decode(&input) + ); + } +} + +#[apply(all_engines)] +fn decode_detect_invalid_last_symbol_every_possible_two_symbols( + engine_wrapper: E, +) { + let engine = E::standard(); + + let mut base64_to_bytes = collections::HashMap::new(); + + for b in 0_u8..=255 { + let mut b64 = vec![0_u8; 4]; + assert_eq!(2, engine.internal_encode(&[b], &mut b64[..])); + let _ = add_padding(2, &mut b64[2..]); + + assert!(base64_to_bytes.insert(b64, vec![b]).is_none()); + } + + // every possible combination of trailing symbols must either decode to 1 byte or get InvalidLastSymbol, with or without any leading chunks + + let mut prefix = Vec::new(); + for _ in 0..256 { + let mut clone = prefix.clone(); + + let mut symbols = [0_u8; 4]; + for &s1 in STANDARD.symbols.iter() { + symbols[0] = s1; + for &s2 in STANDARD.symbols.iter() { + symbols[1] = s2; + symbols[2] = PAD_BYTE; + symbols[3] = PAD_BYTE; + + // chop off previous symbols + clone.truncate(prefix.len()); + clone.extend_from_slice(&symbols[..]); + let decoded_prefix_len = prefix.len() / 4 * 3; + + match base64_to_bytes.get(&symbols[..]) { + Some(bytes) => { + let res = engine + .decode(&clone) + // remove prefix + .map(|decoded| decoded[decoded_prefix_len..].to_vec()); + + assert_eq!(Ok(bytes.clone()), res); + } + None => assert_eq!( + Err(DecodeError::InvalidLastSymbol(1, s2)), + engine.decode(&symbols[..]) + ), + } + } + } + + prefix.extend_from_slice(b"AAAA"); + } +} + +#[apply(all_engines)] +fn decode_detect_invalid_last_symbol_every_possible_three_symbols( + engine_wrapper: E, +) { + let engine = E::standard(); + + let mut base64_to_bytes = collections::HashMap::new(); + + let mut bytes = [0_u8; 2]; + for b1 in 0_u8..=255 { + bytes[0] = b1; + for b2 in 0_u8..=255 { + bytes[1] = b2; + let mut b64 = vec![0_u8; 4]; + assert_eq!(3, engine.internal_encode(&bytes, &mut b64[..])); + let _ = add_padding(3, &mut b64[3..]); + + let mut v = Vec::with_capacity(2); + v.extend_from_slice(&bytes[..]); + + assert!(base64_to_bytes.insert(b64, v).is_none()); + } + } + + // every possible combination of symbols must either decode to 2 bytes or get InvalidLastSymbol, with or without any leading chunks + + let mut prefix = Vec::new(); + for _ in 0..256 { + let mut input = prefix.clone(); + + let mut symbols = [0_u8; 4]; + for &s1 in STANDARD.symbols.iter() { + symbols[0] = s1; + for &s2 in STANDARD.symbols.iter() { + symbols[1] = s2; + for &s3 in STANDARD.symbols.iter() { + symbols[2] = s3; + symbols[3] = PAD_BYTE; + + // chop off previous symbols + input.truncate(prefix.len()); + input.extend_from_slice(&symbols[..]); + let decoded_prefix_len = prefix.len() / 4 * 3; + + match base64_to_bytes.get(&symbols[..]) { + Some(bytes) => { + let res = engine + .decode(&input) + // remove prefix + .map(|decoded| decoded[decoded_prefix_len..].to_vec()); + + assert_eq!(Ok(bytes.clone()), res); + } + None => assert_eq!( + Err(DecodeError::InvalidLastSymbol(2, s3)), + engine.decode(&symbols[..]) + ), + } + } + } + } + prefix.extend_from_slice(b"AAAA"); + } +} + +#[apply(all_engines)] +fn decode_invalid_trailing_bits_ignored_when_configured(engine_wrapper: E) { + let strict = E::standard(); + let forgiving = E::standard_allow_trailing_bits(); + + fn assert_tolerant_decode( + engine: &E, + input: &mut String, + b64_prefix_len: usize, + expected_decode_bytes: Vec, + data: &str, + ) { + let prefixed = prefixed_data(input, b64_prefix_len, data); + let decoded = engine.decode(prefixed); + // prefix is always complete chunks + let decoded_prefix_len = b64_prefix_len / 4 * 3; + assert_eq!( + Ok(expected_decode_bytes), + decoded.map(|v| v[decoded_prefix_len..].to_vec()) + ); + } + + let mut prefix = String::new(); + for _ in 0..256 { + let mut input = prefix.clone(); + + // example from https://github.com/marshallpierce/rust-base64/issues/75 + assert!(strict + .decode(prefixed_data(&mut input, prefix.len(), "/w==")) + .is_ok()); + assert!(strict + .decode(prefixed_data(&mut input, prefix.len(), "iYU=")) + .is_ok()); + // trailing 01 + assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![255], "/x=="); + assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![137, 133], "iYV="); + // trailing 10 + assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![255], "/y=="); + assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![137, 133], "iYW="); + // trailing 11 + assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![255], "/z=="); + assert_tolerant_decode(&forgiving, &mut input, prefix.len(), vec![137, 133], "iYX="); + + prefix.push_str("AAAA"); + } +} + +#[apply(all_engines)] +fn decode_invalid_byte_error(engine_wrapper: E) { + let mut rng = seeded_rng(); + + let mut orig_data = Vec::::new(); + let mut encode_buf = Vec::::new(); + let mut decode_buf = Vec::::new(); + + let len_range = distributions::Uniform::new(1, 1_000); + + for _ in 0..100_000 { + let alphabet = random_alphabet(&mut rng); + let engine = E::random_alphabet(&mut rng, alphabet); + + orig_data.clear(); + encode_buf.clear(); + decode_buf.clear(); + + let (orig_len, encoded_len_just_data, encoded_len_with_padding) = + generate_random_encoded_data( + &engine, + &mut orig_data, + &mut encode_buf, + &mut rng, + &len_range, + ); + + // exactly the right size + decode_buf.resize(orig_len, 0); + + // replace one encoded byte with an invalid byte + let invalid_byte: u8 = loop { + let byte: u8 = rng.gen(); + + if alphabet.symbols.contains(&byte) || byte == PAD_BYTE { + continue; + } else { + break byte; + } + }; + + let invalid_range = distributions::Uniform::new(0, orig_len); + let invalid_index = invalid_range.sample(&mut rng); + encode_buf[invalid_index] = invalid_byte; + + assert_eq!( + Err(DecodeError::InvalidByte(invalid_index, invalid_byte)), + engine.decode_slice_unchecked( + &encode_buf[0..encoded_len_with_padding], + &mut decode_buf[..], + ) + ); + } +} + +/// Any amount of padding anywhere before the final non padding character = invalid byte at first +/// pad byte. +/// From this, we know padding must extend to the end of the input. +// DecoderReader pseudo-engine detects InvalidLastSymbol instead of InvalidLength because it +// can end a decode on the quad that happens to contain the start of the padding +#[apply(all_engines_except_decoder_reader)] +fn decode_padding_before_final_non_padding_char_error_invalid_byte( + engine_wrapper: E, +) { + let mut rng = seeded_rng(); + + // the different amounts of proper padding, w/ offset from end for the last non-padding char + let suffixes = [("/w==", 2), ("iYu=", 1), ("zzzz", 0)]; + + let prefix_quads_range = distributions::Uniform::from(0..=256); + + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for _ in 0..100_000 { + for (suffix, offset) in suffixes.iter() { + let mut s = "ABCD".repeat(prefix_quads_range.sample(&mut rng)); + s.push_str(suffix); + let mut encoded = s.into_bytes(); + + // calculate a range to write padding into that leaves at least one non padding char + let last_non_padding_offset = encoded.len() - 1 - offset; + + // don't include last non padding char as it must stay not padding + let padding_end = rng.gen_range(0..last_non_padding_offset); + + // don't use more than 100 bytes of padding, but also use shorter lengths when + // padding_end is near the start of the encoded data to avoid biasing to padding + // the entire prefix on short lengths + let padding_len = rng.gen_range(1..=usize::min(100, padding_end + 1)); + let padding_start = padding_end.saturating_sub(padding_len); + + encoded[padding_start..=padding_end].fill(PAD_BYTE); + + assert_eq!( + Err(DecodeError::InvalidByte(padding_start, PAD_BYTE)), + engine.decode(&encoded), + ); + } + } + } +} + +/// Any amount of padding before final chunk that crosses over into final chunk with 2-4 bytes = +/// invalid byte at first pad byte. +/// From this and [decode_padding_starts_before_final_chunk_error_invalid_length] we know the +/// padding must start in the final chunk. +// DecoderReader pseudo-engine detects InvalidLastSymbol instead of InvalidLength because it +// can end a decode on the quad that happens to contain the start of the padding +#[apply(all_engines_except_decoder_reader)] +fn decode_padding_starts_before_final_chunk_error_invalid_byte( + engine_wrapper: E, +) { + let mut rng = seeded_rng(); + + // must have at least one prefix quad + let prefix_quads_range = distributions::Uniform::from(1..256); + // excluding 1 since we don't care about invalid length in this test + let suffix_pad_len_range = distributions::Uniform::from(2..=4); + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + for _ in 0..100_000 { + let suffix_len = suffix_pad_len_range.sample(&mut rng); + let mut encoded = "ABCD" + .repeat(prefix_quads_range.sample(&mut rng)) + .into_bytes(); + encoded.resize(encoded.len() + suffix_len, PAD_BYTE); + + // amount of padding must be long enough to extend back from suffix into previous + // quads + let padding_len = rng.gen_range(suffix_len + 1..encoded.len()); + // no non-padding after padding in this test, so padding goes to the end + let padding_start = encoded.len() - padding_len; + encoded[padding_start..].fill(PAD_BYTE); + + assert_eq!( + Err(DecodeError::InvalidByte(padding_start, PAD_BYTE)), + engine.decode(&encoded), + "suffix_len: {}, padding_len: {}, b64: {}", + suffix_len, + padding_len, + std::str::from_utf8(&encoded).unwrap() + ); + } + } +} + +/// Any amount of padding before final chunk that crosses over into final chunk with 1 byte = +/// invalid length. +/// From this we know the padding must start in the final chunk. +// DecoderReader pseudo-engine detects InvalidByte instead of InvalidLength because it starts by +// decoding only the available complete quads +#[apply(all_engines_except_decoder_reader)] +fn decode_padding_starts_before_final_chunk_error_invalid_length( + engine_wrapper: E, +) { + let mut rng = seeded_rng(); + + // must have at least one prefix quad + let prefix_quads_range = distributions::Uniform::from(1..256); + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + for _ in 0..100_000 { + let mut encoded = "ABCD" + .repeat(prefix_quads_range.sample(&mut rng)) + .into_bytes(); + encoded.resize(encoded.len() + 1, PAD_BYTE); + + // amount of padding must be long enough to extend back from suffix into previous + // quads + let padding_len = rng.gen_range(1 + 1..encoded.len()); + // no non-padding after padding in this test, so padding goes to the end + let padding_start = encoded.len() - padding_len; + encoded[padding_start..].fill(PAD_BYTE); + + assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&encoded),); + } + } +} + +/// 0-1 bytes of data before any amount of padding in final chunk = invalid byte, since padding +/// is not valid data (consistent with error for pad bytes in earlier chunks). +/// From this we know there must be 2-3 bytes of data before padding +#[apply(all_engines)] +fn decode_too_little_data_before_padding_error_invalid_byte(engine_wrapper: E) { + let mut rng = seeded_rng(); + + // want to test no prefix quad case, so start at 0 + let prefix_quads_range = distributions::Uniform::from(0_usize..256); + let suffix_data_len_range = distributions::Uniform::from(0_usize..=1); + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + for _ in 0..100_000 { + let suffix_data_len = suffix_data_len_range.sample(&mut rng); + let prefix_quad_len = prefix_quads_range.sample(&mut rng); + + // ensure there is a suffix quad + let min_padding = usize::from(suffix_data_len == 0); + + // for all possible padding lengths + for padding_len in min_padding..=(4 - suffix_data_len) { + let mut encoded = "ABCD".repeat(prefix_quad_len).into_bytes(); + encoded.resize(encoded.len() + suffix_data_len, b'A'); + encoded.resize(encoded.len() + padding_len, PAD_BYTE); + + if suffix_data_len + padding_len == 1 { + assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&encoded),); + } else { + assert_eq!( + Err(DecodeError::InvalidByte( + prefix_quad_len * 4 + suffix_data_len, + PAD_BYTE, + )), + engine.decode(&encoded), + "suffix data len {} pad len {}", + suffix_data_len, + padding_len + ); + } + } + } + } +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 1 +#[apply(all_engines)] +fn decode_malleability_test_case_3_byte_suffix_valid(engine_wrapper: E) { + assert_eq!( + b"Hello".as_slice(), + &E::standard().decode("SGVsbG8=").unwrap() + ); +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 2 +#[apply(all_engines)] +fn decode_malleability_test_case_3_byte_suffix_invalid_trailing_symbol( + engine_wrapper: E, +) { + assert_eq!( + DecodeError::InvalidLastSymbol(6, 0x39), + E::standard().decode("SGVsbG9=").unwrap_err() + ); +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 3 +#[apply(all_engines)] +fn decode_malleability_test_case_3_byte_suffix_no_padding(engine_wrapper: E) { + assert_eq!( + DecodeError::InvalidPadding, + E::standard().decode("SGVsbG9").unwrap_err() + ); +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 4 +#[apply(all_engines)] +fn decode_malleability_test_case_2_byte_suffix_valid_two_padding_symbols( + engine_wrapper: E, +) { + assert_eq!( + b"Hell".as_slice(), + &E::standard().decode("SGVsbA==").unwrap() + ); +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 5 +#[apply(all_engines)] +fn decode_malleability_test_case_2_byte_suffix_short_padding(engine_wrapper: E) { + assert_eq!( + DecodeError::InvalidPadding, + E::standard().decode("SGVsbA=").unwrap_err() + ); +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 6 +#[apply(all_engines)] +fn decode_malleability_test_case_2_byte_suffix_no_padding(engine_wrapper: E) { + assert_eq!( + DecodeError::InvalidPadding, + E::standard().decode("SGVsbA").unwrap_err() + ); +} + +// https://eprint.iacr.org/2022/361.pdf table 2, test 7 +// DecoderReader pseudo-engine gets InvalidByte at 8 (extra padding) since it decodes the first +// two complete quads correctly. +#[apply(all_engines_except_decoder_reader)] +fn decode_malleability_test_case_2_byte_suffix_too_much_padding( + engine_wrapper: E, +) { + assert_eq!( + DecodeError::InvalidByte(6, PAD_BYTE), + E::standard().decode("SGVsbA====").unwrap_err() + ); +} + +/// Requires canonical padding -> accepts 2 + 2, 3 + 1, 4 + 0 final quad configurations +#[apply(all_engines)] +fn decode_pad_mode_requires_canonical_accepts_canonical(engine_wrapper: E) { + assert_all_suffixes_ok( + E::standard_with_pad_mode(true, DecodePaddingMode::RequireCanonical), + vec!["/w==", "iYU=", "AAAA"], + ); +} + +/// Requires canonical padding -> rejects 2 + 0-1, 3 + 0 final chunk configurations +#[apply(all_engines)] +fn decode_pad_mode_requires_canonical_rejects_non_canonical(engine_wrapper: E) { + let engine = E::standard_with_pad_mode(true, DecodePaddingMode::RequireCanonical); + + let suffixes = ["/w", "/w=", "iYU"]; + for num_prefix_quads in 0..256 { + for &suffix in suffixes.iter() { + let mut encoded = "AAAA".repeat(num_prefix_quads); + encoded.push_str(suffix); + + let res = engine.decode(&encoded); + + assert_eq!(Err(DecodeError::InvalidPadding), res); + } + } +} + +/// Requires no padding -> accepts 2 + 0, 3 + 0, 4 + 0 final chunk configuration +#[apply(all_engines)] +fn decode_pad_mode_requires_no_padding_accepts_no_padding(engine_wrapper: E) { + assert_all_suffixes_ok( + E::standard_with_pad_mode(true, DecodePaddingMode::RequireNone), + vec!["/w", "iYU", "AAAA"], + ); +} + +/// Requires no padding -> rejects 2 + 1-2, 3 + 1 final chunk configuration +#[apply(all_engines)] +fn decode_pad_mode_requires_no_padding_rejects_any_padding(engine_wrapper: E) { + let engine = E::standard_with_pad_mode(true, DecodePaddingMode::RequireNone); + + let suffixes = ["/w=", "/w==", "iYU="]; + for num_prefix_quads in 0..256 { + for &suffix in suffixes.iter() { + let mut encoded = "AAAA".repeat(num_prefix_quads); + encoded.push_str(suffix); + + let res = engine.decode(&encoded); + + assert_eq!(Err(DecodeError::InvalidPadding), res); + } + } +} + +/// Indifferent padding accepts 2 + 0-2, 3 + 0-1, 4 + 0 final chunk configuration +#[apply(all_engines)] +fn decode_pad_mode_indifferent_padding_accepts_anything(engine_wrapper: E) { + assert_all_suffixes_ok( + E::standard_with_pad_mode(true, DecodePaddingMode::Indifferent), + vec!["/w", "/w=", "/w==", "iYU", "iYU=", "AAAA"], + ); +} + +//this is a MAY in the rfc: https://tools.ietf.org/html/rfc4648#section-3.3 +// DecoderReader pseudo-engine finds the first padding, but doesn't report it as an error, +// because in the next decode it finds more padding, which is reported as InvalidByte, just +// with an offset at its position in the second decode, rather than being linked to the start +// of the padding that was first seen in the previous decode. +#[apply(all_engines_except_decoder_reader)] +fn decode_pad_byte_in_penultimate_quad_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + // leave room for at least one pad byte in penultimate quad + for num_valid_bytes_penultimate_quad in 0..4 { + // can't have 1 or it would be invalid length + for num_pad_bytes_in_final_quad in 2..=4 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + + // varying amounts of padding in the penultimate quad + for _ in 0..num_valid_bytes_penultimate_quad { + s.push('A'); + } + // finish penultimate quad with padding + for _ in num_valid_bytes_penultimate_quad..4 { + s.push('='); + } + // and more padding in the final quad + for _ in 0..num_pad_bytes_in_final_quad { + s.push('='); + } + + // padding should be an invalid byte before the final quad. + // Could argue that the *next* padding byte (in the next quad) is technically the first + // erroneous one, but reporting that accurately is more complex and probably nobody cares + assert_eq!( + DecodeError::InvalidByte( + num_prefix_quads * 4 + num_valid_bytes_penultimate_quad, + b'=', + ), + engine.decode(&s).unwrap_err(), + ); + } + } + } + } +} + +#[apply(all_engines)] +fn decode_bytes_after_padding_in_final_quad_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + // leave at least one byte in the quad for padding + for bytes_after_padding in 1..4 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + + // every invalid padding position with a 3-byte final quad: 1 to 3 bytes after padding + for _ in 0..(3 - bytes_after_padding) { + s.push('A'); + } + s.push('='); + for _ in 0..bytes_after_padding { + s.push('A'); + } + + // First (and only) padding byte is invalid. + assert_eq!( + DecodeError::InvalidByte( + num_prefix_quads * 4 + (3 - bytes_after_padding), + b'=' + ), + engine.decode(&s).unwrap_err() + ); + } + } + } +} + +#[apply(all_engines)] +fn decode_absurd_pad_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + s.push_str("==Y=Wx===pY=2U====="); + + // first padding byte + assert_eq!( + DecodeError::InvalidByte(num_prefix_quads * 4, b'='), + engine.decode(&s).unwrap_err() + ); + } + } +} + +// DecoderReader pseudo-engine detects InvalidByte instead of InvalidLength because it starts by +// decoding only the available complete quads +#[apply(all_engines_except_decoder_reader)] +fn decode_too_much_padding_returns_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + // add enough padding to ensure that we'll hit all decode stages at the different lengths + for pad_bytes in 1..=64 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + let padding: String = "=".repeat(pad_bytes); + s.push_str(&padding); + + if pad_bytes % 4 == 1 { + assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err()); + } else { + assert_eq!( + DecodeError::InvalidByte(num_prefix_quads * 4, b'='), + engine.decode(&s).unwrap_err() + ); + } + } + } + } +} + +// DecoderReader pseudo-engine detects InvalidByte instead of InvalidLength because it starts by +// decoding only the available complete quads +#[apply(all_engines_except_decoder_reader)] +fn decode_padding_followed_by_non_padding_returns_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + for pad_bytes in 0..=32 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + let padding: String = "=".repeat(pad_bytes); + s.push_str(&padding); + s.push('E'); + + if pad_bytes % 4 == 0 { + assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err()); + } else { + assert_eq!( + DecodeError::InvalidByte(num_prefix_quads * 4, b'='), + engine.decode(&s).unwrap_err() + ); + } + } + } + } +} + +#[apply(all_engines)] +fn decode_one_char_in_final_quad_with_padding_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + s.push_str("E="); + + assert_eq!( + DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='), + engine.decode(&s).unwrap_err() + ); + + // more padding doesn't change the error + s.push('='); + assert_eq!( + DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='), + engine.decode(&s).unwrap_err() + ); + + s.push('='); + assert_eq!( + DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='), + engine.decode(&s).unwrap_err() + ); + } + } +} + +#[apply(all_engines)] +fn decode_too_few_symbols_in_final_quad_error(engine_wrapper: E) { + for mode in all_pad_modes() { + // we don't encode so we don't care about encode padding + let engine = E::standard_with_pad_mode(true, mode); + + for num_prefix_quads in 0..256 { + // <2 is invalid + for final_quad_symbols in 0..2 { + for padding_symbols in 0..=(4 - final_quad_symbols) { + let mut s: String = "ABCD".repeat(num_prefix_quads); + + for _ in 0..final_quad_symbols { + s.push('A'); + } + for _ in 0..padding_symbols { + s.push('='); + } + + match final_quad_symbols + padding_symbols { + 0 => continue, + 1 => { + assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err()); + } + _ => { + // error reported at first padding byte + assert_eq!( + DecodeError::InvalidByte( + num_prefix_quads * 4 + final_quad_symbols, + b'=', + ), + engine.decode(&s).unwrap_err() + ); + } + } + } + } + } + } +} + +// DecoderReader pseudo-engine can't handle DecodePaddingMode::RequireNone since it will decode +// a complete quad with padding in it before encountering the stray byte that makes it an invalid +// length +#[apply(all_engines_except_decoder_reader)] +fn decode_invalid_trailing_bytes(engine_wrapper: E) { + for mode in all_pad_modes() { + do_invalid_trailing_byte(E::standard_with_pad_mode(true, mode), mode); + } +} + +#[apply(all_engines)] +fn decode_invalid_trailing_bytes_all_modes(engine_wrapper: E) { + // excluding no padding mode because the DecoderWrapper pseudo-engine will fail with + // InvalidPadding because it will decode the last complete quad with padding first + for mode in pad_modes_allowing_padding() { + do_invalid_trailing_byte(E::standard_with_pad_mode(true, mode), mode); + } +} + +#[apply(all_engines)] +fn decode_invalid_trailing_padding_as_invalid_length(engine_wrapper: E) { + // excluding no padding mode because the DecoderWrapper pseudo-engine will fail with + // InvalidPadding because it will decode the last complete quad with padding first + for mode in pad_modes_allowing_padding() { + do_invalid_trailing_padding_as_invalid_length(E::standard_with_pad_mode(true, mode), mode); + } +} + +// DecoderReader pseudo-engine can't handle DecodePaddingMode::RequireNone since it will decode +// a complete quad with padding in it before encountering the stray byte that makes it an invalid +// length +#[apply(all_engines_except_decoder_reader)] +fn decode_invalid_trailing_padding_as_invalid_length_all_modes( + engine_wrapper: E, +) { + for mode in all_pad_modes() { + do_invalid_trailing_padding_as_invalid_length(E::standard_with_pad_mode(true, mode), mode); + } +} + +#[apply(all_engines)] +fn decode_wrong_length_error(engine_wrapper: E) { + let engine = E::standard_with_pad_mode(true, DecodePaddingMode::Indifferent); + + for num_prefix_quads in 0..256 { + // at least one token, otherwise it wouldn't be a final quad + for num_tokens_final_quad in 1..=4 { + for num_padding in 0..=(4 - num_tokens_final_quad) { + let mut s: String = "IIII".repeat(num_prefix_quads); + for _ in 0..num_tokens_final_quad { + s.push('g'); + } + for _ in 0..num_padding { + s.push('='); + } + + let res = engine.decode(&s); + if num_tokens_final_quad >= 2 { + assert!(res.is_ok()); + } else if num_tokens_final_quad == 1 && num_padding > 0 { + // = is invalid if it's too early + assert_eq!( + Err(DecodeError::InvalidByte( + num_prefix_quads * 4 + num_tokens_final_quad, + 61 + )), + res + ); + } else if num_padding > 2 { + assert_eq!(Err(DecodeError::InvalidPadding), res); + } else { + assert_eq!(Err(DecodeError::InvalidLength), res); + } + } + } + } +} + +#[apply(all_engines)] +fn decode_into_slice_fits_in_precisely_sized_slice(engine_wrapper: E) { + let mut orig_data = Vec::new(); + let mut encoded_data = String::new(); + let mut decode_buf = Vec::new(); + + let input_len_range = distributions::Uniform::new(0, 1000); + let mut rng = rngs::SmallRng::from_entropy(); + + for _ in 0..10_000 { + orig_data.clear(); + encoded_data.clear(); + decode_buf.clear(); + + let input_len = input_len_range.sample(&mut rng); + + for _ in 0..input_len { + orig_data.push(rng.gen()); + } + + let engine = E::random(&mut rng); + engine.encode_string(&orig_data, &mut encoded_data); + assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len); + + decode_buf.resize(input_len, 0); + + // decode into the non-empty buf + let decode_bytes_written = engine + .decode_slice_unchecked(encoded_data.as_bytes(), &mut decode_buf[..]) + .unwrap(); + + assert_eq!(orig_data.len(), decode_bytes_written); + assert_eq!(orig_data, decode_buf); + } +} + +#[apply(all_engines)] +fn inner_decode_reports_padding_position(engine_wrapper: E) { + let mut b64 = String::new(); + let mut decoded = Vec::new(); + let engine = E::standard(); + + for pad_position in 1..10_000 { + b64.clear(); + decoded.clear(); + // plenty of room for original data + decoded.resize(pad_position, 0); + + for _ in 0..pad_position { + b64.push('A'); + } + // finish the quad with padding + for _ in 0..(4 - (pad_position % 4)) { + b64.push('='); + } + + let decode_res = engine.internal_decode( + b64.as_bytes(), + &mut decoded[..], + engine.internal_decoded_len_estimate(b64.len()), + ); + if pad_position % 4 < 2 { + // impossible padding + assert_eq!( + Err(DecodeError::InvalidByte(pad_position, PAD_BYTE)), + decode_res + ); + } else { + let decoded_bytes = pad_position / 4 * 3 + + match pad_position % 4 { + 0 => 0, + 2 => 1, + 3 => 2, + _ => unreachable!(), + }; + assert_eq!( + Ok(DecodeMetadata::new(decoded_bytes, Some(pad_position))), + decode_res + ); + } + } +} + +#[apply(all_engines)] +fn decode_length_estimate_delta(engine_wrapper: E) { + for engine in [E::standard(), E::standard_unpadded()] { + for &padding in &[true, false] { + for orig_len in 0..1000 { + let encoded_len = encoded_len(orig_len, padding).unwrap(); + + let decoded_estimate = engine + .internal_decoded_len_estimate(encoded_len) + .decoded_len_estimate(); + assert!(decoded_estimate >= orig_len); + assert!( + decoded_estimate - orig_len < 3, + "estimate: {}, encoded: {}, orig: {}", + decoded_estimate, + encoded_len, + orig_len + ); + } + } + } +} + +#[apply(all_engines)] +fn estimate_via_u128_inflation(engine_wrapper: E) { + // cover both ends of usize + (0..1000) + .chain(usize::MAX - 1000..=usize::MAX) + .for_each(|encoded_len| { + // inflate to 128 bit type to be able to safely use the easy formulas + let len_128 = encoded_len as u128; + + let estimate = E::standard() + .internal_decoded_len_estimate(encoded_len) + .decoded_len_estimate(); + + // This check is a little too strict: it requires using the (len + 3) / 4 * 3 formula + // or equivalent, but until other engines come along that use a different formula + // requiring that we think more carefully about what the allowable criteria are, this + // will do. + assert_eq!( + ((len_128 + 3) / 4 * 3) as usize, + estimate, + "enc len {}", + encoded_len + ); + }) +} + +fn do_invalid_trailing_byte(engine: impl Engine, mode: DecodePaddingMode) { + for num_prefix_quads in 0..256 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + s.push_str("Cg==\n"); + + // The case of trailing newlines is common enough to warrant a test for a good error + // message. + assert_eq!( + Err(DecodeError::InvalidByte(num_prefix_quads * 4 + 4, b'\n')), + engine.decode(&s), + "mode: {:?}, input: {}", + mode, + s + ); + } +} + +fn do_invalid_trailing_padding_as_invalid_length(engine: impl Engine, mode: DecodePaddingMode) { + for num_prefix_quads in 0..256 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + s.push_str("Cg==="); + + assert_eq!( + Err(DecodeError::InvalidLength), + engine.decode(&s), + "mode: {:?}, input: {}", + mode, + s + ); + } +} + +/// Returns a tuple of the original data length, the encoded data length (just data), and the length including padding. +/// +/// Vecs provided should be empty. +fn generate_random_encoded_data>( + engine: &E, + orig_data: &mut Vec, + encode_buf: &mut Vec, + rng: &mut R, + length_distribution: &D, +) -> (usize, usize, usize) { + let padding: bool = engine.config().encode_padding(); + + let orig_len = fill_rand(orig_data, rng, length_distribution); + let expected_encoded_len = encoded_len(orig_len, padding).unwrap(); + encode_buf.resize(expected_encoded_len, 0); + + let base_encoded_len = engine.internal_encode(&orig_data[..], &mut encode_buf[..]); + + let enc_len_with_padding = if padding { + base_encoded_len + add_padding(base_encoded_len, &mut encode_buf[base_encoded_len..]) + } else { + base_encoded_len + }; + + assert_eq!(expected_encoded_len, enc_len_with_padding); + + (orig_len, base_encoded_len, enc_len_with_padding) +} + +// fill to a random length +fn fill_rand>( + vec: &mut Vec, + rng: &mut R, + length_distribution: &D, +) -> usize { + let len = length_distribution.sample(rng); + for _ in 0..len { + vec.push(rng.gen()); + } + + len +} + +fn fill_rand_len(vec: &mut Vec, rng: &mut R, len: usize) { + for _ in 0..len { + vec.push(rng.gen()); + } +} + +fn prefixed_data<'i>(input_with_prefix: &'i mut String, prefix_len: usize, data: &str) -> &'i str { + input_with_prefix.truncate(prefix_len); + input_with_prefix.push_str(data); + input_with_prefix.as_str() +} + +/// A wrapper to make using engines in rstest fixtures easier. +/// The functions don't need to be instance methods, but rstest does seem +/// to want an instance, so instances are passed to test functions and then ignored. +trait EngineWrapper { + type Engine: Engine; + + /// Return an engine configured for RFC standard base64 + fn standard() -> Self::Engine; + + /// Return an engine configured for RFC standard base64, except with no padding appended on + /// encode, and required no padding on decode. + fn standard_unpadded() -> Self::Engine; + + /// Return an engine configured for RFC standard alphabet with the provided encode and decode + /// pad settings + fn standard_with_pad_mode(encode_pad: bool, decode_pad_mode: DecodePaddingMode) + -> Self::Engine; + + /// Return an engine configured for RFC standard base64 that allows invalid trailing bits + fn standard_allow_trailing_bits() -> Self::Engine; + + /// Return an engine configured with a randomized alphabet and config + fn random(rng: &mut R) -> Self::Engine; + + /// Return an engine configured with the specified alphabet and randomized config + fn random_alphabet(rng: &mut R, alphabet: &Alphabet) -> Self::Engine; +} + +struct GeneralPurposeWrapper {} + +impl EngineWrapper for GeneralPurposeWrapper { + type Engine = general_purpose::GeneralPurpose; + + fn standard() -> Self::Engine { + general_purpose::GeneralPurpose::new(&STANDARD, general_purpose::PAD) + } + + fn standard_unpadded() -> Self::Engine { + general_purpose::GeneralPurpose::new(&STANDARD, general_purpose::NO_PAD) + } + + fn standard_with_pad_mode( + encode_pad: bool, + decode_pad_mode: DecodePaddingMode, + ) -> Self::Engine { + general_purpose::GeneralPurpose::new( + &STANDARD, + general_purpose::GeneralPurposeConfig::new() + .with_encode_padding(encode_pad) + .with_decode_padding_mode(decode_pad_mode), + ) + } + + fn standard_allow_trailing_bits() -> Self::Engine { + general_purpose::GeneralPurpose::new( + &STANDARD, + general_purpose::GeneralPurposeConfig::new().with_decode_allow_trailing_bits(true), + ) + } + + fn random(rng: &mut R) -> Self::Engine { + let alphabet = random_alphabet(rng); + + Self::random_alphabet(rng, alphabet) + } + + fn random_alphabet(rng: &mut R, alphabet: &Alphabet) -> Self::Engine { + general_purpose::GeneralPurpose::new(alphabet, random_config(rng)) + } +} + +struct NaiveWrapper {} + +impl EngineWrapper for NaiveWrapper { + type Engine = naive::Naive; + + fn standard() -> Self::Engine { + naive::Naive::new( + &STANDARD, + naive::NaiveConfig { + encode_padding: true, + decode_allow_trailing_bits: false, + decode_padding_mode: DecodePaddingMode::RequireCanonical, + }, + ) + } + + fn standard_unpadded() -> Self::Engine { + naive::Naive::new( + &STANDARD, + naive::NaiveConfig { + encode_padding: false, + decode_allow_trailing_bits: false, + decode_padding_mode: DecodePaddingMode::RequireNone, + }, + ) + } + + fn standard_with_pad_mode( + encode_pad: bool, + decode_pad_mode: DecodePaddingMode, + ) -> Self::Engine { + naive::Naive::new( + &STANDARD, + naive::NaiveConfig { + encode_padding: false, + decode_allow_trailing_bits: false, + decode_padding_mode: decode_pad_mode, + }, + ) + } + + fn standard_allow_trailing_bits() -> Self::Engine { + naive::Naive::new( + &STANDARD, + naive::NaiveConfig { + encode_padding: true, + decode_allow_trailing_bits: true, + decode_padding_mode: DecodePaddingMode::RequireCanonical, + }, + ) + } + + fn random(rng: &mut R) -> Self::Engine { + let alphabet = random_alphabet(rng); + + Self::random_alphabet(rng, alphabet) + } + + fn random_alphabet(rng: &mut R, alphabet: &Alphabet) -> Self::Engine { + let mode = rng.gen(); + + let config = naive::NaiveConfig { + encode_padding: match mode { + DecodePaddingMode::Indifferent => rng.gen(), + DecodePaddingMode::RequireCanonical => true, + DecodePaddingMode::RequireNone => false, + }, + decode_allow_trailing_bits: rng.gen(), + decode_padding_mode: mode, + }; + + naive::Naive::new(alphabet, config) + } +} + +/// A pseudo-Engine that routes all decoding through [DecoderReader] +struct DecoderReaderEngine { + engine: E, +} + +impl From for DecoderReaderEngine { + fn from(value: E) -> Self { + Self { engine: value } + } +} + +impl Engine for DecoderReaderEngine { + type Config = E::Config; + type DecodeEstimate = E::DecodeEstimate; + + fn internal_encode(&self, input: &[u8], output: &mut [u8]) -> usize { + self.engine.internal_encode(input, output) + } + + fn internal_decoded_len_estimate(&self, input_len: usize) -> Self::DecodeEstimate { + self.engine.internal_decoded_len_estimate(input_len) + } + + fn internal_decode( + &self, + input: &[u8], + output: &mut [u8], + decode_estimate: Self::DecodeEstimate, + ) -> Result { + let mut reader = DecoderReader::new(input, &self.engine); + let mut buf = vec![0; input.len()]; + // to avoid effects like not detecting invalid length due to progressively growing + // the output buffer in read_to_end etc, read into a big enough buffer in one go + // to make behavior more consistent with normal engines + let _ = reader + .read(&mut buf) + .and_then(|len| { + buf.truncate(len); + // make sure we got everything + reader.read_to_end(&mut buf) + }) + .map_err(|io_error| { + *io_error + .into_inner() + .and_then(|inner| inner.downcast::().ok()) + .unwrap() + })?; + output[..buf.len()].copy_from_slice(&buf); + Ok(DecodeMetadata::new( + buf.len(), + input + .iter() + .enumerate() + .filter(|(_offset, byte)| **byte == PAD_BYTE) + .map(|(offset, _byte)| offset) + .next(), + )) + } + + fn config(&self) -> &Self::Config { + self.engine.config() + } +} + +struct DecoderReaderEngineWrapper {} + +impl EngineWrapper for DecoderReaderEngineWrapper { + type Engine = DecoderReaderEngine; + + fn standard() -> Self::Engine { + GeneralPurposeWrapper::standard().into() + } + + fn standard_unpadded() -> Self::Engine { + GeneralPurposeWrapper::standard_unpadded().into() + } + + fn standard_with_pad_mode( + encode_pad: bool, + decode_pad_mode: DecodePaddingMode, + ) -> Self::Engine { + GeneralPurposeWrapper::standard_with_pad_mode(encode_pad, decode_pad_mode).into() + } + + fn standard_allow_trailing_bits() -> Self::Engine { + GeneralPurposeWrapper::standard_allow_trailing_bits().into() + } + + fn random(rng: &mut R) -> Self::Engine { + GeneralPurposeWrapper::random(rng).into() + } + + fn random_alphabet(rng: &mut R, alphabet: &Alphabet) -> Self::Engine { + GeneralPurposeWrapper::random_alphabet(rng, alphabet).into() + } +} + +fn seeded_rng() -> impl rand::Rng { + rngs::SmallRng::from_entropy() +} + +fn all_pad_modes() -> Vec { + vec![ + DecodePaddingMode::Indifferent, + DecodePaddingMode::RequireCanonical, + DecodePaddingMode::RequireNone, + ] +} + +fn pad_modes_allowing_padding() -> Vec { + vec![ + DecodePaddingMode::Indifferent, + DecodePaddingMode::RequireCanonical, + ] +} + +fn assert_all_suffixes_ok(engine: E, suffixes: Vec<&str>) { + for num_prefix_quads in 0..256 { + for &suffix in suffixes.iter() { + let mut encoded = "AAAA".repeat(num_prefix_quads); + encoded.push_str(suffix); + + let res = &engine.decode(&encoded); + assert!(res.is_ok()); + } + } +} diff --git a/vendor/base64-0.21.5/src/lib.rs b/vendor/base64-0.21.5/src/lib.rs new file mode 100644 index 00000000..6b11fa66 --- /dev/null +++ b/vendor/base64-0.21.5/src/lib.rs @@ -0,0 +1,179 @@ +//! # Getting started +//! +//! 1. Perhaps one of the preconfigured engines in [engine::general_purpose] will suit, e.g. +//! [engine::general_purpose::STANDARD_NO_PAD]. +//! - These are re-exported in [prelude] with a `BASE64_` prefix for those who prefer to +//! `use base64::prelude::*` or equivalent, e.g. [prelude::BASE64_STANDARD_NO_PAD] +//! 1. If not, choose which alphabet you want. Most usage will want [alphabet::STANDARD] or [alphabet::URL_SAFE]. +//! 1. Choose which [Engine] implementation you want. For the moment there is only one: [engine::GeneralPurpose]. +//! 1. Configure the engine appropriately using the engine's `Config` type. +//! - This is where you'll select whether to add padding (when encoding) or expect it (when +//! decoding). If given the choice, prefer no padding. +//! 1. Build the engine using the selected alphabet and config. +//! +//! For more detail, see below. +//! +//! ## Alphabets +//! +//! An [alphabet::Alphabet] defines what ASCII symbols are used to encode to or decode from. +//! +//! Constants in [alphabet] like [alphabet::STANDARD] or [alphabet::URL_SAFE] provide commonly used +//! alphabets, but you can also build your own custom [alphabet::Alphabet] if needed. +//! +//! ## Engines +//! +//! Once you have an `Alphabet`, you can pick which `Engine` you want. A few parts of the public +//! API provide a default, but otherwise the user must provide an `Engine` to use. +//! +//! See [Engine] for more. +//! +//! ## Config +//! +//! In addition to an `Alphabet`, constructing an `Engine` also requires an [engine::Config]. Each +//! `Engine` has a corresponding `Config` implementation since different `Engine`s may offer different +//! levels of configurability. +//! +//! # Encoding +//! +//! Several different encoding methods on [Engine] are available to you depending on your desire for +//! convenience vs performance. +//! +//! | Method | Output | Allocates | +//! | ------------------------ | ---------------------------- | ------------------------------ | +//! | [Engine::encode] | Returns a new `String` | Always | +//! | [Engine::encode_string] | Appends to provided `String` | Only if `String` needs to grow | +//! | [Engine::encode_slice] | Writes to provided `&[u8]` | Never - fastest | +//! +//! All of the encoding methods will pad as per the engine's config. +//! +//! # Decoding +//! +//! Just as for encoding, there are different decoding methods available. +//! +//! | Method | Output | Allocates | +//! | ------------------------ | ----------------------------- | ------------------------------ | +//! | [Engine::decode] | Returns a new `Vec` | Always | +//! | [Engine::decode_vec] | Appends to provided `Vec` | Only if `Vec` needs to grow | +//! | [Engine::decode_slice] | Writes to provided `&[u8]` | Never - fastest | +//! +//! Unlike encoding, where all possible input is valid, decoding can fail (see [DecodeError]). +//! +//! Input can be invalid because it has invalid characters or invalid padding. The nature of how +//! padding is checked depends on the engine's config. +//! Whitespace in the input is invalid, just like any other non-base64 byte. +//! +//! # `Read` and `Write` +//! +//! To decode a [std::io::Read] of b64 bytes, wrap a reader (file, network socket, etc) with +//! [read::DecoderReader]. +//! +//! To write raw bytes and have them b64 encoded on the fly, wrap a [std::io::Write] with +//! [write::EncoderWriter]. +//! +//! There is some performance overhead (15% or so) because of the necessary buffer shuffling -- +//! still fast enough that almost nobody cares. Also, these implementations do not heap allocate. +//! +//! # `Display` +//! +//! See [display] for how to transparently base64 data via a `Display` implementation. +//! +//! # Examples +//! +//! ## Using predefined engines +//! +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::{Engine as _, engine::general_purpose}; +//! +//! let orig = b"data"; +//! let encoded: String = general_purpose::STANDARD_NO_PAD.encode(orig); +//! assert_eq!("ZGF0YQ", encoded); +//! assert_eq!(orig.as_slice(), &general_purpose::STANDARD_NO_PAD.decode(encoded).unwrap()); +//! +//! // or, URL-safe +//! let encoded_url = general_purpose::URL_SAFE_NO_PAD.encode(orig); +//! ``` +//! +//! ## Custom alphabet, config, and engine +//! +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::{engine, alphabet, Engine as _}; +//! +//! // bizarro-world base64: +/ as the first symbols instead of the last +//! let alphabet = +//! alphabet::Alphabet::new("+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") +//! .unwrap(); +//! +//! // a very weird config that encodes with padding but requires no padding when decoding...? +//! let crazy_config = engine::GeneralPurposeConfig::new() +//! .with_decode_allow_trailing_bits(true) +//! .with_encode_padding(true) +//! .with_decode_padding_mode(engine::DecodePaddingMode::RequireNone); +//! +//! let crazy_engine = engine::GeneralPurpose::new(&alphabet, crazy_config); +//! +//! let encoded = crazy_engine.encode(b"abc 123"); +//! +//! ``` +//! +//! # Panics +//! +//! If length calculations result in overflowing `usize`, a panic will result. + +#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] +#![deny( + missing_docs, + trivial_casts, + trivial_numeric_casts, + unused_extern_crates, + unused_import_braces, + unused_results, + variant_size_differences, + warnings +)] +#![forbid(unsafe_code)] +// Allow globally until https://github.com/rust-lang/rust-clippy/issues/8768 is resolved. +// The desired state is to allow it only for the rstest_reuse import. +#![allow(clippy::single_component_path_imports)] +#![cfg_attr(not(any(feature = "std", test)), no_std)] + +#[cfg(any(feature = "alloc", test))] +extern crate alloc; + +// has to be included at top level because of the way rstest_reuse defines its macros +#[cfg(test)] +use rstest_reuse; + +mod chunked_encoder; +pub mod display; +#[cfg(any(feature = "std", test))] +pub mod read; +#[cfg(any(feature = "std", test))] +pub mod write; + +pub mod engine; +pub use engine::Engine; + +pub mod alphabet; + +mod encode; +#[allow(deprecated)] +#[cfg(any(feature = "alloc", test))] +pub use crate::encode::{encode, encode_engine, encode_engine_string}; +#[allow(deprecated)] +pub use crate::encode::{encode_engine_slice, encoded_len, EncodeSliceError}; + +mod decode; +#[allow(deprecated)] +#[cfg(any(feature = "alloc", test))] +pub use crate::decode::{decode, decode_engine, decode_engine_vec}; +#[allow(deprecated)] +pub use crate::decode::{decode_engine_slice, decoded_len_estimate, DecodeError, DecodeSliceError}; + +pub mod prelude; + +#[cfg(test)] +mod tests; + +const PAD_BYTE: u8 = b'='; diff --git a/vendor/base64-0.21.5/src/prelude.rs b/vendor/base64-0.21.5/src/prelude.rs new file mode 100644 index 00000000..df5fdb49 --- /dev/null +++ b/vendor/base64-0.21.5/src/prelude.rs @@ -0,0 +1,20 @@ +//! Preconfigured engines for common use cases. +//! +//! These are re-exports of `const` engines in [crate::engine::general_purpose], renamed with a `BASE64_` +//! prefix for those who prefer to `use` the entire path to a name. +//! +//! # Examples +//! +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::prelude::{Engine as _, BASE64_STANDARD_NO_PAD}; +//! +//! assert_eq!("c29tZSBieXRlcw", &BASE64_STANDARD_NO_PAD.encode(b"some bytes")); +//! ``` + +pub use crate::engine::Engine; + +pub use crate::engine::general_purpose::STANDARD as BASE64_STANDARD; +pub use crate::engine::general_purpose::STANDARD_NO_PAD as BASE64_STANDARD_NO_PAD; +pub use crate::engine::general_purpose::URL_SAFE as BASE64_URL_SAFE; +pub use crate::engine::general_purpose::URL_SAFE_NO_PAD as BASE64_URL_SAFE_NO_PAD; diff --git a/vendor/base64-0.21.5/src/read/decoder.rs b/vendor/base64-0.21.5/src/read/decoder.rs new file mode 100644 index 00000000..b656ae3d --- /dev/null +++ b/vendor/base64-0.21.5/src/read/decoder.rs @@ -0,0 +1,316 @@ +use crate::{engine::Engine, DecodeError, PAD_BYTE}; +use std::{cmp, fmt, io}; + +// This should be large, but it has to fit on the stack. +pub(crate) const BUF_SIZE: usize = 1024; + +// 4 bytes of base64 data encode 3 bytes of raw data (modulo padding). +const BASE64_CHUNK_SIZE: usize = 4; +const DECODED_CHUNK_SIZE: usize = 3; + +/// A `Read` implementation that decodes base64 data read from an underlying reader. +/// +/// # Examples +/// +/// ``` +/// use std::io::Read; +/// use std::io::Cursor; +/// use base64::engine::general_purpose; +/// +/// // use a cursor as the simplest possible `Read` -- in real code this is probably a file, etc. +/// let mut wrapped_reader = Cursor::new(b"YXNkZg=="); +/// let mut decoder = base64::read::DecoderReader::new( +/// &mut wrapped_reader, +/// &general_purpose::STANDARD); +/// +/// // handle errors as you normally would +/// let mut result = Vec::new(); +/// decoder.read_to_end(&mut result).unwrap(); +/// +/// assert_eq!(b"asdf", &result[..]); +/// +/// ``` +pub struct DecoderReader<'e, E: Engine, R: io::Read> { + engine: &'e E, + /// Where b64 data is read from + inner: R, + + // Holds b64 data read from the delegate reader. + b64_buffer: [u8; BUF_SIZE], + // The start of the pending buffered data in b64_buffer. + b64_offset: usize, + // The amount of buffered b64 data. + b64_len: usize, + // Since the caller may provide us with a buffer of size 1 or 2 that's too small to copy a + // decoded chunk in to, we have to be able to hang on to a few decoded bytes. + // Technically we only need to hold 2 bytes but then we'd need a separate temporary buffer to + // decode 3 bytes into and then juggle copying one byte into the provided read buf and the rest + // into here, which seems like a lot of complexity for 1 extra byte of storage. + decoded_buffer: [u8; DECODED_CHUNK_SIZE], + // index of start of decoded data + decoded_offset: usize, + // length of decoded data + decoded_len: usize, + // used to provide accurate offsets in errors + total_b64_decoded: usize, + // offset of previously seen padding, if any + padding_offset: Option, +} + +impl<'e, E: Engine, R: io::Read> fmt::Debug for DecoderReader<'e, E, R> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("DecoderReader") + .field("b64_offset", &self.b64_offset) + .field("b64_len", &self.b64_len) + .field("decoded_buffer", &self.decoded_buffer) + .field("decoded_offset", &self.decoded_offset) + .field("decoded_len", &self.decoded_len) + .field("total_b64_decoded", &self.total_b64_decoded) + .field("padding_offset", &self.padding_offset) + .finish() + } +} + +impl<'e, E: Engine, R: io::Read> DecoderReader<'e, E, R> { + /// Create a new decoder that will read from the provided reader `r`. + pub fn new(reader: R, engine: &'e E) -> Self { + DecoderReader { + engine, + inner: reader, + b64_buffer: [0; BUF_SIZE], + b64_offset: 0, + b64_len: 0, + decoded_buffer: [0; DECODED_CHUNK_SIZE], + decoded_offset: 0, + decoded_len: 0, + total_b64_decoded: 0, + padding_offset: None, + } + } + + /// Write as much as possible of the decoded buffer into the target buffer. + /// Must only be called when there is something to write and space to write into. + /// Returns a Result with the number of (decoded) bytes copied. + fn flush_decoded_buf(&mut self, buf: &mut [u8]) -> io::Result { + debug_assert!(self.decoded_len > 0); + debug_assert!(!buf.is_empty()); + + let copy_len = cmp::min(self.decoded_len, buf.len()); + debug_assert!(copy_len > 0); + debug_assert!(copy_len <= self.decoded_len); + + buf[..copy_len].copy_from_slice( + &self.decoded_buffer[self.decoded_offset..self.decoded_offset + copy_len], + ); + + self.decoded_offset += copy_len; + self.decoded_len -= copy_len; + + debug_assert!(self.decoded_len < DECODED_CHUNK_SIZE); + + Ok(copy_len) + } + + /// Read into the remaining space in the buffer after the current contents. + /// Must only be called when there is space to read into in the buffer. + /// Returns the number of bytes read. + fn read_from_delegate(&mut self) -> io::Result { + debug_assert!(self.b64_offset + self.b64_len < BUF_SIZE); + + let read = self + .inner + .read(&mut self.b64_buffer[self.b64_offset + self.b64_len..])?; + self.b64_len += read; + + debug_assert!(self.b64_offset + self.b64_len <= BUF_SIZE); + + Ok(read) + } + + /// Decode the requested number of bytes from the b64 buffer into the provided buffer. It's the + /// caller's responsibility to choose the number of b64 bytes to decode correctly. + /// + /// Returns a Result with the number of decoded bytes written to `buf`. + fn decode_to_buf(&mut self, b64_len_to_decode: usize, buf: &mut [u8]) -> io::Result { + debug_assert!(self.b64_len >= b64_len_to_decode); + debug_assert!(self.b64_offset + self.b64_len <= BUF_SIZE); + debug_assert!(!buf.is_empty()); + + let b64_to_decode = &self.b64_buffer[self.b64_offset..self.b64_offset + b64_len_to_decode]; + let decode_metadata = self + .engine + .internal_decode( + b64_to_decode, + buf, + self.engine.internal_decoded_len_estimate(b64_len_to_decode), + ) + .map_err(|e| match e { + DecodeError::InvalidByte(offset, byte) => { + // This can be incorrect, but not in a way that probably matters to anyone: + // if there was padding handled in a previous decode, and we are now getting + // InvalidByte due to more padding, we should arguably report InvalidByte with + // PAD_BYTE at the original padding position (`self.padding_offset`), but we + // don't have a good way to tie those two cases together, so instead we + // just report the invalid byte as if the previous padding, and its possibly + // related downgrade to a now invalid byte, didn't happen. + DecodeError::InvalidByte(self.total_b64_decoded + offset, byte) + } + DecodeError::InvalidLength => DecodeError::InvalidLength, + DecodeError::InvalidLastSymbol(offset, byte) => { + DecodeError::InvalidLastSymbol(self.total_b64_decoded + offset, byte) + } + DecodeError::InvalidPadding => DecodeError::InvalidPadding, + }) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + if let Some(offset) = self.padding_offset { + // we've already seen padding + if decode_metadata.decoded_len > 0 { + // we read more after already finding padding; report error at first padding byte + return Err(io::Error::new( + io::ErrorKind::InvalidData, + DecodeError::InvalidByte(offset, PAD_BYTE), + )); + } + } + + self.padding_offset = self.padding_offset.or(decode_metadata + .padding_offset + .map(|offset| self.total_b64_decoded + offset)); + self.total_b64_decoded += b64_len_to_decode; + self.b64_offset += b64_len_to_decode; + self.b64_len -= b64_len_to_decode; + + debug_assert!(self.b64_offset + self.b64_len <= BUF_SIZE); + + Ok(decode_metadata.decoded_len) + } + + /// Unwraps this `DecoderReader`, returning the base reader which it reads base64 encoded + /// input from. + /// + /// Because `DecoderReader` performs internal buffering, the state of the inner reader is + /// unspecified. This function is mainly provided because the inner reader type may provide + /// additional functionality beyond the `Read` implementation which may still be useful. + pub fn into_inner(self) -> R { + self.inner + } +} + +impl<'e, E: Engine, R: io::Read> io::Read for DecoderReader<'e, E, R> { + /// Decode input from the wrapped reader. + /// + /// Under non-error circumstances, this returns `Ok` with the value being the number of bytes + /// written in `buf`. + /// + /// Where possible, this function buffers base64 to minimize the number of read() calls to the + /// delegate reader. + /// + /// # Errors + /// + /// Any errors emitted by the delegate reader are returned. Decoding errors due to invalid + /// base64 are also possible, and will have `io::ErrorKind::InvalidData`. + fn read(&mut self, buf: &mut [u8]) -> io::Result { + if buf.is_empty() { + return Ok(0); + } + + // offset == BUF_SIZE when we copied it all last time + debug_assert!(self.b64_offset <= BUF_SIZE); + debug_assert!(self.b64_offset + self.b64_len <= BUF_SIZE); + debug_assert!(if self.b64_offset == BUF_SIZE { + self.b64_len == 0 + } else { + self.b64_len <= BUF_SIZE + }); + + debug_assert!(if self.decoded_len == 0 { + // can be = when we were able to copy the complete chunk + self.decoded_offset <= DECODED_CHUNK_SIZE + } else { + self.decoded_offset < DECODED_CHUNK_SIZE + }); + + // We shouldn't ever decode into decoded_buffer when we can't immediately write at least one + // byte into the provided buf, so the effective length should only be 3 momentarily between + // when we decode and when we copy into the target buffer. + debug_assert!(self.decoded_len < DECODED_CHUNK_SIZE); + debug_assert!(self.decoded_len + self.decoded_offset <= DECODED_CHUNK_SIZE); + + if self.decoded_len > 0 { + // we have a few leftover decoded bytes; flush that rather than pull in more b64 + self.flush_decoded_buf(buf) + } else { + let mut at_eof = false; + while self.b64_len < BASE64_CHUNK_SIZE { + // Copy any bytes we have to the start of the buffer. + self.b64_buffer + .copy_within(self.b64_offset..self.b64_offset + self.b64_len, 0); + self.b64_offset = 0; + + // then fill in more data + let read = self.read_from_delegate()?; + if read == 0 { + // we never read into an empty buf, so 0 => we've hit EOF + at_eof = true; + break; + } + } + + if self.b64_len == 0 { + debug_assert!(at_eof); + // we must be at EOF, and we have no data left to decode + return Ok(0); + }; + + debug_assert!(if at_eof { + // if we are at eof, we may not have a complete chunk + self.b64_len > 0 + } else { + // otherwise, we must have at least one chunk + self.b64_len >= BASE64_CHUNK_SIZE + }); + + debug_assert_eq!(0, self.decoded_len); + + if buf.len() < DECODED_CHUNK_SIZE { + // caller requested an annoyingly short read + // have to write to a tmp buf first to avoid double mutable borrow + let mut decoded_chunk = [0_u8; DECODED_CHUNK_SIZE]; + // if we are at eof, could have less than BASE64_CHUNK_SIZE, in which case we have + // to assume that these last few tokens are, in fact, valid (i.e. must be 2-4 b64 + // tokens, not 1, since 1 token can't decode to 1 byte). + let to_decode = cmp::min(self.b64_len, BASE64_CHUNK_SIZE); + + let decoded = self.decode_to_buf(to_decode, &mut decoded_chunk[..])?; + self.decoded_buffer[..decoded].copy_from_slice(&decoded_chunk[..decoded]); + + self.decoded_offset = 0; + self.decoded_len = decoded; + + // can be less than 3 on last block due to padding + debug_assert!(decoded <= 3); + + self.flush_decoded_buf(buf) + } else { + let b64_bytes_that_can_decode_into_buf = (buf.len() / DECODED_CHUNK_SIZE) + .checked_mul(BASE64_CHUNK_SIZE) + .expect("too many chunks"); + debug_assert!(b64_bytes_that_can_decode_into_buf >= BASE64_CHUNK_SIZE); + + let b64_bytes_available_to_decode = if at_eof { + self.b64_len + } else { + // only use complete chunks + self.b64_len - self.b64_len % 4 + }; + + let actual_decode_len = cmp::min( + b64_bytes_that_can_decode_into_buf, + b64_bytes_available_to_decode, + ); + self.decode_to_buf(actual_decode_len, buf) + } + } + } +} diff --git a/vendor/base64-0.21.5/src/read/decoder_tests.rs b/vendor/base64-0.21.5/src/read/decoder_tests.rs new file mode 100644 index 00000000..099dd638 --- /dev/null +++ b/vendor/base64-0.21.5/src/read/decoder_tests.rs @@ -0,0 +1,487 @@ +use std::{ + cmp, + io::{self, Read as _}, + iter, +}; + +use rand::{Rng as _, RngCore as _}; + +use super::decoder::{DecoderReader, BUF_SIZE}; +use crate::{ + alphabet, + engine::{general_purpose::STANDARD, Engine, GeneralPurpose}, + tests::{random_alphabet, random_config, random_engine}, + DecodeError, PAD_BYTE, +}; + +#[test] +fn simple() { + let tests: &[(&[u8], &[u8])] = &[ + (&b"0"[..], &b"MA=="[..]), + (b"01", b"MDE="), + (b"012", b"MDEy"), + (b"0123", b"MDEyMw=="), + (b"01234", b"MDEyMzQ="), + (b"012345", b"MDEyMzQ1"), + (b"0123456", b"MDEyMzQ1Ng=="), + (b"01234567", b"MDEyMzQ1Njc="), + (b"012345678", b"MDEyMzQ1Njc4"), + (b"0123456789", b"MDEyMzQ1Njc4OQ=="), + ][..]; + + for (text_expected, base64data) in tests.iter() { + // Read n bytes at a time. + for n in 1..base64data.len() + 1 { + let mut wrapped_reader = io::Cursor::new(base64data); + let mut decoder = DecoderReader::new(&mut wrapped_reader, &STANDARD); + + // handle errors as you normally would + let mut text_got = Vec::new(); + let mut buffer = vec![0u8; n]; + while let Ok(read) = decoder.read(&mut buffer[..]) { + if read == 0 { + break; + } + text_got.extend_from_slice(&buffer[..read]); + } + + assert_eq!( + text_got, + *text_expected, + "\nGot: {}\nExpected: {}", + String::from_utf8_lossy(&text_got[..]), + String::from_utf8_lossy(text_expected) + ); + } + } +} + +// Make sure we error out on trailing junk. +#[test] +fn trailing_junk() { + let tests: &[&[u8]] = &[&b"MDEyMzQ1Njc4*!@#$%^&"[..], b"MDEyMzQ1Njc4OQ== "][..]; + + for base64data in tests.iter() { + // Read n bytes at a time. + for n in 1..base64data.len() + 1 { + let mut wrapped_reader = io::Cursor::new(base64data); + let mut decoder = DecoderReader::new(&mut wrapped_reader, &STANDARD); + + // handle errors as you normally would + let mut buffer = vec![0u8; n]; + let mut saw_error = false; + loop { + match decoder.read(&mut buffer[..]) { + Err(_) => { + saw_error = true; + break; + } + Ok(0) => break, + Ok(_) => (), + } + } + + assert!(saw_error); + } + } +} + +#[test] +fn handles_short_read_from_delegate() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut decoded = Vec::new(); + + for _ in 0..10_000 { + bytes.clear(); + b64.clear(); + decoded.clear(); + + let size = rng.gen_range(0..(10 * BUF_SIZE)); + bytes.extend(iter::repeat(0).take(size)); + bytes.truncate(size); + rng.fill_bytes(&mut bytes[..size]); + assert_eq!(size, bytes.len()); + + let engine = random_engine(&mut rng); + engine.encode_string(&bytes[..], &mut b64); + + let mut wrapped_reader = io::Cursor::new(b64.as_bytes()); + let mut short_reader = RandomShortRead { + delegate: &mut wrapped_reader, + rng: &mut rng, + }; + + let mut decoder = DecoderReader::new(&mut short_reader, &engine); + + let decoded_len = decoder.read_to_end(&mut decoded).unwrap(); + assert_eq!(size, decoded_len); + assert_eq!(&bytes[..], &decoded[..]); + } +} + +#[test] +fn read_in_short_increments() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut decoded = Vec::new(); + + for _ in 0..10_000 { + bytes.clear(); + b64.clear(); + decoded.clear(); + + let size = rng.gen_range(0..(10 * BUF_SIZE)); + bytes.extend(iter::repeat(0).take(size)); + // leave room to play around with larger buffers + decoded.extend(iter::repeat(0).take(size * 3)); + + rng.fill_bytes(&mut bytes[..]); + assert_eq!(size, bytes.len()); + + let engine = random_engine(&mut rng); + + engine.encode_string(&bytes[..], &mut b64); + + let mut wrapped_reader = io::Cursor::new(&b64[..]); + let mut decoder = DecoderReader::new(&mut wrapped_reader, &engine); + + consume_with_short_reads_and_validate(&mut rng, &bytes[..], &mut decoded, &mut decoder); + } +} + +#[test] +fn read_in_short_increments_with_short_delegate_reads() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut decoded = Vec::new(); + + for _ in 0..10_000 { + bytes.clear(); + b64.clear(); + decoded.clear(); + + let size = rng.gen_range(0..(10 * BUF_SIZE)); + bytes.extend(iter::repeat(0).take(size)); + // leave room to play around with larger buffers + decoded.extend(iter::repeat(0).take(size * 3)); + + rng.fill_bytes(&mut bytes[..]); + assert_eq!(size, bytes.len()); + + let engine = random_engine(&mut rng); + + engine.encode_string(&bytes[..], &mut b64); + + let mut base_reader = io::Cursor::new(&b64[..]); + let mut decoder = DecoderReader::new(&mut base_reader, &engine); + let mut short_reader = RandomShortRead { + delegate: &mut decoder, + rng: &mut rand::thread_rng(), + }; + + consume_with_short_reads_and_validate( + &mut rng, + &bytes[..], + &mut decoded, + &mut short_reader, + ); + } +} + +#[test] +fn reports_invalid_last_symbol_correctly() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut b64_bytes = Vec::new(); + let mut decoded = Vec::new(); + let mut bulk_decoded = Vec::new(); + + for _ in 0..1_000 { + bytes.clear(); + b64.clear(); + b64_bytes.clear(); + + let size = rng.gen_range(1..(10 * BUF_SIZE)); + bytes.extend(iter::repeat(0).take(size)); + decoded.extend(iter::repeat(0).take(size)); + rng.fill_bytes(&mut bytes[..]); + assert_eq!(size, bytes.len()); + + let config = random_config(&mut rng); + let alphabet = random_alphabet(&mut rng); + // changing padding will cause invalid padding errors when we twiddle the last byte + let engine = GeneralPurpose::new(alphabet, config.with_encode_padding(false)); + engine.encode_string(&bytes[..], &mut b64); + b64_bytes.extend(b64.bytes()); + assert_eq!(b64_bytes.len(), b64.len()); + + // change the last character to every possible symbol. Should behave the same as bulk + // decoding whether invalid or valid. + for &s1 in alphabet.symbols.iter() { + decoded.clear(); + bulk_decoded.clear(); + + // replace the last + *b64_bytes.last_mut().unwrap() = s1; + let bulk_res = engine.decode_vec(&b64_bytes[..], &mut bulk_decoded); + + let mut wrapped_reader = io::Cursor::new(&b64_bytes[..]); + let mut decoder = DecoderReader::new(&mut wrapped_reader, &engine); + + let stream_res = decoder.read_to_end(&mut decoded).map(|_| ()).map_err(|e| { + e.into_inner() + .and_then(|e| e.downcast::().ok()) + }); + + assert_eq!(bulk_res.map_err(|e| Some(Box::new(e))), stream_res); + } + } +} + +#[test] +fn reports_invalid_byte_correctly() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut stream_decoded = Vec::new(); + let mut bulk_decoded = Vec::new(); + + for _ in 0..10_000 { + bytes.clear(); + b64.clear(); + stream_decoded.clear(); + bulk_decoded.clear(); + + let size = rng.gen_range(1..(10 * BUF_SIZE)); + bytes.extend(iter::repeat(0).take(size)); + rng.fill_bytes(&mut bytes[..size]); + assert_eq!(size, bytes.len()); + + let engine = GeneralPurpose::new(&alphabet::STANDARD, random_config(&mut rng)); + + engine.encode_string(&bytes[..], &mut b64); + // replace one byte, somewhere, with '*', which is invalid + let bad_byte_pos = rng.gen_range(0..b64.len()); + let mut b64_bytes = b64.bytes().collect::>(); + b64_bytes[bad_byte_pos] = b'*'; + + let mut wrapped_reader = io::Cursor::new(b64_bytes.clone()); + let mut decoder = DecoderReader::new(&mut wrapped_reader, &engine); + + let read_decode_err = decoder + .read_to_end(&mut stream_decoded) + .map_err(|e| { + let kind = e.kind(); + let inner = e + .into_inner() + .and_then(|e| e.downcast::().ok()); + inner.map(|i| (*i, kind)) + }) + .err() + .and_then(|o| o); + + let bulk_decode_err = engine.decode_vec(&b64_bytes[..], &mut bulk_decoded).err(); + + // it's tricky to predict where the invalid data's offset will be since if it's in the last + // chunk it will be reported at the first padding location because it's treated as invalid + // padding. So, we just check that it's the same as it is for decoding all at once. + assert_eq!( + bulk_decode_err.map(|e| (e, io::ErrorKind::InvalidData)), + read_decode_err + ); + } +} + +#[test] +fn internal_padding_error_with_short_read_concatenated_texts_invalid_byte_error() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut reader_decoded = Vec::new(); + let mut bulk_decoded = Vec::new(); + + // encodes with padding, requires that padding be present so we don't get InvalidPadding + // just because padding is there at all + let engine = STANDARD; + + for _ in 0..10_000 { + bytes.clear(); + b64.clear(); + reader_decoded.clear(); + bulk_decoded.clear(); + + // at least 2 bytes so there can be a split point between bytes + let size = rng.gen_range(2..(10 * BUF_SIZE)); + bytes.resize(size, 0); + rng.fill_bytes(&mut bytes[..size]); + + // Concatenate two valid b64s, yielding padding in the middle. + // This avoids scenarios that are challenging to assert on, like random padding location + // that might be InvalidLastSymbol when decoded at certain buffer sizes but InvalidByte + // when done all at once. + let split = loop { + // find a split point that will produce padding on the first part + let s = rng.gen_range(1..size); + if s % 3 != 0 { + // short enough to need padding + break s; + }; + }; + + engine.encode_string(&bytes[..split], &mut b64); + assert!(b64.contains('='), "split: {}, b64: {}", split, b64); + let bad_byte_pos = b64.find('=').unwrap(); + engine.encode_string(&bytes[split..], &mut b64); + let b64_bytes = b64.as_bytes(); + + // short read to make it plausible for padding to happen on a read boundary + let read_len = rng.gen_range(1..10); + let mut wrapped_reader = ShortRead { + max_read_len: read_len, + delegate: io::Cursor::new(&b64_bytes), + }; + + let mut decoder = DecoderReader::new(&mut wrapped_reader, &engine); + + let read_decode_err = decoder + .read_to_end(&mut reader_decoded) + .map_err(|e| { + *e.into_inner() + .and_then(|e| e.downcast::().ok()) + .unwrap() + }) + .unwrap_err(); + + let bulk_decode_err = engine.decode_vec(b64_bytes, &mut bulk_decoded).unwrap_err(); + + assert_eq!( + bulk_decode_err, + read_decode_err, + "read len: {}, bad byte pos: {}, b64: {}", + read_len, + bad_byte_pos, + std::str::from_utf8(b64_bytes).unwrap() + ); + assert_eq!( + DecodeError::InvalidByte( + split / 3 * 4 + + match split % 3 { + 1 => 2, + 2 => 3, + _ => unreachable!(), + }, + PAD_BYTE + ), + read_decode_err + ); + } +} + +#[test] +fn internal_padding_anywhere_error() { + let mut rng = rand::thread_rng(); + let mut bytes = Vec::new(); + let mut b64 = String::new(); + let mut reader_decoded = Vec::new(); + + // encodes with padding, requires that padding be present so we don't get InvalidPadding + // just because padding is there at all + let engine = STANDARD; + + for _ in 0..10_000 { + bytes.clear(); + b64.clear(); + reader_decoded.clear(); + + bytes.resize(10 * BUF_SIZE, 0); + rng.fill_bytes(&mut bytes[..]); + + // Just shove a padding byte in there somewhere. + // The specific error to expect is challenging to predict precisely because it + // will vary based on the position of the padding in the quad and the read buffer + // length, but SOMETHING should go wrong. + + engine.encode_string(&bytes[..], &mut b64); + let mut b64_bytes = b64.as_bytes().to_vec(); + // put padding somewhere other than the last quad + b64_bytes[rng.gen_range(0..bytes.len() - 4)] = PAD_BYTE; + + // short read to make it plausible for padding to happen on a read boundary + let read_len = rng.gen_range(1..10); + let mut wrapped_reader = ShortRead { + max_read_len: read_len, + delegate: io::Cursor::new(&b64_bytes), + }; + + let mut decoder = DecoderReader::new(&mut wrapped_reader, &engine); + + let result = decoder.read_to_end(&mut reader_decoded); + assert!(result.is_err()); + } +} + +fn consume_with_short_reads_and_validate( + rng: &mut rand::rngs::ThreadRng, + expected_bytes: &[u8], + decoded: &mut [u8], + short_reader: &mut R, +) { + let mut total_read = 0_usize; + loop { + assert!( + total_read <= expected_bytes.len(), + "tr {} size {}", + total_read, + expected_bytes.len() + ); + if total_read == expected_bytes.len() { + assert_eq!(expected_bytes, &decoded[..total_read]); + // should be done + assert_eq!(0, short_reader.read(&mut *decoded).unwrap()); + // didn't write anything + assert_eq!(expected_bytes, &decoded[..total_read]); + + break; + } + let decode_len = rng.gen_range(1..cmp::max(2, expected_bytes.len() * 2)); + + let read = short_reader + .read(&mut decoded[total_read..total_read + decode_len]) + .unwrap(); + total_read += read; + } +} + +/// Limits how many bytes a reader will provide in each read call. +/// Useful for shaking out code that may work fine only with typical input sources that always fill +/// the buffer. +struct RandomShortRead<'a, 'b, R: io::Read, N: rand::Rng> { + delegate: &'b mut R, + rng: &'a mut N, +} + +impl<'a, 'b, R: io::Read, N: rand::Rng> io::Read for RandomShortRead<'a, 'b, R, N> { + fn read(&mut self, buf: &mut [u8]) -> Result { + // avoid 0 since it means EOF for non-empty buffers + let effective_len = cmp::min(self.rng.gen_range(1..20), buf.len()); + + self.delegate.read(&mut buf[..effective_len]) + } +} + +struct ShortRead { + delegate: R, + max_read_len: usize, +} + +impl io::Read for ShortRead { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = self.max_read_len.max(buf.len()); + self.delegate.read(&mut buf[..len]) + } +} diff --git a/vendor/base64-0.21.5/src/read/mod.rs b/vendor/base64-0.21.5/src/read/mod.rs new file mode 100644 index 00000000..85606448 --- /dev/null +++ b/vendor/base64-0.21.5/src/read/mod.rs @@ -0,0 +1,6 @@ +//! Implementations of `io::Read` to transparently decode base64. +mod decoder; +pub use self::decoder::DecoderReader; + +#[cfg(test)] +mod decoder_tests; diff --git a/vendor/base64-0.21.5/src/tests.rs b/vendor/base64-0.21.5/src/tests.rs new file mode 100644 index 00000000..7083b543 --- /dev/null +++ b/vendor/base64-0.21.5/src/tests.rs @@ -0,0 +1,117 @@ +use std::str; + +use rand::{ + distributions, + distributions::{Distribution as _, Uniform}, + seq::SliceRandom, + Rng, SeedableRng, +}; + +use crate::{ + alphabet, + encode::encoded_len, + engine::{ + general_purpose::{GeneralPurpose, GeneralPurposeConfig}, + Config, DecodePaddingMode, Engine, + }, +}; + +#[test] +fn roundtrip_random_config_short() { + // exercise the slower encode/decode routines that operate on shorter buffers more vigorously + roundtrip_random_config(Uniform::new(0, 50), 10_000); +} + +#[test] +fn roundtrip_random_config_long() { + roundtrip_random_config(Uniform::new(0, 1000), 10_000); +} + +pub fn assert_encode_sanity(encoded: &str, padded: bool, input_len: usize) { + let input_rem = input_len % 3; + let expected_padding_len = if input_rem > 0 { + if padded { + 3 - input_rem + } else { + 0 + } + } else { + 0 + }; + + let expected_encoded_len = encoded_len(input_len, padded).unwrap(); + + assert_eq!(expected_encoded_len, encoded.len()); + + let padding_len = encoded.chars().filter(|&c| c == '=').count(); + + assert_eq!(expected_padding_len, padding_len); + + let _ = str::from_utf8(encoded.as_bytes()).expect("Base64 should be valid utf8"); +} + +fn roundtrip_random_config(input_len_range: Uniform, iterations: u32) { + let mut input_buf: Vec = Vec::new(); + let mut encoded_buf = String::new(); + let mut rng = rand::rngs::SmallRng::from_entropy(); + + for _ in 0..iterations { + input_buf.clear(); + encoded_buf.clear(); + + let input_len = input_len_range.sample(&mut rng); + + let engine = random_engine(&mut rng); + + for _ in 0..input_len { + input_buf.push(rng.gen()); + } + + engine.encode_string(&input_buf, &mut encoded_buf); + + assert_encode_sanity(&encoded_buf, engine.config().encode_padding(), input_len); + + assert_eq!(input_buf, engine.decode(&encoded_buf).unwrap()); + } +} + +pub fn random_config(rng: &mut R) -> GeneralPurposeConfig { + let mode = rng.gen(); + GeneralPurposeConfig::new() + .with_encode_padding(match mode { + DecodePaddingMode::Indifferent => rng.gen(), + DecodePaddingMode::RequireCanonical => true, + DecodePaddingMode::RequireNone => false, + }) + .with_decode_padding_mode(mode) + .with_decode_allow_trailing_bits(rng.gen()) +} + +impl distributions::Distribution for distributions::Standard { + fn sample(&self, rng: &mut R) -> DecodePaddingMode { + match rng.gen_range(0..=2) { + 0 => DecodePaddingMode::Indifferent, + 1 => DecodePaddingMode::RequireCanonical, + _ => DecodePaddingMode::RequireNone, + } + } +} + +pub fn random_alphabet(rng: &mut R) -> &'static alphabet::Alphabet { + ALPHABETS.choose(rng).unwrap() +} + +pub fn random_engine(rng: &mut R) -> GeneralPurpose { + let alphabet = random_alphabet(rng); + let config = random_config(rng); + GeneralPurpose::new(alphabet, config) +} + +const ALPHABETS: &[alphabet::Alphabet] = &[ + alphabet::URL_SAFE, + alphabet::STANDARD, + alphabet::CRYPT, + alphabet::BCRYPT, + alphabet::IMAP_MUTF7, + alphabet::BIN_HEX, +]; diff --git a/vendor/base64-0.21.5/src/write/encoder.rs b/vendor/base64-0.21.5/src/write/encoder.rs new file mode 100644 index 00000000..1c19bb42 --- /dev/null +++ b/vendor/base64-0.21.5/src/write/encoder.rs @@ -0,0 +1,407 @@ +use crate::engine::Engine; +use std::{ + cmp, fmt, io, + io::{ErrorKind, Result}, +}; + +pub(crate) const BUF_SIZE: usize = 1024; +/// The most bytes whose encoding will fit in `BUF_SIZE` +const MAX_INPUT_LEN: usize = BUF_SIZE / 4 * 3; +// 3 bytes of input = 4 bytes of base64, always (because we don't allow line wrapping) +const MIN_ENCODE_CHUNK_SIZE: usize = 3; + +/// A `Write` implementation that base64 encodes data before delegating to the wrapped writer. +/// +/// Because base64 has special handling for the end of the input data (padding, etc), there's a +/// `finish()` method on this type that encodes any leftover input bytes and adds padding if +/// appropriate. It's called automatically when deallocated (see the `Drop` implementation), but +/// any error that occurs when invoking the underlying writer will be suppressed. If you want to +/// handle such errors, call `finish()` yourself. +/// +/// # Examples +/// +/// ``` +/// use std::io::Write; +/// use base64::engine::general_purpose; +/// +/// // use a vec as the simplest possible `Write` -- in real code this is probably a file, etc. +/// let mut enc = base64::write::EncoderWriter::new(Vec::new(), &general_purpose::STANDARD); +/// +/// // handle errors as you normally would +/// enc.write_all(b"asdf").unwrap(); +/// +/// // could leave this out to be called by Drop, if you don't care +/// // about handling errors or getting the delegate writer back +/// let delegate = enc.finish().unwrap(); +/// +/// // base64 was written to the writer +/// assert_eq!(b"YXNkZg==", &delegate[..]); +/// +/// ``` +/// +/// # Panics +/// +/// Calling `write()` (or related methods) or `finish()` after `finish()` has completed without +/// error is invalid and will panic. +/// +/// # Errors +/// +/// Base64 encoding itself does not generate errors, but errors from the wrapped writer will be +/// returned as per the contract of `Write`. +/// +/// # Performance +/// +/// It has some minor performance loss compared to encoding slices (a couple percent). +/// It does not do any heap allocation. +/// +/// # Limitations +/// +/// Owing to the specification of the `write` and `flush` methods on the `Write` trait and their +/// implications for a buffering implementation, these methods may not behave as expected. In +/// particular, calling `write_all` on this interface may fail with `io::ErrorKind::WriteZero`. +/// See the documentation of the `Write` trait implementation for further details. +pub struct EncoderWriter<'e, E: Engine, W: io::Write> { + engine: &'e E, + /// Where encoded data is written to. It's an Option as it's None immediately before Drop is + /// called so that finish() can return the underlying writer. None implies that finish() has + /// been called successfully. + delegate: Option, + /// Holds a partial chunk, if any, after the last `write()`, so that we may then fill the chunk + /// with the next `write()`, encode it, then proceed with the rest of the input normally. + extra_input: [u8; MIN_ENCODE_CHUNK_SIZE], + /// How much of `extra` is occupied, in `[0, MIN_ENCODE_CHUNK_SIZE]`. + extra_input_occupied_len: usize, + /// Buffer to encode into. May hold leftover encoded bytes from a previous write call that the underlying writer + /// did not write last time. + output: [u8; BUF_SIZE], + /// How much of `output` is occupied with encoded data that couldn't be written last time + output_occupied_len: usize, + /// panic safety: don't write again in destructor if writer panicked while we were writing to it + panicked: bool, +} + +impl<'e, E: Engine, W: io::Write> fmt::Debug for EncoderWriter<'e, E, W> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "extra_input: {:?} extra_input_occupied_len:{:?} output[..5]: {:?} output_occupied_len: {:?}", + self.extra_input, + self.extra_input_occupied_len, + &self.output[0..5], + self.output_occupied_len + ) + } +} + +impl<'e, E: Engine, W: io::Write> EncoderWriter<'e, E, W> { + /// Create a new encoder that will write to the provided delegate writer. + pub fn new(delegate: W, engine: &'e E) -> EncoderWriter<'e, E, W> { + EncoderWriter { + engine, + delegate: Some(delegate), + extra_input: [0u8; MIN_ENCODE_CHUNK_SIZE], + extra_input_occupied_len: 0, + output: [0u8; BUF_SIZE], + output_occupied_len: 0, + panicked: false, + } + } + + /// Encode all remaining buffered data and write it, including any trailing incomplete input + /// triples and associated padding. + /// + /// Once this succeeds, no further writes or calls to this method are allowed. + /// + /// This may write to the delegate writer multiple times if the delegate writer does not accept + /// all input provided to its `write` each invocation. + /// + /// If you don't care about error handling, it is not necessary to call this function, as the + /// equivalent finalization is done by the Drop impl. + /// + /// Returns the writer that this was constructed around. + /// + /// # Errors + /// + /// The first error that is not of `ErrorKind::Interrupted` will be returned. + pub fn finish(&mut self) -> Result { + // If we could consume self in finish(), we wouldn't have to worry about this case, but + // finish() is retryable in the face of I/O errors, so we can't consume here. + if self.delegate.is_none() { + panic!("Encoder has already had finish() called"); + }; + + self.write_final_leftovers()?; + + let writer = self.delegate.take().expect("Writer must be present"); + + Ok(writer) + } + + /// Write any remaining buffered data to the delegate writer. + fn write_final_leftovers(&mut self) -> Result<()> { + if self.delegate.is_none() { + // finish() has already successfully called this, and we are now in drop() with a None + // writer, so just no-op + return Ok(()); + } + + self.write_all_encoded_output()?; + + if self.extra_input_occupied_len > 0 { + let encoded_len = self + .engine + .encode_slice( + &self.extra_input[..self.extra_input_occupied_len], + &mut self.output[..], + ) + .expect("buffer is large enough"); + + self.output_occupied_len = encoded_len; + + self.write_all_encoded_output()?; + + // write succeeded, do not write the encoding of extra again if finish() is retried + self.extra_input_occupied_len = 0; + } + + Ok(()) + } + + /// Write as much of the encoded output to the delegate writer as it will accept, and store the + /// leftovers to be attempted at the next write() call. Updates `self.output_occupied_len`. + /// + /// # Errors + /// + /// Errors from the delegate writer are returned. In the case of an error, + /// `self.output_occupied_len` will not be updated, as errors from `write` are specified to mean + /// that no write took place. + fn write_to_delegate(&mut self, current_output_len: usize) -> Result<()> { + self.panicked = true; + let res = self + .delegate + .as_mut() + .expect("Writer must be present") + .write(&self.output[..current_output_len]); + self.panicked = false; + + res.map(|consumed| { + debug_assert!(consumed <= current_output_len); + + if consumed < current_output_len { + self.output_occupied_len = current_output_len.checked_sub(consumed).unwrap(); + // If we're blocking on I/O, the minor inefficiency of copying bytes to the + // start of the buffer is the least of our concerns... + // TODO Rotate moves more than we need to; copy_within now stable. + self.output.rotate_left(consumed); + } else { + self.output_occupied_len = 0; + } + }) + } + + /// Write all buffered encoded output. If this returns `Ok`, `self.output_occupied_len` is `0`. + /// + /// This is basically write_all for the remaining buffered data but without the undesirable + /// abort-on-`Ok(0)` behavior. + /// + /// # Errors + /// + /// Any error emitted by the delegate writer abort the write loop and is returned, unless it's + /// `Interrupted`, in which case the error is ignored and writes will continue. + fn write_all_encoded_output(&mut self) -> Result<()> { + while self.output_occupied_len > 0 { + let remaining_len = self.output_occupied_len; + match self.write_to_delegate(remaining_len) { + // try again on interrupts ala write_all + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + // other errors return + Err(e) => return Err(e), + // success no-ops because remaining length is already updated + Ok(_) => {} + }; + } + + debug_assert_eq!(0, self.output_occupied_len); + Ok(()) + } + + /// Unwraps this `EncoderWriter`, returning the base writer it writes base64 encoded output + /// to. + /// + /// Normally this method should not be needed, since `finish()` returns the inner writer if + /// it completes successfully. That will also ensure all data has been flushed, which the + /// `into_inner()` function does *not* do. + /// + /// Calling this method after `finish()` has completed successfully will panic, since the + /// writer has already been returned. + /// + /// This method may be useful if the writer implements additional APIs beyond the `Write` + /// trait. Note that the inner writer might be in an error state or have an incomplete + /// base64 string written to it. + pub fn into_inner(mut self) -> W { + self.delegate + .take() + .expect("Encoder has already had finish() called") + } +} + +impl<'e, E: Engine, W: io::Write> io::Write for EncoderWriter<'e, E, W> { + /// Encode input and then write to the delegate writer. + /// + /// Under non-error circumstances, this returns `Ok` with the value being the number of bytes + /// of `input` consumed. The value may be `0`, which interacts poorly with `write_all`, which + /// interprets `Ok(0)` as an error, despite it being allowed by the contract of `write`. See + /// for more on that. + /// + /// If the previous call to `write` provided more (encoded) data than the delegate writer could + /// accept in a single call to its `write`, the remaining data is buffered. As long as buffered + /// data is present, subsequent calls to `write` will try to write the remaining buffered data + /// to the delegate and return either `Ok(0)` -- and therefore not consume any of `input` -- or + /// an error. + /// + /// # Errors + /// + /// Any errors emitted by the delegate writer are returned. + fn write(&mut self, input: &[u8]) -> Result { + if self.delegate.is_none() { + panic!("Cannot write more after calling finish()"); + } + + if input.is_empty() { + return Ok(0); + } + + // The contract of `Write::write` places some constraints on this implementation: + // - a call to `write()` represents at most one call to a wrapped `Write`, so we can't + // iterate over the input and encode multiple chunks. + // - Errors mean that "no bytes were written to this writer", so we need to reset the + // internal state to what it was before the error occurred + + // before reading any input, write any leftover encoded output from last time + if self.output_occupied_len > 0 { + let current_len = self.output_occupied_len; + return self + .write_to_delegate(current_len) + // did not read any input + .map(|_| 0); + } + + debug_assert_eq!(0, self.output_occupied_len); + + // how many bytes, if any, were read into `extra` to create a triple to encode + let mut extra_input_read_len = 0; + let mut input = input; + + let orig_extra_len = self.extra_input_occupied_len; + + let mut encoded_size = 0; + // always a multiple of MIN_ENCODE_CHUNK_SIZE + let mut max_input_len = MAX_INPUT_LEN; + + // process leftover un-encoded input from last write + if self.extra_input_occupied_len > 0 { + debug_assert!(self.extra_input_occupied_len < 3); + if input.len() + self.extra_input_occupied_len >= MIN_ENCODE_CHUNK_SIZE { + // Fill up `extra`, encode that into `output`, and consume as much of the rest of + // `input` as possible. + // We could write just the encoding of `extra` by itself but then we'd have to + // return after writing only 4 bytes, which is inefficient if the underlying writer + // would make a syscall. + extra_input_read_len = MIN_ENCODE_CHUNK_SIZE - self.extra_input_occupied_len; + debug_assert!(extra_input_read_len > 0); + // overwrite only bytes that weren't already used. If we need to rollback extra_len + // (when the subsequent write errors), the old leading bytes will still be there. + self.extra_input[self.extra_input_occupied_len..MIN_ENCODE_CHUNK_SIZE] + .copy_from_slice(&input[0..extra_input_read_len]); + + let len = self.engine.internal_encode( + &self.extra_input[0..MIN_ENCODE_CHUNK_SIZE], + &mut self.output[..], + ); + debug_assert_eq!(4, len); + + input = &input[extra_input_read_len..]; + + // consider extra to be used up, since we encoded it + self.extra_input_occupied_len = 0; + // don't clobber where we just encoded to + encoded_size = 4; + // and don't read more than can be encoded + max_input_len = MAX_INPUT_LEN - MIN_ENCODE_CHUNK_SIZE; + + // fall through to normal encoding + } else { + // `extra` and `input` are non empty, but `|extra| + |input| < 3`, so there must be + // 1 byte in each. + debug_assert_eq!(1, input.len()); + debug_assert_eq!(1, self.extra_input_occupied_len); + + self.extra_input[self.extra_input_occupied_len] = input[0]; + self.extra_input_occupied_len += 1; + return Ok(1); + }; + } else if input.len() < MIN_ENCODE_CHUNK_SIZE { + // `extra` is empty, and `input` fits inside it + self.extra_input[0..input.len()].copy_from_slice(input); + self.extra_input_occupied_len = input.len(); + return Ok(input.len()); + }; + + // either 0 or 1 complete chunks encoded from extra + debug_assert!(encoded_size == 0 || encoded_size == 4); + debug_assert!( + // didn't encode extra input + MAX_INPUT_LEN == max_input_len + // encoded one triple + || MAX_INPUT_LEN == max_input_len + MIN_ENCODE_CHUNK_SIZE + ); + + // encode complete triples only + let input_complete_chunks_len = input.len() - (input.len() % MIN_ENCODE_CHUNK_SIZE); + let input_chunks_to_encode_len = cmp::min(input_complete_chunks_len, max_input_len); + debug_assert_eq!(0, max_input_len % MIN_ENCODE_CHUNK_SIZE); + debug_assert_eq!(0, input_chunks_to_encode_len % MIN_ENCODE_CHUNK_SIZE); + + encoded_size += self.engine.internal_encode( + &input[..(input_chunks_to_encode_len)], + &mut self.output[encoded_size..], + ); + + // not updating `self.output_occupied_len` here because if the below write fails, it should + // "never take place" -- the buffer contents we encoded are ignored and perhaps retried + // later, if the consumer chooses. + + self.write_to_delegate(encoded_size) + // no matter whether we wrote the full encoded buffer or not, we consumed the same + // input + .map(|_| extra_input_read_len + input_chunks_to_encode_len) + .map_err(|e| { + // in case we filled and encoded `extra`, reset extra_len + self.extra_input_occupied_len = orig_extra_len; + + e + }) + } + + /// Because this is usually treated as OK to call multiple times, it will *not* flush any + /// incomplete chunks of input or write padding. + /// # Errors + /// + /// The first error that is not of [`ErrorKind::Interrupted`] will be returned. + fn flush(&mut self) -> Result<()> { + self.write_all_encoded_output()?; + self.delegate + .as_mut() + .expect("Writer must be present") + .flush() + } +} + +impl<'e, E: Engine, W: io::Write> Drop for EncoderWriter<'e, E, W> { + fn drop(&mut self) { + if !self.panicked { + // like `BufWriter`, ignore errors during drop + let _ = self.write_final_leftovers(); + } + } +} diff --git a/vendor/base64-0.21.5/src/write/encoder_string_writer.rs b/vendor/base64-0.21.5/src/write/encoder_string_writer.rs new file mode 100644 index 00000000..9c02bcde --- /dev/null +++ b/vendor/base64-0.21.5/src/write/encoder_string_writer.rs @@ -0,0 +1,207 @@ +use super::encoder::EncoderWriter; +use crate::engine::Engine; +use std::io; + +/// A `Write` implementation that base64-encodes data using the provided config and accumulates the +/// resulting base64 utf8 `&str` in a [StrConsumer] implementation (typically `String`), which is +/// then exposed via `into_inner()`. +/// +/// # Examples +/// +/// Buffer base64 in a new String: +/// +/// ``` +/// use std::io::Write; +/// use base64::engine::general_purpose; +/// +/// let mut enc = base64::write::EncoderStringWriter::new(&general_purpose::STANDARD); +/// +/// enc.write_all(b"asdf").unwrap(); +/// +/// // get the resulting String +/// let b64_string = enc.into_inner(); +/// +/// assert_eq!("YXNkZg==", &b64_string); +/// ``` +/// +/// Or, append to an existing `String`, which implements `StrConsumer`: +/// +/// ``` +/// use std::io::Write; +/// use base64::engine::general_purpose; +/// +/// let mut buf = String::from("base64: "); +/// +/// let mut enc = base64::write::EncoderStringWriter::from_consumer( +/// &mut buf, +/// &general_purpose::STANDARD); +/// +/// enc.write_all(b"asdf").unwrap(); +/// +/// // release the &mut reference on buf +/// let _ = enc.into_inner(); +/// +/// assert_eq!("base64: YXNkZg==", &buf); +/// ``` +/// +/// # Performance +/// +/// Because it has to validate that the base64 is UTF-8, it is about 80% as fast as writing plain +/// bytes to a `io::Write`. +pub struct EncoderStringWriter<'e, E: Engine, S: StrConsumer> { + encoder: EncoderWriter<'e, E, Utf8SingleCodeUnitWriter>, +} + +impl<'e, E: Engine, S: StrConsumer> EncoderStringWriter<'e, E, S> { + /// Create a EncoderStringWriter that will append to the provided `StrConsumer`. + pub fn from_consumer(str_consumer: S, engine: &'e E) -> Self { + EncoderStringWriter { + encoder: EncoderWriter::new(Utf8SingleCodeUnitWriter { str_consumer }, engine), + } + } + + /// Encode all remaining buffered data, including any trailing incomplete input triples and + /// associated padding. + /// + /// Returns the base64-encoded form of the accumulated written data. + pub fn into_inner(mut self) -> S { + self.encoder + .finish() + .expect("Writing to a consumer should never fail") + .str_consumer + } +} + +impl<'e, E: Engine> EncoderStringWriter<'e, E, String> { + /// Create a EncoderStringWriter that will encode into a new `String` with the provided config. + pub fn new(engine: &'e E) -> Self { + EncoderStringWriter::from_consumer(String::new(), engine) + } +} + +impl<'e, E: Engine, S: StrConsumer> io::Write for EncoderStringWriter<'e, E, S> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.encoder.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.encoder.flush() + } +} + +/// An abstraction around consuming `str`s produced by base64 encoding. +pub trait StrConsumer { + /// Consume the base64 encoded data in `buf` + fn consume(&mut self, buf: &str); +} + +/// As for io::Write, `StrConsumer` is implemented automatically for `&mut S`. +impl StrConsumer for &mut S { + fn consume(&mut self, buf: &str) { + (**self).consume(buf); + } +} + +/// Pushes the str onto the end of the String +impl StrConsumer for String { + fn consume(&mut self, buf: &str) { + self.push_str(buf); + } +} + +/// A `Write` that only can handle bytes that are valid single-byte UTF-8 code units. +/// +/// This is safe because we only use it when writing base64, which is always valid UTF-8. +struct Utf8SingleCodeUnitWriter { + str_consumer: S, +} + +impl io::Write for Utf8SingleCodeUnitWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + // Because we expect all input to be valid utf-8 individual bytes, we can encode any buffer + // length + let s = std::str::from_utf8(buf).expect("Input must be valid UTF-8"); + + self.str_consumer.consume(s); + + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + // no op + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::{ + engine::Engine, tests::random_engine, write::encoder_string_writer::EncoderStringWriter, + }; + use rand::Rng; + use std::cmp; + use std::io::Write; + + #[test] + fn every_possible_split_of_input() { + let mut rng = rand::thread_rng(); + let mut orig_data = Vec::::new(); + let mut normal_encoded = String::new(); + + let size = 5_000; + + for i in 0..size { + orig_data.clear(); + normal_encoded.clear(); + + orig_data.resize(size, 0); + rng.fill(&mut orig_data[..]); + + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut normal_encoded); + + let mut stream_encoder = EncoderStringWriter::new(&engine); + // Write the first i bytes, then the rest + stream_encoder.write_all(&orig_data[0..i]).unwrap(); + stream_encoder.write_all(&orig_data[i..]).unwrap(); + + let stream_encoded = stream_encoder.into_inner(); + + assert_eq!(normal_encoded, stream_encoded); + } + } + #[test] + fn incremental_writes() { + let mut rng = rand::thread_rng(); + let mut orig_data = Vec::::new(); + let mut normal_encoded = String::new(); + + let size = 5_000; + + for _ in 0..size { + orig_data.clear(); + normal_encoded.clear(); + + orig_data.resize(size, 0); + rng.fill(&mut orig_data[..]); + + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut normal_encoded); + + let mut stream_encoder = EncoderStringWriter::new(&engine); + // write small nibbles of data + let mut offset = 0; + while offset < size { + let nibble_size = cmp::min(rng.gen_range(0..=64), size - offset); + let len = stream_encoder + .write(&orig_data[offset..offset + nibble_size]) + .unwrap(); + offset += len; + } + + let stream_encoded = stream_encoder.into_inner(); + + assert_eq!(normal_encoded, stream_encoded); + } + } +} diff --git a/vendor/base64-0.21.5/src/write/encoder_tests.rs b/vendor/base64-0.21.5/src/write/encoder_tests.rs new file mode 100644 index 00000000..1f1a1650 --- /dev/null +++ b/vendor/base64-0.21.5/src/write/encoder_tests.rs @@ -0,0 +1,554 @@ +use std::io::{Cursor, Write}; +use std::{cmp, io, str}; + +use rand::Rng; + +use crate::{ + alphabet::{STANDARD, URL_SAFE}, + engine::{ + general_purpose::{GeneralPurpose, NO_PAD, PAD}, + Engine, + }, + tests::random_engine, +}; + +use super::EncoderWriter; + +const URL_SAFE_ENGINE: GeneralPurpose = GeneralPurpose::new(&URL_SAFE, PAD); +const NO_PAD_ENGINE: GeneralPurpose = GeneralPurpose::new(&STANDARD, NO_PAD); + +#[test] +fn encode_three_bytes() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + let sz = enc.write(b"abc").unwrap(); + assert_eq!(sz, 3); + } + assert_eq!(&c.get_ref()[..], URL_SAFE_ENGINE.encode("abc").as_bytes()); +} + +#[test] +fn encode_nine_bytes_two_writes() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + let sz = enc.write(b"abcdef").unwrap(); + assert_eq!(sz, 6); + let sz = enc.write(b"ghi").unwrap(); + assert_eq!(sz, 3); + } + assert_eq!( + &c.get_ref()[..], + URL_SAFE_ENGINE.encode("abcdefghi").as_bytes() + ); +} + +#[test] +fn encode_one_then_two_bytes() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + let sz = enc.write(b"a").unwrap(); + assert_eq!(sz, 1); + let sz = enc.write(b"bc").unwrap(); + assert_eq!(sz, 2); + } + assert_eq!(&c.get_ref()[..], URL_SAFE_ENGINE.encode("abc").as_bytes()); +} + +#[test] +fn encode_one_then_five_bytes() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + let sz = enc.write(b"a").unwrap(); + assert_eq!(sz, 1); + let sz = enc.write(b"bcdef").unwrap(); + assert_eq!(sz, 5); + } + assert_eq!( + &c.get_ref()[..], + URL_SAFE_ENGINE.encode("abcdef").as_bytes() + ); +} + +#[test] +fn encode_1_2_3_bytes() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + let sz = enc.write(b"a").unwrap(); + assert_eq!(sz, 1); + let sz = enc.write(b"bc").unwrap(); + assert_eq!(sz, 2); + let sz = enc.write(b"def").unwrap(); + assert_eq!(sz, 3); + } + assert_eq!( + &c.get_ref()[..], + URL_SAFE_ENGINE.encode("abcdef").as_bytes() + ); +} + +#[test] +fn encode_with_padding() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + enc.write_all(b"abcd").unwrap(); + + enc.flush().unwrap(); + } + assert_eq!(&c.get_ref()[..], URL_SAFE_ENGINE.encode("abcd").as_bytes()); +} + +#[test] +fn encode_with_padding_multiple_writes() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + assert_eq!(1, enc.write(b"a").unwrap()); + assert_eq!(2, enc.write(b"bc").unwrap()); + assert_eq!(3, enc.write(b"def").unwrap()); + assert_eq!(1, enc.write(b"g").unwrap()); + + enc.flush().unwrap(); + } + assert_eq!( + &c.get_ref()[..], + URL_SAFE_ENGINE.encode("abcdefg").as_bytes() + ); +} + +#[test] +fn finish_writes_extra_byte() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &URL_SAFE_ENGINE); + + assert_eq!(6, enc.write(b"abcdef").unwrap()); + + // will be in extra + assert_eq!(1, enc.write(b"g").unwrap()); + + // 1 trailing byte = 2 encoded chars + let _ = enc.finish().unwrap(); + } + assert_eq!( + &c.get_ref()[..], + URL_SAFE_ENGINE.encode("abcdefg").as_bytes() + ); +} + +#[test] +fn write_partial_chunk_encodes_partial_chunk() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + // nothing encoded yet + assert_eq!(2, enc.write(b"ab").unwrap()); + // encoded here + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("ab").as_bytes()); + assert_eq!(3, c.get_ref().len()); +} + +#[test] +fn write_1_chunk_encodes_complete_chunk() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + assert_eq!(3, enc.write(b"abc").unwrap()); + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("abc").as_bytes()); + assert_eq!(4, c.get_ref().len()); +} + +#[test] +fn write_1_chunk_and_partial_encodes_only_complete_chunk() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + // "d" not consumed since it's not a full chunk + assert_eq!(3, enc.write(b"abcd").unwrap()); + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("abc").as_bytes()); + assert_eq!(4, c.get_ref().len()); +} + +#[test] +fn write_2_partials_to_exactly_complete_chunk_encodes_complete_chunk() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + assert_eq!(1, enc.write(b"a").unwrap()); + assert_eq!(2, enc.write(b"bc").unwrap()); + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("abc").as_bytes()); + assert_eq!(4, c.get_ref().len()); +} + +#[test] +fn write_partial_then_enough_to_complete_chunk_but_not_complete_another_chunk_encodes_complete_chunk_without_consuming_remaining( +) { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + assert_eq!(1, enc.write(b"a").unwrap()); + // doesn't consume "d" + assert_eq!(2, enc.write(b"bcd").unwrap()); + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("abc").as_bytes()); + assert_eq!(4, c.get_ref().len()); +} + +#[test] +fn write_partial_then_enough_to_complete_chunk_and_another_chunk_encodes_complete_chunks() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + assert_eq!(1, enc.write(b"a").unwrap()); + // completes partial chunk, and another chunk + assert_eq!(5, enc.write(b"bcdef").unwrap()); + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("abcdef").as_bytes()); + assert_eq!(8, c.get_ref().len()); +} + +#[test] +fn write_partial_then_enough_to_complete_chunk_and_another_chunk_and_another_partial_chunk_encodes_only_complete_chunks( +) { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + + assert_eq!(1, enc.write(b"a").unwrap()); + // completes partial chunk, and another chunk, with one more partial chunk that's not + // consumed + assert_eq!(5, enc.write(b"bcdefe").unwrap()); + let _ = enc.finish().unwrap(); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("abcdef").as_bytes()); + assert_eq!(8, c.get_ref().len()); +} + +#[test] +fn drop_calls_finish_for_you() { + let mut c = Cursor::new(Vec::new()); + { + let mut enc = EncoderWriter::new(&mut c, &NO_PAD_ENGINE); + assert_eq!(1, enc.write(b"a").unwrap()); + } + assert_eq!(&c.get_ref()[..], NO_PAD_ENGINE.encode("a").as_bytes()); + assert_eq!(2, c.get_ref().len()); +} + +#[test] +fn every_possible_split_of_input() { + let mut rng = rand::thread_rng(); + let mut orig_data = Vec::::new(); + let mut stream_encoded = Vec::::new(); + let mut normal_encoded = String::new(); + + let size = 5_000; + + for i in 0..size { + orig_data.clear(); + stream_encoded.clear(); + normal_encoded.clear(); + + for _ in 0..size { + orig_data.push(rng.gen()); + } + + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut normal_encoded); + + { + let mut stream_encoder = EncoderWriter::new(&mut stream_encoded, &engine); + // Write the first i bytes, then the rest + stream_encoder.write_all(&orig_data[0..i]).unwrap(); + stream_encoder.write_all(&orig_data[i..]).unwrap(); + } + + assert_eq!(normal_encoded, str::from_utf8(&stream_encoded).unwrap()); + } +} + +#[test] +fn encode_random_config_matches_normal_encode_reasonable_input_len() { + // choose up to 2 * buf size, so ~half the time it'll use a full buffer + do_encode_random_config_matches_normal_encode(super::encoder::BUF_SIZE * 2); +} + +#[test] +fn encode_random_config_matches_normal_encode_tiny_input_len() { + do_encode_random_config_matches_normal_encode(10); +} + +#[test] +fn retrying_writes_that_error_with_interrupted_works() { + let mut rng = rand::thread_rng(); + let mut orig_data = Vec::::new(); + let mut stream_encoded = Vec::::new(); + let mut normal_encoded = String::new(); + + for _ in 0..1_000 { + orig_data.clear(); + stream_encoded.clear(); + normal_encoded.clear(); + + let orig_len: usize = rng.gen_range(100..20_000); + for _ in 0..orig_len { + orig_data.push(rng.gen()); + } + + // encode the normal way + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut normal_encoded); + + // encode via the stream encoder + { + let mut interrupt_rng = rand::thread_rng(); + let mut interrupting_writer = InterruptingWriter { + w: &mut stream_encoded, + rng: &mut interrupt_rng, + fraction: 0.8, + }; + + let mut stream_encoder = EncoderWriter::new(&mut interrupting_writer, &engine); + let mut bytes_consumed = 0; + while bytes_consumed < orig_len { + // use short inputs since we want to use `extra` a lot as that's what needs rollback + // when errors occur + let input_len: usize = cmp::min(rng.gen_range(0..10), orig_len - bytes_consumed); + + retry_interrupted_write_all( + &mut stream_encoder, + &orig_data[bytes_consumed..bytes_consumed + input_len], + ) + .unwrap(); + + bytes_consumed += input_len; + } + + loop { + let res = stream_encoder.finish(); + match res { + Ok(_) => break, + Err(e) => match e.kind() { + io::ErrorKind::Interrupted => continue, + _ => panic!("{:?}", e), // bail + }, + } + } + + assert_eq!(orig_len, bytes_consumed); + } + + assert_eq!(normal_encoded, str::from_utf8(&stream_encoded).unwrap()); + } +} + +#[test] +fn writes_that_only_write_part_of_input_and_sometimes_interrupt_produce_correct_encoded_data() { + let mut rng = rand::thread_rng(); + let mut orig_data = Vec::::new(); + let mut stream_encoded = Vec::::new(); + let mut normal_encoded = String::new(); + + for _ in 0..1_000 { + orig_data.clear(); + stream_encoded.clear(); + normal_encoded.clear(); + + let orig_len: usize = rng.gen_range(100..20_000); + for _ in 0..orig_len { + orig_data.push(rng.gen()); + } + + // encode the normal way + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut normal_encoded); + + // encode via the stream encoder + { + let mut partial_rng = rand::thread_rng(); + let mut partial_writer = PartialInterruptingWriter { + w: &mut stream_encoded, + rng: &mut partial_rng, + full_input_fraction: 0.1, + no_interrupt_fraction: 0.1, + }; + + let mut stream_encoder = EncoderWriter::new(&mut partial_writer, &engine); + let mut bytes_consumed = 0; + while bytes_consumed < orig_len { + // use at most medium-length inputs to exercise retry logic more aggressively + let input_len: usize = cmp::min(rng.gen_range(0..100), orig_len - bytes_consumed); + + let res = + stream_encoder.write(&orig_data[bytes_consumed..bytes_consumed + input_len]); + + // retry on interrupt + match res { + Ok(len) => bytes_consumed += len, + Err(e) => match e.kind() { + io::ErrorKind::Interrupted => continue, + _ => { + panic!("should not see other errors"); + } + }, + } + } + + let _ = stream_encoder.finish().unwrap(); + + assert_eq!(orig_len, bytes_consumed); + } + + assert_eq!(normal_encoded, str::from_utf8(&stream_encoded).unwrap()); + } +} + +/// Retry writes until all the data is written or an error that isn't Interrupted is returned. +fn retry_interrupted_write_all(w: &mut W, buf: &[u8]) -> io::Result<()> { + let mut bytes_consumed = 0; + + while bytes_consumed < buf.len() { + let res = w.write(&buf[bytes_consumed..]); + + match res { + Ok(len) => bytes_consumed += len, + Err(e) => match e.kind() { + io::ErrorKind::Interrupted => continue, + _ => return Err(e), + }, + } + } + + Ok(()) +} + +fn do_encode_random_config_matches_normal_encode(max_input_len: usize) { + let mut rng = rand::thread_rng(); + let mut orig_data = Vec::::new(); + let mut stream_encoded = Vec::::new(); + let mut normal_encoded = String::new(); + + for _ in 0..1_000 { + orig_data.clear(); + stream_encoded.clear(); + normal_encoded.clear(); + + let orig_len: usize = rng.gen_range(100..20_000); + for _ in 0..orig_len { + orig_data.push(rng.gen()); + } + + // encode the normal way + let engine = random_engine(&mut rng); + engine.encode_string(&orig_data, &mut normal_encoded); + + // encode via the stream encoder + { + let mut stream_encoder = EncoderWriter::new(&mut stream_encoded, &engine); + let mut bytes_consumed = 0; + while bytes_consumed < orig_len { + let input_len: usize = + cmp::min(rng.gen_range(0..max_input_len), orig_len - bytes_consumed); + + // write a little bit of the data + stream_encoder + .write_all(&orig_data[bytes_consumed..bytes_consumed + input_len]) + .unwrap(); + + bytes_consumed += input_len; + } + + let _ = stream_encoder.finish().unwrap(); + + assert_eq!(orig_len, bytes_consumed); + } + + assert_eq!(normal_encoded, str::from_utf8(&stream_encoded).unwrap()); + } +} + +/// A `Write` implementation that returns Interrupted some fraction of the time, randomly. +struct InterruptingWriter<'a, W: 'a + Write, R: 'a + Rng> { + w: &'a mut W, + rng: &'a mut R, + /// In [0, 1]. If a random number in [0, 1] is `<= threshold`, `Write` methods will return + /// an `Interrupted` error + fraction: f64, +} + +impl<'a, W: Write, R: Rng> Write for InterruptingWriter<'a, W, R> { + fn write(&mut self, buf: &[u8]) -> io::Result { + if self.rng.gen_range(0.0..1.0) <= self.fraction { + return Err(io::Error::new(io::ErrorKind::Interrupted, "interrupted")); + } + + self.w.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + if self.rng.gen_range(0.0..1.0) <= self.fraction { + return Err(io::Error::new(io::ErrorKind::Interrupted, "interrupted")); + } + + self.w.flush() + } +} + +/// A `Write` implementation that sometimes will only write part of its input. +struct PartialInterruptingWriter<'a, W: 'a + Write, R: 'a + Rng> { + w: &'a mut W, + rng: &'a mut R, + /// In [0, 1]. If a random number in [0, 1] is `<= threshold`, `write()` will write all its + /// input. Otherwise, it will write a random substring + full_input_fraction: f64, + no_interrupt_fraction: f64, +} + +impl<'a, W: Write, R: Rng> Write for PartialInterruptingWriter<'a, W, R> { + fn write(&mut self, buf: &[u8]) -> io::Result { + if self.rng.gen_range(0.0..1.0) > self.no_interrupt_fraction { + return Err(io::Error::new(io::ErrorKind::Interrupted, "interrupted")); + } + + if self.rng.gen_range(0.0..1.0) <= self.full_input_fraction || buf.is_empty() { + // pass through the buf untouched + self.w.write(buf) + } else { + // only use a prefix of it + self.w + .write(&buf[0..(self.rng.gen_range(0..(buf.len() - 1)))]) + } + } + + fn flush(&mut self) -> io::Result<()> { + self.w.flush() + } +} diff --git a/vendor/base64-0.21.5/src/write/mod.rs b/vendor/base64-0.21.5/src/write/mod.rs new file mode 100644 index 00000000..2a617db9 --- /dev/null +++ b/vendor/base64-0.21.5/src/write/mod.rs @@ -0,0 +1,11 @@ +//! Implementations of `io::Write` to transparently handle base64. +mod encoder; +mod encoder_string_writer; + +pub use self::{ + encoder::EncoderWriter, + encoder_string_writer::{EncoderStringWriter, StrConsumer}, +}; + +#[cfg(test)] +mod encoder_tests; diff --git a/vendor/base64-0.21.5/tests/encode.rs b/vendor/base64-0.21.5/tests/encode.rs new file mode 100644 index 00000000..9d694474 --- /dev/null +++ b/vendor/base64-0.21.5/tests/encode.rs @@ -0,0 +1,77 @@ +use base64::{ + alphabet::URL_SAFE, engine::general_purpose::PAD, engine::general_purpose::STANDARD, *, +}; + +fn compare_encode(expected: &str, target: &[u8]) { + assert_eq!(expected, STANDARD.encode(target)); +} + +#[test] +fn encode_all_ascii() { + let ascii: Vec = (0..=127).collect(); + + compare_encode( + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7P\ + D0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8\ + =", + &ascii, + ); +} + +#[test] +fn encode_all_bytes() { + let bytes: Vec = (0..=255).collect(); + + compare_encode( + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7P\ + D0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\ + +AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6\ + /wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==", + &bytes, + ); +} + +#[test] +fn encode_all_bytes_url() { + let bytes: Vec = (0..=255).collect(); + + assert_eq!( + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0\ + -P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn\ + -AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq\ + -wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy\ + 8_T19vf4-fr7_P3-_w==", + &engine::GeneralPurpose::new(&URL_SAFE, PAD).encode(bytes) + ); +} + +#[test] +fn encoded_len_unpadded() { + assert_eq!(0, encoded_len(0, false).unwrap()); + assert_eq!(2, encoded_len(1, false).unwrap()); + assert_eq!(3, encoded_len(2, false).unwrap()); + assert_eq!(4, encoded_len(3, false).unwrap()); + assert_eq!(6, encoded_len(4, false).unwrap()); + assert_eq!(7, encoded_len(5, false).unwrap()); + assert_eq!(8, encoded_len(6, false).unwrap()); + assert_eq!(10, encoded_len(7, false).unwrap()); +} + +#[test] +fn encoded_len_padded() { + assert_eq!(0, encoded_len(0, true).unwrap()); + assert_eq!(4, encoded_len(1, true).unwrap()); + assert_eq!(4, encoded_len(2, true).unwrap()); + assert_eq!(4, encoded_len(3, true).unwrap()); + assert_eq!(8, encoded_len(4, true).unwrap()); + assert_eq!(8, encoded_len(5, true).unwrap()); + assert_eq!(8, encoded_len(6, true).unwrap()); + assert_eq!(12, encoded_len(7, true).unwrap()); +} +#[test] +fn encoded_len_overflow() { + let max_size = usize::MAX / 4 * 3 + 2; + assert_eq!(2, max_size % 3); + assert_eq!(Some(usize::MAX), encoded_len(max_size, false)); + assert_eq!(None, encoded_len(max_size + 1, false)); +} diff --git a/vendor/base64-0.21.5/tests/tests.rs b/vendor/base64-0.21.5/tests/tests.rs new file mode 100644 index 00000000..eceff40d --- /dev/null +++ b/vendor/base64-0.21.5/tests/tests.rs @@ -0,0 +1,161 @@ +use rand::{Rng, SeedableRng}; + +use base64::engine::{general_purpose::STANDARD, Engine}; +use base64::*; + +use base64::engine::general_purpose::{GeneralPurpose, NO_PAD}; + +// generate random contents of the specified length and test encode/decode roundtrip +fn roundtrip_random( + byte_buf: &mut Vec, + str_buf: &mut String, + engine: &E, + byte_len: usize, + approx_values_per_byte: u8, + max_rounds: u64, +) { + // let the short ones be short but don't let it get too crazy large + let num_rounds = calculate_number_of_rounds(byte_len, approx_values_per_byte, max_rounds); + let mut r = rand::rngs::SmallRng::from_entropy(); + let mut decode_buf = Vec::new(); + + for _ in 0..num_rounds { + byte_buf.clear(); + str_buf.clear(); + decode_buf.clear(); + while byte_buf.len() < byte_len { + byte_buf.push(r.gen::()); + } + + engine.encode_string(&byte_buf, str_buf); + engine.decode_vec(&str_buf, &mut decode_buf).unwrap(); + + assert_eq!(byte_buf, &decode_buf); + } +} + +fn calculate_number_of_rounds(byte_len: usize, approx_values_per_byte: u8, max: u64) -> u64 { + // don't overflow + let mut prod = approx_values_per_byte as u64; + + for _ in 0..byte_len { + if prod > max { + return max; + } + + prod = prod.saturating_mul(prod); + } + + prod +} + +#[test] +fn roundtrip_random_short_standard() { + let mut byte_buf: Vec = Vec::new(); + let mut str_buf = String::new(); + + for input_len in 0..40 { + roundtrip_random(&mut byte_buf, &mut str_buf, &STANDARD, input_len, 4, 10000); + } +} + +#[test] +fn roundtrip_random_with_fast_loop_standard() { + let mut byte_buf: Vec = Vec::new(); + let mut str_buf = String::new(); + + for input_len in 40..100 { + roundtrip_random(&mut byte_buf, &mut str_buf, &STANDARD, input_len, 4, 1000); + } +} + +#[test] +fn roundtrip_random_short_no_padding() { + let mut byte_buf: Vec = Vec::new(); + let mut str_buf = String::new(); + + let engine = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD); + for input_len in 0..40 { + roundtrip_random(&mut byte_buf, &mut str_buf, &engine, input_len, 4, 10000); + } +} + +#[test] +fn roundtrip_random_no_padding() { + let mut byte_buf: Vec = Vec::new(); + let mut str_buf = String::new(); + + let engine = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD); + + for input_len in 40..100 { + roundtrip_random(&mut byte_buf, &mut str_buf, &engine, input_len, 4, 1000); + } +} + +#[test] +fn roundtrip_decode_trailing_10_bytes() { + // This is a special case because we decode 8 byte blocks of input at a time as much as we can, + // ideally unrolled to 32 bytes at a time, in stages 1 and 2. Since we also write a u64's worth + // of bytes (8) to the output, we always write 2 garbage bytes that then will be overwritten by + // the NEXT block. However, if the next block only contains 2 bytes, it will decode to 1 byte, + // and therefore be too short to cover up the trailing 2 garbage bytes. Thus, we have stage 3 + // to handle that case. + + for num_quads in 0..25 { + let mut s: String = "ABCD".repeat(num_quads); + s.push_str("EFGHIJKLZg"); + + let engine = GeneralPurpose::new(&alphabet::STANDARD, NO_PAD); + let decoded = engine.decode(&s).unwrap(); + assert_eq!(num_quads * 3 + 7, decoded.len()); + + assert_eq!(s, engine.encode(&decoded)); + } +} + +#[test] +fn display_wrapper_matches_normal_encode() { + let mut bytes = Vec::::with_capacity(256); + + for i in 0..255 { + bytes.push(i); + } + bytes.push(255); + + assert_eq!( + STANDARD.encode(&bytes), + format!("{}", display::Base64Display::new(&bytes, &STANDARD)) + ); +} + +#[test] +fn encode_engine_slice_error_when_buffer_too_small() { + for num_triples in 1..100 { + let input = "AAA".repeat(num_triples); + let mut vec = vec![0; (num_triples - 1) * 4]; + assert_eq!( + EncodeSliceError::OutputSliceTooSmall, + STANDARD.encode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + assert_eq!( + EncodeSliceError::OutputSliceTooSmall, + STANDARD.encode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + assert_eq!( + EncodeSliceError::OutputSliceTooSmall, + STANDARD.encode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + assert_eq!( + EncodeSliceError::OutputSliceTooSmall, + STANDARD.encode_slice(&input, &mut vec).unwrap_err() + ); + vec.push(0); + assert_eq!( + num_triples * 4, + STANDARD.encode_slice(&input, &mut vec).unwrap() + ); + } +} diff --git a/vendor/base64/.cargo-checksum.json b/vendor/base64/.cargo-checksum.json index 7aab19ce..74114189 100644 --- a/vendor/base64/.cargo-checksum.json +++ b/vendor/base64/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"3fcb2ea14aeaf0ebde20e464f0a735b2f58b0fecc99a20c11421ce47788911b8","Cargo.toml":"8a94eedc97a8458e7becfa780a67dfa2ea959bb5660c77dc8236fb7c6a9a64e6","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"df01f5b4317d601e7de86743f9818aec9196abf9e298f5e47679b7a966ecd945","RELEASE-NOTES.md":"fa36233aeddb2e63dc0580ffc69a5a1cdbf24f962146ab2d6b817381e2f38cdd","benches/benchmarks.rs":"da4a49294a7fcaf718f2b062a52ed669ca096abce6c57b4025efdd24825048c2","clippy.toml":"b26be4d15ed059985ce6994f11817fd7562046f46e460a0dc64dbb71cfc246d1","examples/base64.rs":"8c48673029aeeb1e06a2ecfd237acf8ef24349990e97f6d2c4d0fa2af36c94b3","icon_CLion.svg":"cffa044ba75cb998ee3306991dc4a3755ec2f39ab95ddd4b74bc21988389020f","src/alphabet.rs":"f0cba9462692db0bc9572e3d03c01ac77ff705fa9e664db4162da1a279a871e1","src/chunked_encoder.rs":"edfdbb9a4329b80fb2c769ada81e234e00839e0fa85faaa70bacf40ce12e951c","src/decode.rs":"666ca75ccd975f0548d37312d2843ca4703b83697a044839bbefeba8f4f7874a","src/display.rs":"31bf3e19274a0b80dd8948a81ea535944f756ef5b88736124c940f5fe1e8c71c","src/encode.rs":"0c827067fced8a20723be2586ebbad94e4749e2cdad463091c4fd6899bd1d0e7","src/engine/general_purpose/decode.rs":"ba8a76d333ab96dd07b3f84bd6d405d690d2d17e84bd0878f05245a82dc16853","src/engine/general_purpose/decode_suffix.rs":"71ceb066b73e8cc833916e2cedbf0a01b07c2f16e30b2b2f63aff1c823874b51","src/engine/general_purpose/mod.rs":"9f49375fc03166a491acf464daa7a9e6540fdc2cca407da9a248e15640952c20","src/engine/mod.rs":"15210115e5f99e0d252a1240922deb1516778e318564f92a9d880a82fd82a55e","src/engine/naive.rs":"dc166010633e8de0fbff31e2f05d128506f3e0f34a6358c1a825b59a8ea1af0d","src/engine/tests.rs":"37bee2de07343bf5d37720f29cda291e8562f2363704e0ad91862d5991568d22","src/lib.rs":"c1eb62ba9f461dfa00b5297c9bc3d9f6c6702295806d43bb82e46ffb54ea61ed","src/prelude.rs":"c1587138e5301ac797c5c362cb3638649b33f79c20c16db6f38ad44330540752","src/read/decoder.rs":"cc87daa4c52a23d1275352bccf07468baf2b60e90b2ac14f89a94254697cb83c","src/read/decoder_tests.rs":"edeee377e70095532be1625d0148de2273b739e9069a05e616d3e67877d92f1d","src/read/mod.rs":"e0b714eda02d16b1ffa6f78fd09b2f963e01c881b1f7c17b39db4e904be5e746","src/tests.rs":"90cb9f8a1ccb7c4ddc4f8618208e0031fc97e0df0e5aa466d6a5cf45d25967d8","src/write/encoder.rs":"c889c853249220fe2ddaeb77ee6e2ee2945f7db88cd6658ef89ff71b81255ea8","src/write/encoder_string_writer.rs":"0326c9d120369b9bbc35697b5b9b141bed24283374c93d5af1052eb042e47799","src/write/encoder_tests.rs":"28695a485b17cf5db73656aae5d90127f726e02c6d70efd83e5ab53a4cc17b38","src/write/mod.rs":"73cd98dadc9d712b3fefd9449d97e825e097397441b90588e0051e4d3b0911b9","tests/encode.rs":"5309f4538b1df611436f7bfba7409c725161b6f841b1bbf8d9890ae185de7d88","tests/tests.rs":"78efcf0dc4bb6ae52f7a91fcad89e44e4dce578224c36b4e6c1c306459be8500"},"package":"35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"} \ No newline at end of file +{"files":{"Cargo.lock":"cee37732975a1ffc1f956d3d05b6edf1baec72841cfabc384a21b02b3bfa0275","Cargo.toml":"52bee6a418e14918d37058fd15fccfd0f417a06fe4f9668b6f97866bf7f991e3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0dd882e53de11566d50f8e8e2d5a651bcf3fabee4987d70f306233cf39094ba7","README.md":"df01f5b4317d601e7de86743f9818aec9196abf9e298f5e47679b7a966ecd945","RELEASE-NOTES.md":"997a5193317a8bff266ecfe4f015ba070b782b6df7d3a1738b9b52584d57f9c6","benches/benchmarks.rs":"cebbcc8649e760e569c6be04f5e727aee2c2568ced7faab580fc0aa0d0426d26","clippy.toml":"b26be4d15ed059985ce6994f11817fd7562046f46e460a0dc64dbb71cfc246d1","examples/base64.rs":"b75ead2199a9b4389c69fe6f1ae988176a263b8fc84e7a4fea1d7e5a41592078","icon_CLion.svg":"cffa044ba75cb998ee3306991dc4a3755ec2f39ab95ddd4b74bc21988389020f","src/alphabet.rs":"5de2beb8fcccb078c61cac2c0477ebbde145122d6c10a0f7ea2e57e8159318e0","src/chunked_encoder.rs":"edfdbb9a4329b80fb2c769ada81e234e00839e0fa85faaa70bacf40ce12e951c","src/decode.rs":"b046a72d62eaac58dc42efcf7848d9d96d022f6594e851cf87074b77ce45c04a","src/display.rs":"31bf3e19274a0b80dd8948a81ea535944f756ef5b88736124c940f5fe1e8c71c","src/encode.rs":"44ddcc162f3fe9817b6e857dda0a3b9197b90a657e5f71c44aacabf5431ccf7d","src/engine/general_purpose/decode.rs":"d865b057e5788e7fefd189cf57ec913df263e6a0742dfa52513f587e14fa1a92","src/engine/general_purpose/decode_suffix.rs":"689688f7bf442b232d3b9f56a1b41c56d9393ace88556a165c224b93dd19b74e","src/engine/general_purpose/mod.rs":"901760a7f5721ec3bafad5fea6251f57de0f767ecb2e1e2fdfe64d661404ec34","src/engine/mod.rs":"5e4a6c0e86417f3b62350264ef383f91e9864390f7c315d786ecd8e9c920ee9f","src/engine/naive.rs":"70de29d909c3fe7918d2965782088b05047b8b6e30d1d2bf11ba073d3f8633ff","src/engine/tests.rs":"2cc8d1431f40f5b9c3ad8970e6fb73bba8be3f2317553dd026539f41908aaa19","src/lib.rs":"c4db7bd31ace78aec2ecd151cef3ad90dfdc76097ba12027bde79d3c82612f7c","src/prelude.rs":"c1587138e5301ac797c5c362cb3638649b33f79c20c16db6f38ad44330540752","src/read/decoder.rs":"00aaa0553a54fcf12762658c4e56663a9705cc30c07af30976291e6f69d78c3d","src/read/decoder_tests.rs":"66ec39bf6e86f21f4db1afd6c5cd63d4a4931ab896b9c38de25d99b803804bbf","src/read/mod.rs":"e0b714eda02d16b1ffa6f78fd09b2f963e01c881b1f7c17b39db4e904be5e746","src/tests.rs":"90cb9f8a1ccb7c4ddc4f8618208e0031fc97e0df0e5aa466d6a5cf45d25967d8","src/write/encoder.rs":"c889c853249220fe2ddaeb77ee6e2ee2945f7db88cd6658ef89ff71b81255ea8","src/write/encoder_string_writer.rs":"0326c9d120369b9bbc35697b5b9b141bed24283374c93d5af1052eb042e47799","src/write/encoder_tests.rs":"28695a485b17cf5db73656aae5d90127f726e02c6d70efd83e5ab53a4cc17b38","src/write/mod.rs":"73cd98dadc9d712b3fefd9449d97e825e097397441b90588e0051e4d3b0911b9","tests/encode.rs":"5309f4538b1df611436f7bfba7409c725161b6f841b1bbf8d9890ae185de7d88","tests/tests.rs":"78efcf0dc4bb6ae52f7a91fcad89e44e4dce578224c36b4e6c1c306459be8500"},"package":"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"} \ No newline at end of file diff --git a/vendor/base64/Cargo.lock b/vendor/base64/Cargo.lock index da628ba3..84e188d1 100644 --- a/vendor/base64/Cargo.lock +++ b/vendor/base64/Cargo.lock @@ -3,36 +3,179 @@ version = 3 [[package]] -name = "aho-corasick" +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "async-attributes" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ - "memchr", + "quote", + "syn 1.0.109", ] [[package]] -name = "anes" -version = "0.1.6" +name = "async-channel" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "async-channel" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ - "winapi", + "concurrent-queue", + "event-listener 5.2.0", + "event-listener-strategy 0.5.0", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae5ebefcc48e7452b4987947920dac9450be1110cadf34d1b8c116bdbaf97c" +dependencies = [ + "async-lock 3.3.0", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.2.0", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.2.0", + "async-executor", + "async-io 2.3.1", + "async-lock 3.3.0", + "blocking", + "futures-lite 2.2.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2", + "waker-fn", ] +[[package]] +name = "async-io" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f97ab0c5b00a7cdbe5a371b9a782ee7be1316095885c8a4ea1daf490eb0ef65" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.2.0", + "parking", + "polling 3.4.0", + "rustix 0.38.9", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -45,14 +188,15 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.21.5" +version = "0.22.1" dependencies = [ + "clap", "criterion", - "lazy_static", + "once_cell", "rand", "rstest", "rstest_reuse", - "structopt", + "strum", ] [[package]] @@ -61,11 +205,33 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel 2.2.0", + "async-lock 3.3.0", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.2.0", + "piper", + "tracing", +] + [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "8ea184aa71bb362a1157c896979544cc23974e08fd265f29ea96b59f0b4a555b" [[package]] name = "cast" @@ -81,9 +247,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -92,15 +258,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -108,29 +274,32 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ - "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "indexmap", + "once_cell", "strsim", - "textwrap 0.11.0", - "unicode-width", - "vec_map", + "termcolor", + "textwrap", ] [[package]] -name = "clap" +name = "clap_derive" version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "textwrap 0.16.0", + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -142,6 +311,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "criterion" version = "0.4.0" @@ -152,7 +330,7 @@ dependencies = [ "atty", "cast", "ciborium", - "clap 3.2.25", + "clap", "criterion-plot", "itertools", "lazy_static", @@ -180,59 +358,279 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "ctor" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ - "cfg-if", + "quote", + "syn 1.0.109", ] [[package]] name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.2.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445ba825b27408685aaecefd65178908c36c6e96aaf6d8599419d46e624192ba" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "half" -version = "1.8.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -242,12 +640,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -258,6 +653,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "indexmap" version = "1.9.3" @@ -268,6 +669,26 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -279,19 +700,28 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -300,45 +730,52 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "log" -version = "0.4.20" +name = "linux-raw-sys" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] -name = "memchr" -version = "2.6.4" +name = "linux-raw-sys" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] -name = "memoffset" -version = "0.9.0" +name = "log" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "autocfg", + "cfg-if", + "value-bag", ] +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" @@ -352,6 +789,35 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + [[package]] name = "plotters" version = "0.3.5" @@ -380,6 +846,36 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.9", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -412,18 +908,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -460,9 +956,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", @@ -470,9 +966,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -480,38 +976,37 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", "regex-syntax", ] [[package]] -name = "regex-automata" -version = "0.4.3" +name = "regex-syntax" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] -name = "regex-syntax" -version = "0.8.2" +name = "rstest" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "b939295f93cb1d12bc1a83cf9ee963199b133fb8a79832dd51b68bb9f59a04dc" +dependencies = [ + "async-std", + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] [[package]] -name = "rstest" -version = "0.12.0" +name = "rstest_macros" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d912f35156a3f99a66ee3e11ac2e0b3f34ac85a07e05263d05a7e2c8810d616f" +checksum = "f78aba848123782ba59340928ec7d876ebe745aa0365d6af8a630f19a5c16116" dependencies = [ "cfg-if", "proc-macro2", @@ -522,13 +1017,14 @@ dependencies = [ [[package]] name = "rstest_reuse" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b29d3117bce27ea307d1fb7ce12c64ba11b3fd04311a42d32bc5f0072e6e3d4d" +checksum = "88530b681abe67924d42cca181d070e3ac20e0740569441a9e35a7cedd2b34a4" dependencies = [ "quote", + "rand", "rustc_version", - "syn 1.0.109", + "syn 2.0.52", ] [[package]] @@ -540,11 +1036,44 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -555,77 +1084,88 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "semver" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.52", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "structopt" -version = "0.3.26" +name = "strum" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "clap 2.34.0", - "lazy_static", - "structopt-derive", + "strum_macros", ] [[package]] -name = "structopt-derive" -version = "0.4.18" +name = "strum_macros" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "rustversion", + "syn 2.0.52", ] [[package]] @@ -641,9 +1181,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -651,19 +1191,19 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "termcolor" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ - "unicode-width", + "winapi-util", ] [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "tinytemplate" @@ -676,28 +1216,36 @@ dependencies = [ ] [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "tracing" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] [[package]] -name = "unicode-segmentation" -version = "1.10.1" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] -name = "unicode-width" -version = "0.1.11" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "vec_map" -version = "0.8.2" +name = "value-bag" +version = "1.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] [[package]] name = "version_check" @@ -705,11 +1253,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -723,9 +1277,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -733,24 +1287,36 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.52", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -758,28 +1324,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446" dependencies = [ "js-sys", "wasm-bindgen", @@ -815,3 +1381,135 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" diff --git a/vendor/base64/Cargo.toml b/vendor/base64/Cargo.toml index 2de75ab2..e1b35fc4 100644 --- a/vendor/base64/Cargo.toml +++ b/vendor/base64/Cargo.toml @@ -13,11 +13,8 @@ edition = "2018" rust-version = "1.48.0" name = "base64" -version = "0.21.5" -authors = [ - "Alice Maz ", - "Marshall Pierce ", -] +version = "0.22.1" +authors = ["Marshall Pierce "] description = "encodes and decodes base64 as bytes or utf8" documentation = "https://docs.rs/base64" readme = "README.md" @@ -58,24 +55,29 @@ name = "benchmarks" harness = false required-features = ["std"] +[dev-dependencies.clap] +version = "3.2.25" +features = ["derive"] + [dev-dependencies.criterion] version = "0.4.0" -[dev-dependencies.lazy_static] -version = "1.4.0" +[dev-dependencies.once_cell] +version = "1" [dev-dependencies.rand] version = "0.8.5" features = ["small_rng"] [dev-dependencies.rstest] -version = "0.12.0" +version = "0.13.0" [dev-dependencies.rstest_reuse] -version = "0.3.0" +version = "0.6.0" -[dev-dependencies.structopt] -version = "0.3.26" +[dev-dependencies.strum] +version = "0.25" +features = ["derive"] [features] alloc = [] diff --git a/vendor/base64/RELEASE-NOTES.md b/vendor/base64/RELEASE-NOTES.md index d6d94c5a..91b68a67 100644 --- a/vendor/base64/RELEASE-NOTES.md +++ b/vendor/base64/RELEASE-NOTES.md @@ -1,3 +1,21 @@ +# 0.22.1 + +- Correct the symbols used for the predefined `alphabet::BIN_HEX`. + +# 0.22.0 + +- `DecodeSliceError::OutputSliceTooSmall` is now conservative rather than precise. That is, the error will only occur if the decoded output _cannot_ fit, meaning that `Engine::decode_slice` can now be used with exactly-sized output slices. As part of this, `Engine::internal_decode` now returns `DecodeSliceError` instead of `DecodeError`, but that is not expected to affect any external callers. +- `DecodeError::InvalidLength` now refers specifically to the _number of valid symbols_ being invalid (i.e. `len % 4 == 1`), rather than just the number of input bytes. This avoids confusing scenarios when based on interpretation you could make a case for either `InvalidLength` or `InvalidByte` being appropriate. +- Decoding is somewhat faster (5-10%) + +# 0.21.7 + +- Support getting an alphabet's contents as a str via `Alphabet::as_str()` + +# 0.21.6 + +- Improved introductory documentation and example + # 0.21.5 - Add `Debug` and `Clone` impls for the general purpose Engine diff --git a/vendor/base64/benches/benchmarks.rs b/vendor/base64/benches/benchmarks.rs index 802c8cca..8f041854 100644 --- a/vendor/base64/benches/benchmarks.rs +++ b/vendor/base64/benches/benchmarks.rs @@ -102,9 +102,8 @@ fn do_encode_bench_slice(b: &mut Bencher, &size: &usize) { fn do_encode_bench_stream(b: &mut Bencher, &size: &usize) { let mut v: Vec = Vec::with_capacity(size); fill(&mut v); - let mut buf = Vec::new(); + let mut buf = Vec::with_capacity(size * 2); - buf.reserve(size * 2); b.iter(|| { buf.clear(); let mut stream_enc = write::EncoderWriter::new(&mut buf, &STANDARD); diff --git a/vendor/base64/examples/base64.rs b/vendor/base64/examples/base64.rs index 0a214d28..0c8aa3fe 100644 --- a/vendor/base64/examples/base64.rs +++ b/vendor/base64/examples/base64.rs @@ -2,51 +2,40 @@ use std::fs::File; use std::io::{self, Read}; use std::path::PathBuf; use std::process; -use std::str::FromStr; use base64::{alphabet, engine, read, write}; -use structopt::StructOpt; +use clap::Parser; -#[derive(Debug, StructOpt)] +#[derive(Clone, Debug, Parser, strum::EnumString, Default)] +#[strum(serialize_all = "kebab-case")] enum Alphabet { + #[default] Standard, UrlSafe, } -impl Default for Alphabet { - fn default() -> Self { - Self::Standard - } -} - -impl FromStr for Alphabet { - type Err = String; - fn from_str(s: &str) -> Result { - match s { - "standard" => Ok(Self::Standard), - "urlsafe" => Ok(Self::UrlSafe), - _ => Err(format!("alphabet '{}' unrecognized", s)), - } - } -} - /// Base64 encode or decode FILE (or standard input), to standard output. -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] struct Opt { - /// decode data - #[structopt(short = "d", long = "decode")] + /// Decode the base64-encoded input (default: encode the input as base64). + #[structopt(short = 'd', long = "decode")] decode: bool, - /// The alphabet to choose. Defaults to the standard base64 alphabet. - /// Supported alphabets include "standard" and "urlsafe". + + /// The encoding alphabet: "standard" (default) or "url-safe". #[structopt(long = "alphabet")] alphabet: Option, - /// The file to encode/decode. - #[structopt(parse(from_os_str))] + + /// Omit padding characters while encoding, and reject them while decoding. + #[structopt(short = 'p', long = "no-padding")] + no_padding: bool, + + /// The file to encode or decode. + #[structopt(name = "FILE", parse(from_os_str))] file: Option, } fn main() { - let opt = Opt::from_args(); + let opt = Opt::parse(); let stdin; let mut input: Box = match opt.file { None => { @@ -66,7 +55,10 @@ fn main() { Alphabet::Standard => alphabet::STANDARD, Alphabet::UrlSafe => alphabet::URL_SAFE, }, - engine::general_purpose::PAD, + match opt.no_padding { + true => engine::general_purpose::NO_PAD, + false => engine::general_purpose::PAD, + }, ); let stdout = io::stdout(); diff --git a/vendor/base64/src/alphabet.rs b/vendor/base64/src/alphabet.rs index f7cd8191..b07bfdfe 100644 --- a/vendor/base64/src/alphabet.rs +++ b/vendor/base64/src/alphabet.rs @@ -38,17 +38,18 @@ const ALPHABET_SIZE: usize = 64; /// }; /// ``` /// -/// Building a lazy_static: +/// Building lazily: /// /// ``` /// use base64::{ /// alphabet::Alphabet, /// engine::{general_purpose::GeneralPurpose, GeneralPurposeConfig}, /// }; +/// use once_cell::sync::Lazy; /// -/// lazy_static::lazy_static! { -/// static ref CUSTOM: Alphabet = Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap(); -/// } +/// static CUSTOM: Lazy = Lazy::new(|| +/// Alphabet::new("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").unwrap() +/// ); /// ``` #[derive(Clone, Debug, Eq, PartialEq)] pub struct Alphabet { @@ -122,6 +123,11 @@ impl Alphabet { Ok(Self::from_str_unchecked(alphabet)) } + + /// Create a `&str` from the symbols in the `Alphabet` + pub fn as_str(&self) -> &str { + core::str::from_utf8(&self.symbols).unwrap() + } } impl convert::TryFrom<&str> for Alphabet { @@ -159,21 +165,21 @@ impl fmt::Display for ParseAlphabetError { #[cfg(any(feature = "std", test))] impl error::Error for ParseAlphabetError {} -/// The standard alphabet (uses `+` and `/`). +/// The standard alphabet (with `+` and `/`) specified in [RFC 4648][]. /// -/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-3). +/// [RFC 4648]: https://datatracker.ietf.org/doc/html/rfc4648#section-4 pub const STANDARD: Alphabet = Alphabet::from_str_unchecked( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", ); -/// The URL safe alphabet (uses `-` and `_`). +/// The URL-safe alphabet (with `-` and `_`) specified in [RFC 4648][]. /// -/// See [RFC 3548](https://tools.ietf.org/html/rfc3548#section-4). +/// [RFC 4648]: https://datatracker.ietf.org/doc/html/rfc4648#section-5 pub const URL_SAFE: Alphabet = Alphabet::from_str_unchecked( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", ); -/// The `crypt(3)` alphabet (uses `.` and `/` as the first two values). +/// The `crypt(3)` alphabet (with `.` and `/` as the _first_ two characters). /// /// Not standardized, but folk wisdom on the net asserts that this alphabet is what crypt uses. pub const CRYPT: Alphabet = Alphabet::from_str_unchecked( @@ -185,7 +191,7 @@ pub const BCRYPT: Alphabet = Alphabet::from_str_unchecked( "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", ); -/// The alphabet used in IMAP-modified UTF-7 (uses `+` and `,`). +/// The alphabet used in IMAP-modified UTF-7 (with `+` and `,`). /// /// See [RFC 3501](https://tools.ietf.org/html/rfc3501#section-5.1.3) pub const IMAP_MUTF7: Alphabet = Alphabet::from_str_unchecked( @@ -196,7 +202,7 @@ pub const IMAP_MUTF7: Alphabet = Alphabet::from_str_unchecked( /// /// See [BinHex 4.0 Definition](http://files.stairways.com/other/binhex-40-specs-info.txt) pub const BIN_HEX: Alphabet = Alphabet::from_str_unchecked( - "!\"#$%&'()*+,-0123456789@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdehijklmpqr", + "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr", ); #[cfg(test)] @@ -269,4 +275,11 @@ mod tests { .unwrap() ); } + + #[test] + fn str_same_as_input() { + let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let a = Alphabet::try_from(alphabet).unwrap(); + assert_eq!(alphabet, a.as_str()) + } } diff --git a/vendor/base64/src/decode.rs b/vendor/base64/src/decode.rs index 5230fd3c..6df8abad 100644 --- a/vendor/base64/src/decode.rs +++ b/vendor/base64/src/decode.rs @@ -9,18 +9,20 @@ use std::error; #[derive(Clone, Debug, PartialEq, Eq)] pub enum DecodeError { /// An invalid byte was found in the input. The offset and offending byte are provided. - /// Padding characters (`=`) interspersed in the encoded form will be treated as invalid bytes. + /// + /// Padding characters (`=`) interspersed in the encoded form are invalid, as they may only + /// be present as the last 0-2 bytes of input. + /// + /// This error may also indicate that extraneous trailing input bytes are present, causing + /// otherwise valid padding to no longer be the last bytes of input. InvalidByte(usize, u8), - /// The length of the input is invalid. - /// A typical cause of this is stray trailing whitespace or other separator bytes. - /// In the case where excess trailing bytes have produced an invalid length *and* the last byte - /// is also an invalid base64 symbol (as would be the case for whitespace, etc), `InvalidByte` - /// will be emitted instead of `InvalidLength` to make the issue easier to debug. - InvalidLength, + /// The length of the input, as measured in valid base64 symbols, is invalid. + /// There must be 2-4 symbols in the last input quad. + InvalidLength(usize), /// The last non-padding input symbol's encoded 6 bits have nonzero bits that will be discarded. /// This is indicative of corrupted or truncated Base64. - /// Unlike `InvalidByte`, which reports symbols that aren't in the alphabet, this error is for - /// symbols that are in the alphabet but represent nonsensical encodings. + /// Unlike [DecodeError::InvalidByte], which reports symbols that aren't in the alphabet, + /// this error is for symbols that are in the alphabet but represent nonsensical encodings. InvalidLastSymbol(usize, u8), /// The nature of the padding was not as configured: absent or incorrect when it must be /// canonical, or present when it must be absent, etc. @@ -30,8 +32,10 @@ pub enum DecodeError { impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Self::InvalidByte(index, byte) => write!(f, "Invalid byte {}, offset {}.", byte, index), - Self::InvalidLength => write!(f, "Encoded text cannot have a 6-bit remainder."), + Self::InvalidByte(index, byte) => { + write!(f, "Invalid symbol {}, offset {}.", byte, index) + } + Self::InvalidLength(len) => write!(f, "Invalid input length: {}", len), Self::InvalidLastSymbol(index, byte) => { write!(f, "Invalid last symbol {}, offset {}.", byte, index) } @@ -48,9 +52,7 @@ impl error::Error for DecodeError {} pub enum DecodeSliceError { /// A [DecodeError] occurred DecodeError(DecodeError), - /// The provided slice _may_ be too small. - /// - /// The check is conservative (assumes the last triplet of output bytes will all be needed). + /// The provided slice is too small. OutputSliceTooSmall, } @@ -338,3 +340,47 @@ mod tests { } } } + +#[allow(deprecated)] +#[cfg(test)] +mod coverage_gaming { + use super::*; + use std::error::Error; + + #[test] + fn decode_error() { + let _ = format!("{:?}", DecodeError::InvalidPadding.clone()); + let _ = format!( + "{} {} {} {}", + DecodeError::InvalidByte(0, 0), + DecodeError::InvalidLength(0), + DecodeError::InvalidLastSymbol(0, 0), + DecodeError::InvalidPadding, + ); + } + + #[test] + fn decode_slice_error() { + let _ = format!("{:?}", DecodeSliceError::OutputSliceTooSmall.clone()); + let _ = format!( + "{} {}", + DecodeSliceError::OutputSliceTooSmall, + DecodeSliceError::DecodeError(DecodeError::InvalidPadding) + ); + let _ = DecodeSliceError::OutputSliceTooSmall.source(); + let _ = DecodeSliceError::DecodeError(DecodeError::InvalidPadding).source(); + } + + #[test] + fn deprecated_fns() { + let _ = decode(""); + let _ = decode_engine("", &crate::prelude::BASE64_STANDARD); + let _ = decode_engine_vec("", &mut Vec::new(), &crate::prelude::BASE64_STANDARD); + let _ = decode_engine_slice("", &mut [], &crate::prelude::BASE64_STANDARD); + } + + #[test] + fn decoded_len_est() { + assert_eq!(3, decoded_len_estimate(4)); + } +} diff --git a/vendor/base64/src/encode.rs b/vendor/base64/src/encode.rs index 88e64992..ae6d7907 100644 --- a/vendor/base64/src/encode.rs +++ b/vendor/base64/src/encode.rs @@ -98,7 +98,8 @@ pub const fn encoded_len(bytes_len: usize, padding: bool) -> Option { let rem = bytes_len % 3; let complete_input_chunks = bytes_len / 3; - // `let Some(_) = _ else` requires 1.65.0, whereas this messier one works on 1.48 + // `?` is disallowed in const, and `let Some(_) = _ else` requires 1.65.0, whereas this + // messier syntax works on 1.48 let complete_chunk_output = if let Some(complete_chunk_output) = complete_input_chunks.checked_mul(4) { complete_chunk_output diff --git a/vendor/base64/src/engine/general_purpose/decode.rs b/vendor/base64/src/engine/general_purpose/decode.rs index 21a386fd..b55d3fc5 100644 --- a/vendor/base64/src/engine/general_purpose/decode.rs +++ b/vendor/base64/src/engine/general_purpose/decode.rs @@ -1,47 +1,28 @@ use crate::{ engine::{general_purpose::INVALID_VALUE, DecodeEstimate, DecodeMetadata, DecodePaddingMode}, - DecodeError, PAD_BYTE, + DecodeError, DecodeSliceError, PAD_BYTE, }; -// decode logic operates on chunks of 8 input bytes without padding -const INPUT_CHUNK_LEN: usize = 8; -const DECODED_CHUNK_LEN: usize = 6; - -// we read a u64 and write a u64, but a u64 of input only yields 6 bytes of output, so the last -// 2 bytes of any output u64 should not be counted as written to (but must be available in a -// slice). -const DECODED_CHUNK_SUFFIX: usize = 2; - -// how many u64's of input to handle at a time -const CHUNKS_PER_FAST_LOOP_BLOCK: usize = 4; - -const INPUT_BLOCK_LEN: usize = CHUNKS_PER_FAST_LOOP_BLOCK * INPUT_CHUNK_LEN; - -// includes the trailing 2 bytes for the final u64 write -const DECODED_BLOCK_LEN: usize = - CHUNKS_PER_FAST_LOOP_BLOCK * DECODED_CHUNK_LEN + DECODED_CHUNK_SUFFIX; - #[doc(hidden)] pub struct GeneralPurposeEstimate { - /// Total number of decode chunks, including a possibly partial last chunk - num_chunks: usize, - decoded_len_estimate: usize, + /// input len % 4 + rem: usize, + conservative_decoded_len: usize, } impl GeneralPurposeEstimate { pub(crate) fn new(encoded_len: usize) -> Self { - // Formulas that won't overflow + let rem = encoded_len % 4; Self { - num_chunks: encoded_len / INPUT_CHUNK_LEN - + (encoded_len % INPUT_CHUNK_LEN > 0) as usize, - decoded_len_estimate: (encoded_len / 4 + (encoded_len % 4 > 0) as usize) * 3, + rem, + conservative_decoded_len: (encoded_len / 4 + (rem > 0) as usize) * 3, } } } impl DecodeEstimate for GeneralPurposeEstimate { fn decoded_len_estimate(&self) -> usize { - self.decoded_len_estimate + self.conservative_decoded_len } } @@ -58,263 +39,262 @@ pub(crate) fn decode_helper( decode_table: &[u8; 256], decode_allow_trailing_bits: bool, padding_mode: DecodePaddingMode, -) -> Result { - let remainder_len = input.len() % INPUT_CHUNK_LEN; - - // Because the fast decode loop writes in groups of 8 bytes (unrolled to - // CHUNKS_PER_FAST_LOOP_BLOCK times 8 bytes, where possible) and outputs 8 bytes at a time (of - // which only 6 are valid data), we need to be sure that we stop using the fast decode loop - // soon enough that there will always be 2 more bytes of valid data written after that loop. - let trailing_bytes_to_skip = match remainder_len { - // if input is a multiple of the chunk size, ignore the last chunk as it may have padding, - // and the fast decode logic cannot handle padding - 0 => INPUT_CHUNK_LEN, - // 1 and 5 trailing bytes are illegal: can't decode 6 bits of input into a byte - 1 | 5 => { - // trailing whitespace is so common that it's worth it to check the last byte to - // possibly return a better error message - if let Some(b) = input.last() { - if *b != PAD_BYTE && decode_table[*b as usize] == INVALID_VALUE { - return Err(DecodeError::InvalidByte(input.len() - 1, *b)); - } - } +) -> Result { + let input_complete_nonterminal_quads_len = + complete_quads_len(input, estimate.rem, output.len(), decode_table)?; - return Err(DecodeError::InvalidLength); - } - // This will decode to one output byte, which isn't enough to overwrite the 2 extra bytes - // written by the fast decode loop. So, we have to ignore both these 2 bytes and the - // previous chunk. - 2 => INPUT_CHUNK_LEN + 2, - // If this is 3 un-padded chars, then it would actually decode to 2 bytes. However, if this - // is an erroneous 2 chars + 1 pad char that would decode to 1 byte, then it should fail - // with an error, not panic from going past the bounds of the output slice, so we let it - // use stage 3 + 4. - 3 => INPUT_CHUNK_LEN + 3, - // This can also decode to one output byte because it may be 2 input chars + 2 padding - // chars, which would decode to 1 byte. - 4 => INPUT_CHUNK_LEN + 4, - // Everything else is a legal decode len (given that we don't require padding), and will - // decode to at least 2 bytes of output. - _ => remainder_len, - }; + const UNROLLED_INPUT_CHUNK_SIZE: usize = 32; + const UNROLLED_OUTPUT_CHUNK_SIZE: usize = UNROLLED_INPUT_CHUNK_SIZE / 4 * 3; - // rounded up to include partial chunks - let mut remaining_chunks = estimate.num_chunks; + let input_complete_quads_after_unrolled_chunks_len = + input_complete_nonterminal_quads_len % UNROLLED_INPUT_CHUNK_SIZE; - let mut input_index = 0; - let mut output_index = 0; + let input_unrolled_loop_len = + input_complete_nonterminal_quads_len - input_complete_quads_after_unrolled_chunks_len; + // chunks of 32 bytes + for (chunk_index, chunk) in input[..input_unrolled_loop_len] + .chunks_exact(UNROLLED_INPUT_CHUNK_SIZE) + .enumerate() { - let length_of_fast_decode_chunks = input.len().saturating_sub(trailing_bytes_to_skip); - - // Fast loop, stage 1 - // manual unroll to CHUNKS_PER_FAST_LOOP_BLOCK of u64s to amortize slice bounds checks - if let Some(max_start_index) = length_of_fast_decode_chunks.checked_sub(INPUT_BLOCK_LEN) { - while input_index <= max_start_index { - let input_slice = &input[input_index..(input_index + INPUT_BLOCK_LEN)]; - let output_slice = &mut output[output_index..(output_index + DECODED_BLOCK_LEN)]; - - decode_chunk( - &input_slice[0..], - input_index, - decode_table, - &mut output_slice[0..], - )?; - decode_chunk( - &input_slice[8..], - input_index + 8, - decode_table, - &mut output_slice[6..], - )?; - decode_chunk( - &input_slice[16..], - input_index + 16, - decode_table, - &mut output_slice[12..], - )?; - decode_chunk( - &input_slice[24..], - input_index + 24, - decode_table, - &mut output_slice[18..], - )?; - - input_index += INPUT_BLOCK_LEN; - output_index += DECODED_BLOCK_LEN - DECODED_CHUNK_SUFFIX; - remaining_chunks -= CHUNKS_PER_FAST_LOOP_BLOCK; - } - } - - // Fast loop, stage 2 (aka still pretty fast loop) - // 8 bytes at a time for whatever we didn't do in stage 1. - if let Some(max_start_index) = length_of_fast_decode_chunks.checked_sub(INPUT_CHUNK_LEN) { - while input_index < max_start_index { - decode_chunk( - &input[input_index..(input_index + INPUT_CHUNK_LEN)], - input_index, - decode_table, - &mut output - [output_index..(output_index + DECODED_CHUNK_LEN + DECODED_CHUNK_SUFFIX)], - )?; - - output_index += DECODED_CHUNK_LEN; - input_index += INPUT_CHUNK_LEN; - remaining_chunks -= 1; - } - } - } + let input_index = chunk_index * UNROLLED_INPUT_CHUNK_SIZE; + let chunk_output = &mut output[chunk_index * UNROLLED_OUTPUT_CHUNK_SIZE + ..(chunk_index + 1) * UNROLLED_OUTPUT_CHUNK_SIZE]; - // Stage 3 - // If input length was such that a chunk had to be deferred until after the fast loop - // because decoding it would have produced 2 trailing bytes that wouldn't then be - // overwritten, we decode that chunk here. This way is slower but doesn't write the 2 - // trailing bytes. - // However, we still need to avoid the last chunk (partial or complete) because it could - // have padding, so we always do 1 fewer to avoid the last chunk. - for _ in 1..remaining_chunks { - decode_chunk_precise( - &input[input_index..], + decode_chunk_8( + &chunk[0..8], input_index, decode_table, - &mut output[output_index..(output_index + DECODED_CHUNK_LEN)], + &mut chunk_output[0..6], + )?; + decode_chunk_8( + &chunk[8..16], + input_index + 8, + decode_table, + &mut chunk_output[6..12], + )?; + decode_chunk_8( + &chunk[16..24], + input_index + 16, + decode_table, + &mut chunk_output[12..18], + )?; + decode_chunk_8( + &chunk[24..32], + input_index + 24, + decode_table, + &mut chunk_output[18..24], )?; - - input_index += INPUT_CHUNK_LEN; - output_index += DECODED_CHUNK_LEN; } - // always have one more (possibly partial) block of 8 input - debug_assert!(input.len() - input_index > 1 || input.is_empty()); - debug_assert!(input.len() - input_index <= 8); + // remaining quads, except for the last possibly partial one, as it may have padding + let output_unrolled_loop_len = input_unrolled_loop_len / 4 * 3; + let output_complete_quad_len = input_complete_nonterminal_quads_len / 4 * 3; + { + let output_after_unroll = &mut output[output_unrolled_loop_len..output_complete_quad_len]; + + for (chunk_index, chunk) in input + [input_unrolled_loop_len..input_complete_nonterminal_quads_len] + .chunks_exact(4) + .enumerate() + { + let chunk_output = &mut output_after_unroll[chunk_index * 3..chunk_index * 3 + 3]; + + decode_chunk_4( + chunk, + input_unrolled_loop_len + chunk_index * 4, + decode_table, + chunk_output, + )?; + } + } super::decode_suffix::decode_suffix( input, - input_index, + input_complete_nonterminal_quads_len, output, - output_index, + output_complete_quad_len, decode_table, decode_allow_trailing_bits, padding_mode, ) } -/// Decode 8 bytes of input into 6 bytes of output. 8 bytes of output will be written, but only the -/// first 6 of those contain meaningful data. +/// Returns the length of complete quads, except for the last one, even if it is complete. +/// +/// Returns an error if the output len is not big enough for decoding those complete quads, or if +/// the input % 4 == 1, and that last byte is an invalid value other than a pad byte. +/// +/// - `input` is the base64 input +/// - `input_len_rem` is input len % 4 +/// - `output_len` is the length of the output slice +pub(crate) fn complete_quads_len( + input: &[u8], + input_len_rem: usize, + output_len: usize, + decode_table: &[u8; 256], +) -> Result { + debug_assert!(input.len() % 4 == input_len_rem); + + // detect a trailing invalid byte, like a newline, as a user convenience + if input_len_rem == 1 { + let last_byte = input[input.len() - 1]; + // exclude pad bytes; might be part of padding that extends from earlier in the input + if last_byte != PAD_BYTE && decode_table[usize::from(last_byte)] == INVALID_VALUE { + return Err(DecodeError::InvalidByte(input.len() - 1, last_byte).into()); + } + }; + + // skip last quad, even if it's complete, as it may have padding + let input_complete_nonterminal_quads_len = input + .len() + .saturating_sub(input_len_rem) + // if rem was 0, subtract 4 to avoid padding + .saturating_sub((input_len_rem == 0) as usize * 4); + debug_assert!( + input.is_empty() || (1..=4).contains(&(input.len() - input_complete_nonterminal_quads_len)) + ); + + // check that everything except the last quad handled by decode_suffix will fit + if output_len < input_complete_nonterminal_quads_len / 4 * 3 { + return Err(DecodeSliceError::OutputSliceTooSmall); + }; + Ok(input_complete_nonterminal_quads_len) +} + +/// Decode 8 bytes of input into 6 bytes of output. /// -/// `input` is the bytes to decode, of which the first 8 bytes will be processed. +/// `input` is the 8 bytes to decode. /// `index_at_start_of_input` is the offset in the overall input (used for reporting errors /// accurately) /// `decode_table` is the lookup table for the particular base64 alphabet. -/// `output` will have its first 8 bytes overwritten, of which only the first 6 are valid decoded -/// data. +/// `output` will have its first 6 bytes overwritten // yes, really inline (worth 30-50% speedup) #[inline(always)] -fn decode_chunk( +fn decode_chunk_8( input: &[u8], index_at_start_of_input: usize, decode_table: &[u8; 256], output: &mut [u8], ) -> Result<(), DecodeError> { - let morsel = decode_table[input[0] as usize]; + let morsel = decode_table[usize::from(input[0])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte(index_at_start_of_input, input[0])); } - let mut accum = (morsel as u64) << 58; + let mut accum = u64::from(morsel) << 58; - let morsel = decode_table[input[1] as usize]; + let morsel = decode_table[usize::from(input[1])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 1, input[1], )); } - accum |= (morsel as u64) << 52; + accum |= u64::from(morsel) << 52; - let morsel = decode_table[input[2] as usize]; + let morsel = decode_table[usize::from(input[2])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 2, input[2], )); } - accum |= (morsel as u64) << 46; + accum |= u64::from(morsel) << 46; - let morsel = decode_table[input[3] as usize]; + let morsel = decode_table[usize::from(input[3])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 3, input[3], )); } - accum |= (morsel as u64) << 40; + accum |= u64::from(morsel) << 40; - let morsel = decode_table[input[4] as usize]; + let morsel = decode_table[usize::from(input[4])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 4, input[4], )); } - accum |= (morsel as u64) << 34; + accum |= u64::from(morsel) << 34; - let morsel = decode_table[input[5] as usize]; + let morsel = decode_table[usize::from(input[5])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 5, input[5], )); } - accum |= (morsel as u64) << 28; + accum |= u64::from(morsel) << 28; - let morsel = decode_table[input[6] as usize]; + let morsel = decode_table[usize::from(input[6])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 6, input[6], )); } - accum |= (morsel as u64) << 22; + accum |= u64::from(morsel) << 22; - let morsel = decode_table[input[7] as usize]; + let morsel = decode_table[usize::from(input[7])]; if morsel == INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 7, input[7], )); } - accum |= (morsel as u64) << 16; + accum |= u64::from(morsel) << 16; - write_u64(output, accum); + output[..6].copy_from_slice(&accum.to_be_bytes()[..6]); Ok(()) } -/// Decode an 8-byte chunk, but only write the 6 bytes actually decoded instead of including 2 -/// trailing garbage bytes. -#[inline] -fn decode_chunk_precise( +/// Like [decode_chunk_8] but for 4 bytes of input and 3 bytes of output. +#[inline(always)] +fn decode_chunk_4( input: &[u8], index_at_start_of_input: usize, decode_table: &[u8; 256], output: &mut [u8], ) -> Result<(), DecodeError> { - let mut tmp_buf = [0_u8; 8]; + let morsel = decode_table[usize::from(input[0])]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte(index_at_start_of_input, input[0])); + } + let mut accum = u32::from(morsel) << 26; - decode_chunk( - input, - index_at_start_of_input, - decode_table, - &mut tmp_buf[..], - )?; + let morsel = decode_table[usize::from(input[1])]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 1, + input[1], + )); + } + accum |= u32::from(morsel) << 20; + + let morsel = decode_table[usize::from(input[2])]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 2, + input[2], + )); + } + accum |= u32::from(morsel) << 14; - output[0..6].copy_from_slice(&tmp_buf[0..6]); + let morsel = decode_table[usize::from(input[3])]; + if morsel == INVALID_VALUE { + return Err(DecodeError::InvalidByte( + index_at_start_of_input + 3, + input[3], + )); + } + accum |= u32::from(morsel) << 8; - Ok(()) -} + output[..3].copy_from_slice(&accum.to_be_bytes()[..3]); -#[inline] -fn write_u64(output: &mut [u8], value: u64) { - output[..8].copy_from_slice(&value.to_be_bytes()); + Ok(()) } #[cfg(test)] @@ -324,37 +304,36 @@ mod tests { use crate::engine::general_purpose::STANDARD; #[test] - fn decode_chunk_precise_writes_only_6_bytes() { + fn decode_chunk_8_writes_only_6_bytes() { let input = b"Zm9vYmFy"; // "foobar" let mut output = [0_u8, 1, 2, 3, 4, 5, 6, 7]; - decode_chunk_precise(&input[..], 0, &STANDARD.decode_table, &mut output).unwrap(); + decode_chunk_8(&input[..], 0, &STANDARD.decode_table, &mut output).unwrap(); assert_eq!(&vec![b'f', b'o', b'o', b'b', b'a', b'r', 6, 7], &output); } #[test] - fn decode_chunk_writes_8_bytes() { - let input = b"Zm9vYmFy"; // "foobar" - let mut output = [0_u8, 1, 2, 3, 4, 5, 6, 7]; + fn decode_chunk_4_writes_only_3_bytes() { + let input = b"Zm9v"; // "foobar" + let mut output = [0_u8, 1, 2, 3]; - decode_chunk(&input[..], 0, &STANDARD.decode_table, &mut output).unwrap(); - assert_eq!(&vec![b'f', b'o', b'o', b'b', b'a', b'r', 0, 0], &output); + decode_chunk_4(&input[..], 0, &STANDARD.decode_table, &mut output).unwrap(); + assert_eq!(&vec![b'f', b'o', b'o', 3], &output); } #[test] fn estimate_short_lengths() { - for (range, (num_chunks, decoded_len_estimate)) in [ - (0..=0, (0, 0)), - (1..=4, (1, 3)), - (5..=8, (1, 6)), - (9..=12, (2, 9)), - (13..=16, (2, 12)), - (17..=20, (3, 15)), + for (range, decoded_len_estimate) in [ + (0..=0, 0), + (1..=4, 3), + (5..=8, 6), + (9..=12, 9), + (13..=16, 12), + (17..=20, 15), ] { for encoded_len in range { let estimate = GeneralPurposeEstimate::new(encoded_len); - assert_eq!(num_chunks, estimate.num_chunks); - assert_eq!(decoded_len_estimate, estimate.decoded_len_estimate); + assert_eq!(decoded_len_estimate, estimate.decoded_len_estimate()); } } } @@ -370,13 +349,8 @@ mod tests { let estimate = GeneralPurposeEstimate::new(encoded_len); assert_eq!( - ((len_128 + (INPUT_CHUNK_LEN - 1) as u128) / (INPUT_CHUNK_LEN as u128)) - as usize, - estimate.num_chunks - ); - assert_eq!( - ((len_128 + 3) / 4 * 3) as usize, - estimate.decoded_len_estimate + (len_128 + 3) / 4 * 3, + estimate.conservative_decoded_len as u128 ); }) } diff --git a/vendor/base64/src/engine/general_purpose/decode_suffix.rs b/vendor/base64/src/engine/general_purpose/decode_suffix.rs index e1e005d2..02aaf514 100644 --- a/vendor/base64/src/engine/general_purpose/decode_suffix.rs +++ b/vendor/base64/src/engine/general_purpose/decode_suffix.rs @@ -1,9 +1,9 @@ use crate::{ engine::{general_purpose::INVALID_VALUE, DecodeMetadata, DecodePaddingMode}, - DecodeError, PAD_BYTE, + DecodeError, DecodeSliceError, PAD_BYTE, }; -/// Decode the last 1-8 bytes, checking for trailing set bits and padding per the provided +/// Decode the last 0-4 bytes, checking for trailing set bits and padding per the provided /// parameters. /// /// Returns the decode metadata representing the total number of bytes decoded, including the ones @@ -16,17 +16,19 @@ pub(crate) fn decode_suffix( decode_table: &[u8; 256], decode_allow_trailing_bits: bool, padding_mode: DecodePaddingMode, -) -> Result { - // Decode any leftovers that aren't a complete input block of 8 bytes. - // Use a u64 as a stack-resident 8 byte buffer. - let mut leftover_bits: u64 = 0; +) -> Result { + debug_assert!((input.len() - input_index) <= 4); + + // Decode any leftovers that might not be a complete input chunk of 4 bytes. + // Use a u32 as a stack-resident 4 byte buffer. let mut morsels_in_leftover = 0; - let mut padding_bytes = 0; - let mut first_padding_index: usize = 0; + let mut padding_bytes_count = 0; + // offset from input_index + let mut first_padding_offset: usize = 0; let mut last_symbol = 0_u8; - let start_of_leftovers = input_index; + let mut morsels = [0_u8; 4]; - for (i, &b) in input[start_of_leftovers..].iter().enumerate() { + for (leftover_index, &b) in input[input_index..].iter().enumerate() { // '=' padding if b == PAD_BYTE { // There can be bad padding bytes in a few ways: @@ -41,30 +43,22 @@ pub(crate) fn decode_suffix( // Per config, non-canonical but still functional non- or partially-padded base64 // may be treated as an error condition. - if i % 4 < 2 { - // Check for case #2. - let bad_padding_index = start_of_leftovers - + if padding_bytes > 0 { - // If we've already seen padding, report the first padding index. - // This is to be consistent with the normal decode logic: it will report an - // error on the first padding character (since it doesn't expect to see - // anything but actual encoded data). - // This could only happen if the padding started in the previous quad since - // otherwise this case would have been hit at i % 4 == 0 if it was the same - // quad. - first_padding_index - } else { - // haven't seen padding before, just use where we are now - i - }; - return Err(DecodeError::InvalidByte(bad_padding_index, b)); + if leftover_index < 2 { + // Check for error #2. + // Either the previous byte was padding, in which case we would have already hit + // this case, or it wasn't, in which case this is the first such error. + debug_assert!( + leftover_index == 0 || (leftover_index == 1 && padding_bytes_count == 0) + ); + let bad_padding_index = input_index + leftover_index; + return Err(DecodeError::InvalidByte(bad_padding_index, b).into()); } - if padding_bytes == 0 { - first_padding_index = i; + if padding_bytes_count == 0 { + first_padding_offset = leftover_index; } - padding_bytes += 1; + padding_bytes_count += 1; continue; } @@ -72,39 +66,44 @@ pub(crate) fn decode_suffix( // To make '=' handling consistent with the main loop, don't allow // non-suffix '=' in trailing chunk either. Report error as first // erroneous padding. - if padding_bytes > 0 { - return Err(DecodeError::InvalidByte( - start_of_leftovers + first_padding_index, - PAD_BYTE, - )); + if padding_bytes_count > 0 { + return Err( + DecodeError::InvalidByte(input_index + first_padding_offset, PAD_BYTE).into(), + ); } last_symbol = b; // can use up to 8 * 6 = 48 bits of the u64, if last chunk has no padding. // Pack the leftovers from left to right. - let shift = 64 - (morsels_in_leftover + 1) * 6; let morsel = decode_table[b as usize]; if morsel == INVALID_VALUE { - return Err(DecodeError::InvalidByte(start_of_leftovers + i, b)); + return Err(DecodeError::InvalidByte(input_index + leftover_index, b).into()); } - leftover_bits |= (morsel as u64) << shift; + morsels[morsels_in_leftover] = morsel; morsels_in_leftover += 1; } + // If there was 1 trailing byte, and it was valid, and we got to this point without hitting + // an invalid byte, now we can report invalid length + if !input.is_empty() && morsels_in_leftover < 2 { + return Err(DecodeError::InvalidLength(input_index + morsels_in_leftover).into()); + } + match padding_mode { DecodePaddingMode::Indifferent => { /* everything we care about was already checked */ } DecodePaddingMode::RequireCanonical => { - if (padding_bytes + morsels_in_leftover) % 4 != 0 { - return Err(DecodeError::InvalidPadding); + // allow empty input + if (padding_bytes_count + morsels_in_leftover) % 4 != 0 { + return Err(DecodeError::InvalidPadding.into()); } } DecodePaddingMode::RequireNone => { - if padding_bytes > 0 { + if padding_bytes_count > 0 { // check at the end to make sure we let the cases of padding that should be InvalidByte // get hit - return Err(DecodeError::InvalidPadding); + return Err(DecodeError::InvalidPadding.into()); } } } @@ -117,50 +116,45 @@ pub(crate) fn decode_suffix( // bits in the bottom 6, but would be a non-canonical encoding. So, we calculate a // mask based on how many bits are used for just the canonical encoding, and optionally // error if any other bits are set. In the example of one encoded byte -> 2 symbols, - // 2 symbols can technically encode 12 bits, but the last 4 are non canonical, and + // 2 symbols can technically encode 12 bits, but the last 4 are non-canonical, and // useless since there are no more symbols to provide the necessary 4 additional bits // to finish the second original byte. - let leftover_bits_ready_to_append = match morsels_in_leftover { - 0 => 0, - 2 => 8, - 3 => 16, - 4 => 24, - 6 => 32, - 7 => 40, - 8 => 48, - // can also be detected as case #2 bad padding above - _ => unreachable!( - "Impossible: must only have 0 to 8 input bytes in last chunk, with no invalid lengths" - ), - }; + let leftover_bytes_to_append = morsels_in_leftover * 6 / 8; + // Put the up to 6 complete bytes as the high bytes. + // Gain a couple percent speedup from nudging these ORs to use more ILP with a two-way split. + let mut leftover_num = (u32::from(morsels[0]) << 26) + | (u32::from(morsels[1]) << 20) + | (u32::from(morsels[2]) << 14) + | (u32::from(morsels[3]) << 8); // if there are bits set outside the bits we care about, last symbol encodes trailing bits that // will not be included in the output - let mask = !0 >> leftover_bits_ready_to_append; - if !decode_allow_trailing_bits && (leftover_bits & mask) != 0 { + let mask = !0_u32 >> (leftover_bytes_to_append * 8); + if !decode_allow_trailing_bits && (leftover_num & mask) != 0 { // last morsel is at `morsels_in_leftover` - 1 return Err(DecodeError::InvalidLastSymbol( - start_of_leftovers + morsels_in_leftover - 1, + input_index + morsels_in_leftover - 1, last_symbol, - )); + ) + .into()); } - // TODO benchmark simply converting to big endian bytes - let mut leftover_bits_appended_to_buf = 0; - while leftover_bits_appended_to_buf < leftover_bits_ready_to_append { - // `as` simply truncates the higher bits, which is what we want here - let selected_bits = (leftover_bits >> (56 - leftover_bits_appended_to_buf)) as u8; - output[output_index] = selected_bits; + // Strangely, this approach benchmarks better than writing bytes one at a time, + // or copy_from_slice into output. + for _ in 0..leftover_bytes_to_append { + let hi_byte = (leftover_num >> 24) as u8; + leftover_num <<= 8; + *output + .get_mut(output_index) + .ok_or(DecodeSliceError::OutputSliceTooSmall)? = hi_byte; output_index += 1; - - leftover_bits_appended_to_buf += 8; } Ok(DecodeMetadata::new( output_index, - if padding_bytes > 0 { - Some(input_index + first_padding_index) + if padding_bytes_count > 0 { + Some(input_index + first_padding_offset) } else { None }, diff --git a/vendor/base64/src/engine/general_purpose/mod.rs b/vendor/base64/src/engine/general_purpose/mod.rs index e0227f3b..6fe95809 100644 --- a/vendor/base64/src/engine/general_purpose/mod.rs +++ b/vendor/base64/src/engine/general_purpose/mod.rs @@ -3,11 +3,11 @@ use crate::{ alphabet, alphabet::Alphabet, engine::{Config, DecodeMetadata, DecodePaddingMode}, - DecodeError, + DecodeSliceError, }; use core::convert::TryInto; -mod decode; +pub(crate) mod decode; pub(crate) mod decode_suffix; pub use decode::GeneralPurposeEstimate; @@ -173,7 +173,7 @@ impl super::Engine for GeneralPurpose { input: &[u8], output: &mut [u8], estimate: Self::DecodeEstimate, - ) -> Result { + ) -> Result { decode::decode_helper( input, estimate, diff --git a/vendor/base64/src/engine/mod.rs b/vendor/base64/src/engine/mod.rs index 16c05d75..f2cc33f6 100644 --- a/vendor/base64/src/engine/mod.rs +++ b/vendor/base64/src/engine/mod.rs @@ -83,17 +83,13 @@ pub trait Engine: Send + Sync { /// /// Non-canonical trailing bits in the final tokens or non-canonical padding must be reported as /// errors unless the engine is configured otherwise. - /// - /// # Panics - /// - /// Panics if `output` is too small. #[doc(hidden)] fn internal_decode( &self, input: &[u8], output: &mut [u8], decode_estimate: Self::DecodeEstimate, - ) -> Result; + ) -> Result; /// Returns the config for this engine. fn config(&self) -> &Self::Config; @@ -113,6 +109,7 @@ pub trait Engine: Send + Sync { /// engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD); /// /// let b64_url = CUSTOM_ENGINE.encode(b"hello internet~"); + /// ``` #[cfg(any(feature = "alloc", test))] #[inline] fn encode>(&self, input: T) -> String { @@ -253,7 +250,13 @@ pub trait Engine: Send + Sync { let mut buffer = vec![0; estimate.decoded_len_estimate()]; let bytes_written = engine - .internal_decode(input_bytes, &mut buffer, estimate)? + .internal_decode(input_bytes, &mut buffer, estimate) + .map_err(|e| match e { + DecodeSliceError::DecodeError(e) => e, + DecodeSliceError::OutputSliceTooSmall => { + unreachable!("Vec is sized conservatively") + } + })? .decoded_len; buffer.truncate(bytes_written); @@ -318,7 +321,13 @@ pub trait Engine: Send + Sync { let buffer_slice = &mut buffer.as_mut_slice()[starting_output_len..]; let bytes_written = engine - .internal_decode(input_bytes, buffer_slice, estimate)? + .internal_decode(input_bytes, buffer_slice, estimate) + .map_err(|e| match e { + DecodeSliceError::DecodeError(e) => e, + DecodeSliceError::OutputSliceTooSmall => { + unreachable!("Vec is sized conservatively") + } + })? .decoded_len; buffer.truncate(starting_output_len + bytes_written); @@ -354,15 +363,12 @@ pub trait Engine: Send + Sync { where E: Engine + ?Sized, { - let estimate = engine.internal_decoded_len_estimate(input_bytes.len()); - - if output.len() < estimate.decoded_len_estimate() { - return Err(DecodeSliceError::OutputSliceTooSmall); - } - engine - .internal_decode(input_bytes, output, estimate) - .map_err(|e| e.into()) + .internal_decode( + input_bytes, + output, + engine.internal_decoded_len_estimate(input_bytes.len()), + ) .map(|dm| dm.decoded_len) } @@ -400,6 +406,12 @@ pub trait Engine: Send + Sync { engine.internal_decoded_len_estimate(input_bytes.len()), ) .map(|dm| dm.decoded_len) + .map_err(|e| match e { + DecodeSliceError::DecodeError(e) => e, + DecodeSliceError::OutputSliceTooSmall => { + panic!("Output slice is too small") + } + }) } inner(self, input.as_ref(), output) diff --git a/vendor/base64/src/engine/naive.rs b/vendor/base64/src/engine/naive.rs index 6a50cbed..af509bfa 100644 --- a/vendor/base64/src/engine/naive.rs +++ b/vendor/base64/src/engine/naive.rs @@ -4,7 +4,7 @@ use crate::{ general_purpose::{self, decode_table, encode_table}, Config, DecodeEstimate, DecodeMetadata, DecodePaddingMode, Engine, }, - DecodeError, PAD_BYTE, + DecodeError, DecodeSliceError, }; use std::ops::{BitAnd, BitOr, Shl, Shr}; @@ -111,63 +111,40 @@ impl Engine for Naive { input: &[u8], output: &mut [u8], estimate: Self::DecodeEstimate, - ) -> Result { - if estimate.rem == 1 { - // trailing whitespace is so common that it's worth it to check the last byte to - // possibly return a better error message - if let Some(b) = input.last() { - if *b != PAD_BYTE - && self.decode_table[*b as usize] == general_purpose::INVALID_VALUE - { - return Err(DecodeError::InvalidByte(input.len() - 1, *b)); - } - } - - return Err(DecodeError::InvalidLength); - } + ) -> Result { + let complete_nonterminal_quads_len = general_purpose::decode::complete_quads_len( + input, + estimate.rem, + output.len(), + &self.decode_table, + )?; - let mut input_index = 0_usize; - let mut output_index = 0_usize; const BOTTOM_BYTE: u32 = 0xFF; - // can only use the main loop on non-trailing chunks - if input.len() > Self::DECODE_INPUT_CHUNK_SIZE { - // skip the last chunk, whether it's partial or full, since it might - // have padding, and start at the beginning of the chunk before that - let last_complete_chunk_start_index = estimate.complete_chunk_len - - if estimate.rem == 0 { - // Trailing chunk is also full chunk, so there must be at least 2 chunks, and - // this won't underflow - Self::DECODE_INPUT_CHUNK_SIZE * 2 - } else { - // Trailing chunk is partial, so it's already excluded in - // complete_chunk_len - Self::DECODE_INPUT_CHUNK_SIZE - }; - - while input_index <= last_complete_chunk_start_index { - let chunk = &input[input_index..input_index + Self::DECODE_INPUT_CHUNK_SIZE]; - let decoded_int: u32 = self.decode_byte_into_u32(input_index, chunk[0])?.shl(18) - | self - .decode_byte_into_u32(input_index + 1, chunk[1])? - .shl(12) - | self.decode_byte_into_u32(input_index + 2, chunk[2])?.shl(6) - | self.decode_byte_into_u32(input_index + 3, chunk[3])?; - - output[output_index] = decoded_int.shr(16_u8).bitand(BOTTOM_BYTE) as u8; - output[output_index + 1] = decoded_int.shr(8_u8).bitand(BOTTOM_BYTE) as u8; - output[output_index + 2] = decoded_int.bitand(BOTTOM_BYTE) as u8; - - input_index += Self::DECODE_INPUT_CHUNK_SIZE; - output_index += 3; - } + for (chunk_index, chunk) in input[..complete_nonterminal_quads_len] + .chunks_exact(4) + .enumerate() + { + let input_index = chunk_index * 4; + let output_index = chunk_index * 3; + + let decoded_int: u32 = self.decode_byte_into_u32(input_index, chunk[0])?.shl(18) + | self + .decode_byte_into_u32(input_index + 1, chunk[1])? + .shl(12) + | self.decode_byte_into_u32(input_index + 2, chunk[2])?.shl(6) + | self.decode_byte_into_u32(input_index + 3, chunk[3])?; + + output[output_index] = decoded_int.shr(16_u8).bitand(BOTTOM_BYTE) as u8; + output[output_index + 1] = decoded_int.shr(8_u8).bitand(BOTTOM_BYTE) as u8; + output[output_index + 2] = decoded_int.bitand(BOTTOM_BYTE) as u8; } general_purpose::decode_suffix::decode_suffix( input, - input_index, + complete_nonterminal_quads_len, output, - output_index, + complete_nonterminal_quads_len / 4 * 3, &self.decode_table, self.config.decode_allow_trailing_bits, self.config.decode_padding_mode, diff --git a/vendor/base64/src/engine/tests.rs b/vendor/base64/src/engine/tests.rs index b0480055..72bbf4bb 100644 --- a/vendor/base64/src/engine/tests.rs +++ b/vendor/base64/src/engine/tests.rs @@ -19,7 +19,7 @@ use crate::{ }, read::DecoderReader, tests::{assert_encode_sanity, random_alphabet, random_config}, - DecodeError, PAD_BYTE, + DecodeError, DecodeSliceError, PAD_BYTE, }; // the case::foo syntax includes the "foo" in the generated test method names @@ -365,26 +365,49 @@ fn decode_detect_invalid_last_symbol(engine_wrapper: E) { } #[apply(all_engines)] -fn decode_detect_invalid_last_symbol_when_length_is_also_invalid( - engine_wrapper: E, -) { - let mut rng = seeded_rng(); - - // check across enough lengths that it would likely cover any implementation's various internal - // small/large input division +fn decode_detect_1_valid_symbol_in_last_quad_invalid_length(engine_wrapper: E) { for len in (0_usize..256).map(|len| len * 4 + 1) { - let engine = E::random_alphabet(&mut rng, &STANDARD); + for mode in all_pad_modes() { + let mut input = vec![b'A'; len]; - let mut input = vec![b'A'; len]; + let engine = E::standard_with_pad_mode(true, mode); - // with a valid last char, it's InvalidLength - assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&input)); - // after mangling the last char, it's InvalidByte - input[len - 1] = b'"'; - assert_eq!( - Err(DecodeError::InvalidByte(len - 1, b'"')), - engine.decode(&input) - ); + assert_eq!(Err(DecodeError::InvalidLength(len)), engine.decode(&input)); + // if we add padding, then the first pad byte in the quad is invalid because it should + // be the second symbol + for _ in 0..3 { + input.push(PAD_BYTE); + assert_eq!( + Err(DecodeError::InvalidByte(len, PAD_BYTE)), + engine.decode(&input) + ); + } + } + } +} + +#[apply(all_engines)] +fn decode_detect_1_invalid_byte_in_last_quad_invalid_byte(engine_wrapper: E) { + for prefix_len in (0_usize..256).map(|len| len * 4) { + for mode in all_pad_modes() { + let mut input = vec![b'A'; prefix_len]; + input.push(b'*'); + + let engine = E::standard_with_pad_mode(true, mode); + + assert_eq!( + Err(DecodeError::InvalidByte(prefix_len, b'*')), + engine.decode(&input) + ); + // adding padding doesn't matter + for _ in 0..3 { + input.push(PAD_BYTE); + assert_eq!( + Err(DecodeError::InvalidByte(prefix_len, b'*')), + engine.decode(&input) + ); + } + } } } @@ -471,8 +494,10 @@ fn decode_detect_invalid_last_symbol_every_possible_three_symbols(engine_wrapper: E) { /// Any amount of padding anywhere before the final non padding character = invalid byte at first /// pad byte. -/// From this, we know padding must extend to the end of the input. -// DecoderReader pseudo-engine detects InvalidLastSymbol instead of InvalidLength because it -// can end a decode on the quad that happens to contain the start of the padding -#[apply(all_engines_except_decoder_reader)] -fn decode_padding_before_final_non_padding_char_error_invalid_byte( +/// From this and [decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad_non_canonical_padding_suffix_all_modes], +/// we know padding must extend contiguously to the end of the input. +#[apply(all_engines)] +fn decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad_all_modes< + E: EngineWrapper, +>( engine_wrapper: E, ) { - let mut rng = seeded_rng(); + // Different amounts of padding, w/ offset from end for the last non-padding char. + // Only canonical padding, so Canonical mode will work. + let suffixes = &[("AA==", 2), ("AAA=", 1), ("AAAA", 0)]; - // the different amounts of proper padding, w/ offset from end for the last non-padding char - let suffixes = [("/w==", 2), ("iYu=", 1), ("zzzz", 0)]; + for mode in pad_modes_allowing_padding() { + // We don't encode, so we don't care about encode padding. + let engine = E::standard_with_pad_mode(true, mode); - let prefix_quads_range = distributions::Uniform::from(0..=256); + decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad( + engine, + suffixes.as_slice(), + ); + } +} - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); +/// See [decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad_all_modes] +#[apply(all_engines)] +fn decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad_non_canonical_padding_suffix< + E: EngineWrapper, +>( + engine_wrapper: E, +) { + // Different amounts of padding, w/ offset from end for the last non-padding char, and + // non-canonical padding. + let suffixes = [ + ("AA==", 2), + ("AA=", 1), + ("AA", 0), + ("AAA=", 1), + ("AAA", 0), + ("AAAA", 0), + ]; - for _ in 0..100_000 { - for (suffix, offset) in suffixes.iter() { - let mut s = "ABCD".repeat(prefix_quads_range.sample(&mut rng)); - s.push_str(suffix); - let mut encoded = s.into_bytes(); + // We don't encode, so we don't care about encode padding. + // Decoding is indifferent so that we don't get caught by missing padding on the last quad + let engine = E::standard_with_pad_mode(true, DecodePaddingMode::Indifferent); - // calculate a range to write padding into that leaves at least one non padding char - let last_non_padding_offset = encoded.len() - 1 - offset; + decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad( + engine, + suffixes.as_slice(), + ) +} - // don't include last non padding char as it must stay not padding - let padding_end = rng.gen_range(0..last_non_padding_offset); +fn decode_padding_before_final_non_padding_char_error_invalid_byte_at_first_pad( + engine: impl Engine, + suffixes: &[(&str, usize)], +) { + let mut rng = seeded_rng(); - // don't use more than 100 bytes of padding, but also use shorter lengths when - // padding_end is near the start of the encoded data to avoid biasing to padding - // the entire prefix on short lengths - let padding_len = rng.gen_range(1..=usize::min(100, padding_end + 1)); - let padding_start = padding_end.saturating_sub(padding_len); + let prefix_quads_range = distributions::Uniform::from(0..=256); - encoded[padding_start..=padding_end].fill(PAD_BYTE); + for _ in 0..100_000 { + for (suffix, suffix_offset) in suffixes.iter() { + let mut s = "AAAA".repeat(prefix_quads_range.sample(&mut rng)); + s.push_str(suffix); + let mut encoded = s.into_bytes(); - assert_eq!( - Err(DecodeError::InvalidByte(padding_start, PAD_BYTE)), - engine.decode(&encoded), - ); - } + // calculate a range to write padding into that leaves at least one non padding char + let last_non_padding_offset = encoded.len() - 1 - suffix_offset; + + // don't include last non padding char as it must stay not padding + let padding_end = rng.gen_range(0..last_non_padding_offset); + + // don't use more than 100 bytes of padding, but also use shorter lengths when + // padding_end is near the start of the encoded data to avoid biasing to padding + // the entire prefix on short lengths + let padding_len = rng.gen_range(1..=usize::min(100, padding_end + 1)); + let padding_start = padding_end.saturating_sub(padding_len); + + encoded[padding_start..=padding_end].fill(PAD_BYTE); + + // should still have non-padding before any final padding + assert_ne!(PAD_BYTE, encoded[last_non_padding_offset]); + assert_eq!( + Err(DecodeError::InvalidByte(padding_start, PAD_BYTE)), + engine.decode(&encoded), + "len: {}, input: {}", + encoded.len(), + String::from_utf8(encoded).unwrap() + ); } } } -/// Any amount of padding before final chunk that crosses over into final chunk with 2-4 bytes = +/// Any amount of padding before final chunk that crosses over into final chunk with 1-4 bytes = /// invalid byte at first pad byte. -/// From this and [decode_padding_starts_before_final_chunk_error_invalid_length] we know the -/// padding must start in the final chunk. -// DecoderReader pseudo-engine detects InvalidLastSymbol instead of InvalidLength because it -// can end a decode on the quad that happens to contain the start of the padding -#[apply(all_engines_except_decoder_reader)] -fn decode_padding_starts_before_final_chunk_error_invalid_byte( +/// From this we know the padding must start in the final chunk. +#[apply(all_engines)] +fn decode_padding_starts_before_final_chunk_error_invalid_byte_at_first_pad( engine_wrapper: E, ) { let mut rng = seeded_rng(); // must have at least one prefix quad let prefix_quads_range = distributions::Uniform::from(1..256); - // excluding 1 since we don't care about invalid length in this test - let suffix_pad_len_range = distributions::Uniform::from(2..=4); - for mode in all_pad_modes() { + let suffix_pad_len_range = distributions::Uniform::from(1..=4); + // don't use no-padding mode, as the reader decode might decode a block that ends with + // valid padding, which should then be referenced when encountering the later invalid byte + for mode in pad_modes_allowing_padding() { // we don't encode so we don't care about encode padding let engine = E::standard_with_pad_mode(true, mode); for _ in 0..100_000 { let suffix_len = suffix_pad_len_range.sample(&mut rng); - let mut encoded = "ABCD" + // all 0 bits so we don't hit InvalidLastSymbol with the reader decoder + let mut encoded = "AAAA" .repeat(prefix_quads_range.sample(&mut rng)) .into_bytes(); encoded.resize(encoded.len() + suffix_len, PAD_BYTE); @@ -705,40 +774,6 @@ fn decode_padding_starts_before_final_chunk_error_invalid_byte } } -/// Any amount of padding before final chunk that crosses over into final chunk with 1 byte = -/// invalid length. -/// From this we know the padding must start in the final chunk. -// DecoderReader pseudo-engine detects InvalidByte instead of InvalidLength because it starts by -// decoding only the available complete quads -#[apply(all_engines_except_decoder_reader)] -fn decode_padding_starts_before_final_chunk_error_invalid_length( - engine_wrapper: E, -) { - let mut rng = seeded_rng(); - - // must have at least one prefix quad - let prefix_quads_range = distributions::Uniform::from(1..256); - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - for _ in 0..100_000 { - let mut encoded = "ABCD" - .repeat(prefix_quads_range.sample(&mut rng)) - .into_bytes(); - encoded.resize(encoded.len() + 1, PAD_BYTE); - - // amount of padding must be long enough to extend back from suffix into previous - // quads - let padding_len = rng.gen_range(1 + 1..encoded.len()); - // no non-padding after padding in this test, so padding goes to the end - let padding_start = encoded.len() - padding_len; - encoded[padding_start..].fill(PAD_BYTE); - - assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&encoded),); - } - } -} - /// 0-1 bytes of data before any amount of padding in final chunk = invalid byte, since padding /// is not valid data (consistent with error for pad bytes in earlier chunks). /// From this we know there must be 2-3 bytes of data before padding @@ -756,29 +791,23 @@ fn decode_too_little_data_before_padding_error_invalid_byte(en let suffix_data_len = suffix_data_len_range.sample(&mut rng); let prefix_quad_len = prefix_quads_range.sample(&mut rng); - // ensure there is a suffix quad - let min_padding = usize::from(suffix_data_len == 0); - // for all possible padding lengths - for padding_len in min_padding..=(4 - suffix_data_len) { + for padding_len in 1..=(4 - suffix_data_len) { let mut encoded = "ABCD".repeat(prefix_quad_len).into_bytes(); encoded.resize(encoded.len() + suffix_data_len, b'A'); encoded.resize(encoded.len() + padding_len, PAD_BYTE); - if suffix_data_len + padding_len == 1 { - assert_eq!(Err(DecodeError::InvalidLength), engine.decode(&encoded),); - } else { - assert_eq!( - Err(DecodeError::InvalidByte( - prefix_quad_len * 4 + suffix_data_len, - PAD_BYTE, - )), - engine.decode(&encoded), - "suffix data len {} pad len {}", - suffix_data_len, - padding_len - ); - } + assert_eq!( + Err(DecodeError::InvalidByte( + prefix_quad_len * 4 + suffix_data_len, + PAD_BYTE, + )), + engine.decode(&encoded), + "input {} suffix data len {} pad len {}", + String::from_utf8(encoded).unwrap(), + suffix_data_len, + padding_len + ); } } } @@ -918,258 +947,64 @@ fn decode_pad_mode_indifferent_padding_accepts_anything(engine ); } -//this is a MAY in the rfc: https://tools.ietf.org/html/rfc4648#section-3.3 -// DecoderReader pseudo-engine finds the first padding, but doesn't report it as an error, -// because in the next decode it finds more padding, which is reported as InvalidByte, just -// with an offset at its position in the second decode, rather than being linked to the start -// of the padding that was first seen in the previous decode. -#[apply(all_engines_except_decoder_reader)] -fn decode_pad_byte_in_penultimate_quad_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - // leave room for at least one pad byte in penultimate quad - for num_valid_bytes_penultimate_quad in 0..4 { - // can't have 1 or it would be invalid length - for num_pad_bytes_in_final_quad in 2..=4 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - - // varying amounts of padding in the penultimate quad - for _ in 0..num_valid_bytes_penultimate_quad { - s.push('A'); - } - // finish penultimate quad with padding - for _ in num_valid_bytes_penultimate_quad..4 { - s.push('='); - } - // and more padding in the final quad - for _ in 0..num_pad_bytes_in_final_quad { - s.push('='); - } - - // padding should be an invalid byte before the final quad. - // Could argue that the *next* padding byte (in the next quad) is technically the first - // erroneous one, but reporting that accurately is more complex and probably nobody cares - assert_eq!( - DecodeError::InvalidByte( - num_prefix_quads * 4 + num_valid_bytes_penultimate_quad, - b'=', - ), - engine.decode(&s).unwrap_err(), - ); - } - } - } - } -} - -#[apply(all_engines)] -fn decode_bytes_after_padding_in_final_quad_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - // leave at least one byte in the quad for padding - for bytes_after_padding in 1..4 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - - // every invalid padding position with a 3-byte final quad: 1 to 3 bytes after padding - for _ in 0..(3 - bytes_after_padding) { - s.push('A'); - } - s.push('='); - for _ in 0..bytes_after_padding { - s.push('A'); - } - - // First (and only) padding byte is invalid. - assert_eq!( - DecodeError::InvalidByte( - num_prefix_quads * 4 + (3 - bytes_after_padding), - b'=' - ), - engine.decode(&s).unwrap_err() - ); - } - } - } -} - -#[apply(all_engines)] -fn decode_absurd_pad_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - s.push_str("==Y=Wx===pY=2U====="); - - // first padding byte - assert_eq!( - DecodeError::InvalidByte(num_prefix_quads * 4, b'='), - engine.decode(&s).unwrap_err() - ); - } - } -} - -// DecoderReader pseudo-engine detects InvalidByte instead of InvalidLength because it starts by -// decoding only the available complete quads -#[apply(all_engines_except_decoder_reader)] -fn decode_too_much_padding_returns_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - // add enough padding to ensure that we'll hit all decode stages at the different lengths - for pad_bytes in 1..=64 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - let padding: String = "=".repeat(pad_bytes); - s.push_str(&padding); - - if pad_bytes % 4 == 1 { - assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err()); - } else { - assert_eq!( - DecodeError::InvalidByte(num_prefix_quads * 4, b'='), - engine.decode(&s).unwrap_err() - ); - } - } - } - } -} - -// DecoderReader pseudo-engine detects InvalidByte instead of InvalidLength because it starts by -// decoding only the available complete quads -#[apply(all_engines_except_decoder_reader)] -fn decode_padding_followed_by_non_padding_returns_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - for pad_bytes in 0..=32 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - let padding: String = "=".repeat(pad_bytes); - s.push_str(&padding); - s.push('E'); - - if pad_bytes % 4 == 0 { - assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err()); - } else { - assert_eq!( - DecodeError::InvalidByte(num_prefix_quads * 4, b'='), - engine.decode(&s).unwrap_err() - ); - } - } - } - } -} - -#[apply(all_engines)] -fn decode_one_char_in_final_quad_with_padding_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - s.push_str("E="); - - assert_eq!( - DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='), - engine.decode(&s).unwrap_err() - ); - - // more padding doesn't change the error - s.push('='); - assert_eq!( - DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='), - engine.decode(&s).unwrap_err() - ); - - s.push('='); - assert_eq!( - DecodeError::InvalidByte(num_prefix_quads * 4 + 1, b'='), - engine.decode(&s).unwrap_err() - ); - } - } -} - -#[apply(all_engines)] -fn decode_too_few_symbols_in_final_quad_error(engine_wrapper: E) { - for mode in all_pad_modes() { - // we don't encode so we don't care about encode padding - let engine = E::standard_with_pad_mode(true, mode); - - for num_prefix_quads in 0..256 { - // <2 is invalid - for final_quad_symbols in 0..2 { - for padding_symbols in 0..=(4 - final_quad_symbols) { - let mut s: String = "ABCD".repeat(num_prefix_quads); - - for _ in 0..final_quad_symbols { - s.push('A'); - } - for _ in 0..padding_symbols { - s.push('='); - } - - match final_quad_symbols + padding_symbols { - 0 => continue, - 1 => { - assert_eq!(DecodeError::InvalidLength, engine.decode(&s).unwrap_err()); - } - _ => { - // error reported at first padding byte - assert_eq!( - DecodeError::InvalidByte( - num_prefix_quads * 4 + final_quad_symbols, - b'=', - ), - engine.decode(&s).unwrap_err() - ); - } - } - } - } - } - } -} - +/// 1 trailing byte that's not padding is detected as invalid byte even though there's padding +/// in the middle of the input. This is essentially mandating the eager check for 1 trailing byte +/// to catch the \n suffix case. // DecoderReader pseudo-engine can't handle DecodePaddingMode::RequireNone since it will decode // a complete quad with padding in it before encountering the stray byte that makes it an invalid // length #[apply(all_engines_except_decoder_reader)] -fn decode_invalid_trailing_bytes(engine_wrapper: E) { +fn decode_invalid_trailing_bytes_all_pad_modes_invalid_byte(engine_wrapper: E) { for mode in all_pad_modes() { do_invalid_trailing_byte(E::standard_with_pad_mode(true, mode), mode); } } #[apply(all_engines)] -fn decode_invalid_trailing_bytes_all_modes(engine_wrapper: E) { +fn decode_invalid_trailing_bytes_invalid_byte(engine_wrapper: E) { // excluding no padding mode because the DecoderWrapper pseudo-engine will fail with // InvalidPadding because it will decode the last complete quad with padding first for mode in pad_modes_allowing_padding() { do_invalid_trailing_byte(E::standard_with_pad_mode(true, mode), mode); } } +fn do_invalid_trailing_byte(engine: impl Engine, mode: DecodePaddingMode) { + for last_byte in [b'*', b'\n'] { + for num_prefix_quads in 0..256 { + let mut s: String = "ABCD".repeat(num_prefix_quads); + s.push_str("Cg=="); + let mut input = s.into_bytes(); + input.push(last_byte); + // The case of trailing newlines is common enough to warrant a test for a good error + // message. + assert_eq!( + Err(DecodeError::InvalidByte( + num_prefix_quads * 4 + 4, + last_byte + )), + engine.decode(&input), + "mode: {:?}, input: {}", + mode, + String::from_utf8(input).unwrap() + ); + } + } +} + +/// When there's 1 trailing byte, but it's padding, it's only InvalidByte if there isn't padding +/// earlier. #[apply(all_engines)] -fn decode_invalid_trailing_padding_as_invalid_length(engine_wrapper: E) { +fn decode_invalid_trailing_padding_as_invalid_byte_at_first_pad_byte( + engine_wrapper: E, +) { // excluding no padding mode because the DecoderWrapper pseudo-engine will fail with // InvalidPadding because it will decode the last complete quad with padding first for mode in pad_modes_allowing_padding() { - do_invalid_trailing_padding_as_invalid_length(E::standard_with_pad_mode(true, mode), mode); + do_invalid_trailing_padding_as_invalid_byte_at_first_padding( + E::standard_with_pad_mode(true, mode), + mode, + ); } } @@ -1177,48 +1012,36 @@ fn decode_invalid_trailing_padding_as_invalid_length(engine_wr // a complete quad with padding in it before encountering the stray byte that makes it an invalid // length #[apply(all_engines_except_decoder_reader)] -fn decode_invalid_trailing_padding_as_invalid_length_all_modes( +fn decode_invalid_trailing_padding_as_invalid_byte_at_first_byte_all_modes( engine_wrapper: E, ) { for mode in all_pad_modes() { - do_invalid_trailing_padding_as_invalid_length(E::standard_with_pad_mode(true, mode), mode); + do_invalid_trailing_padding_as_invalid_byte_at_first_padding( + E::standard_with_pad_mode(true, mode), + mode, + ); } } - -#[apply(all_engines)] -fn decode_wrong_length_error(engine_wrapper: E) { - let engine = E::standard_with_pad_mode(true, DecodePaddingMode::Indifferent); - +fn do_invalid_trailing_padding_as_invalid_byte_at_first_padding( + engine: impl Engine, + mode: DecodePaddingMode, +) { for num_prefix_quads in 0..256 { - // at least one token, otherwise it wouldn't be a final quad - for num_tokens_final_quad in 1..=4 { - for num_padding in 0..=(4 - num_tokens_final_quad) { - let mut s: String = "IIII".repeat(num_prefix_quads); - for _ in 0..num_tokens_final_quad { - s.push('g'); - } - for _ in 0..num_padding { - s.push('='); - } + for (suffix, pad_offset) in [("AA===", 2), ("AAA==", 3), ("AAAA=", 4)] { + let mut s: String = "ABCD".repeat(num_prefix_quads); + s.push_str(suffix); - let res = engine.decode(&s); - if num_tokens_final_quad >= 2 { - assert!(res.is_ok()); - } else if num_tokens_final_quad == 1 && num_padding > 0 { - // = is invalid if it's too early - assert_eq!( - Err(DecodeError::InvalidByte( - num_prefix_quads * 4 + num_tokens_final_quad, - 61 - )), - res - ); - } else if num_padding > 2 { - assert_eq!(Err(DecodeError::InvalidPadding), res); - } else { - assert_eq!(Err(DecodeError::InvalidLength), res); - } - } + assert_eq!( + // pad after `g`, not the last one + Err(DecodeError::InvalidByte( + num_prefix_quads * 4 + pad_offset, + PAD_BYTE + )), + engine.decode(&s), + "mode: {:?}, input: {}", + mode, + s + ); } } } @@ -1248,12 +1071,20 @@ fn decode_into_slice_fits_in_precisely_sized_slice(engine_wrap assert_encode_sanity(&encoded_data, engine.config().encode_padding(), input_len); decode_buf.resize(input_len, 0); - // decode into the non-empty buf let decode_bytes_written = engine .decode_slice_unchecked(encoded_data.as_bytes(), &mut decode_buf[..]) .unwrap(); + assert_eq!(orig_data.len(), decode_bytes_written); + assert_eq!(orig_data, decode_buf); + // same for checked variant + decode_buf.clear(); + decode_buf.resize(input_len, 0); + // decode into the non-empty buf + let decode_bytes_written = engine + .decode_slice(encoded_data.as_bytes(), &mut decode_buf[..]) + .unwrap(); assert_eq!(orig_data.len(), decode_bytes_written); assert_eq!(orig_data, decode_buf); } @@ -1287,7 +1118,10 @@ fn inner_decode_reports_padding_position(engine_wrapper: E) { if pad_position % 4 < 2 { // impossible padding assert_eq!( - Err(DecodeError::InvalidByte(pad_position, PAD_BYTE)), + Err(DecodeSliceError::DecodeError(DecodeError::InvalidByte( + pad_position, + PAD_BYTE + ))), decode_res ); } else { @@ -1355,35 +1189,60 @@ fn estimate_via_u128_inflation(engine_wrapper: E) { }) } -fn do_invalid_trailing_byte(engine: impl Engine, mode: DecodePaddingMode) { - for num_prefix_quads in 0..256 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - s.push_str("Cg==\n"); - - // The case of trailing newlines is common enough to warrant a test for a good error - // message. - assert_eq!( - Err(DecodeError::InvalidByte(num_prefix_quads * 4 + 4, b'\n')), - engine.decode(&s), - "mode: {:?}, input: {}", - mode, - s - ); - } -} +#[apply(all_engines)] +fn decode_slice_checked_fails_gracefully_at_all_output_lengths( + engine_wrapper: E, +) { + let mut rng = seeded_rng(); + for original_len in 0..1000 { + let mut original = vec![0; original_len]; + rng.fill(&mut original[..]); + + for mode in all_pad_modes() { + let engine = E::standard_with_pad_mode( + match mode { + DecodePaddingMode::Indifferent | DecodePaddingMode::RequireCanonical => true, + DecodePaddingMode::RequireNone => false, + }, + mode, + ); -fn do_invalid_trailing_padding_as_invalid_length(engine: impl Engine, mode: DecodePaddingMode) { - for num_prefix_quads in 0..256 { - let mut s: String = "ABCD".repeat(num_prefix_quads); - s.push_str("Cg==="); + let encoded = engine.encode(&original); + let mut decode_buf = Vec::with_capacity(original_len); + for decode_buf_len in 0..original_len { + decode_buf.resize(decode_buf_len, 0); + assert_eq!( + DecodeSliceError::OutputSliceTooSmall, + engine + .decode_slice(&encoded, &mut decode_buf[..]) + .unwrap_err(), + "original len: {}, encoded len: {}, buf len: {}, mode: {:?}", + original_len, + encoded.len(), + decode_buf_len, + mode + ); + // internal method works the same + assert_eq!( + DecodeSliceError::OutputSliceTooSmall, + engine + .internal_decode( + encoded.as_bytes(), + &mut decode_buf[..], + engine.internal_decoded_len_estimate(encoded.len()) + ) + .unwrap_err() + ); + } - assert_eq!( - Err(DecodeError::InvalidLength), - engine.decode(&s), - "mode: {:?}, input: {}", - mode, - s - ); + decode_buf.resize(original_len, 0); + rng.fill(&mut decode_buf[..]); + assert_eq!( + original_len, + engine.decode_slice(&encoded, &mut decode_buf[..]).unwrap() + ); + assert_eq!(original, decode_buf); + } } } @@ -1547,7 +1406,7 @@ impl EngineWrapper for NaiveWrapper { naive::Naive::new( &STANDARD, naive::NaiveConfig { - encode_padding: false, + encode_padding: encode_pad, decode_allow_trailing_bits: false, decode_padding_mode: decode_pad_mode, }, @@ -1616,7 +1475,7 @@ impl Engine for DecoderReaderEngine { input: &[u8], output: &mut [u8], decode_estimate: Self::DecodeEstimate, - ) -> Result { + ) -> Result { let mut reader = DecoderReader::new(input, &self.engine); let mut buf = vec![0; input.len()]; // to avoid effects like not detecting invalid length due to progressively growing @@ -1635,6 +1494,9 @@ impl Engine for DecoderReaderEngine { .and_then(|inner| inner.downcast::().ok()) .unwrap() })?; + if output.len() < buf.len() { + return Err(DecodeSliceError::OutputSliceTooSmall); + } output[..buf.len()].copy_from_slice(&buf); Ok(DecodeMetadata::new( buf.len(), diff --git a/vendor/base64/src/lib.rs b/vendor/base64/src/lib.rs index 6b11fa66..579a7225 100644 --- a/vendor/base64/src/lib.rs +++ b/vendor/base64/src/lib.rs @@ -1,100 +1,124 @@ -//! # Getting started +//! Correct, fast, and configurable [base64][] decoding and encoding. Base64 +//! transports binary data efficiently in contexts where only plain text is +//! allowed. //! -//! 1. Perhaps one of the preconfigured engines in [engine::general_purpose] will suit, e.g. -//! [engine::general_purpose::STANDARD_NO_PAD]. -//! - These are re-exported in [prelude] with a `BASE64_` prefix for those who prefer to -//! `use base64::prelude::*` or equivalent, e.g. [prelude::BASE64_STANDARD_NO_PAD] -//! 1. If not, choose which alphabet you want. Most usage will want [alphabet::STANDARD] or [alphabet::URL_SAFE]. -//! 1. Choose which [Engine] implementation you want. For the moment there is only one: [engine::GeneralPurpose]. -//! 1. Configure the engine appropriately using the engine's `Config` type. -//! - This is where you'll select whether to add padding (when encoding) or expect it (when -//! decoding). If given the choice, prefer no padding. -//! 1. Build the engine using the selected alphabet and config. +//! [base64]: https://developer.mozilla.org/en-US/docs/Glossary/Base64 //! -//! For more detail, see below. +//! # Usage //! -//! ## Alphabets +//! Use an [`Engine`] to decode or encode base64, configured with the base64 +//! alphabet and padding behavior best suited to your application. //! -//! An [alphabet::Alphabet] defines what ASCII symbols are used to encode to or decode from. +//! ## Engine setup //! -//! Constants in [alphabet] like [alphabet::STANDARD] or [alphabet::URL_SAFE] provide commonly used -//! alphabets, but you can also build your own custom [alphabet::Alphabet] if needed. +//! There is more than one way to encode a stream of bytes as “base64”. +//! Different applications use different encoding +//! [alphabets][alphabet::Alphabet] and +//! [padding behaviors][engine::general_purpose::GeneralPurposeConfig]. //! -//! ## Engines +//! ### Encoding alphabet //! -//! Once you have an `Alphabet`, you can pick which `Engine` you want. A few parts of the public -//! API provide a default, but otherwise the user must provide an `Engine` to use. +//! Almost all base64 [alphabets][alphabet::Alphabet] use `A-Z`, `a-z`, and +//! `0-9`, which gives nearly 64 characters (26 + 26 + 10 = 62), but they differ +//! in their choice of their final 2. //! -//! See [Engine] for more. +//! Most applications use the [standard][alphabet::STANDARD] alphabet specified +//! in [RFC 4648][rfc-alphabet]. If that’s all you need, you can get started +//! quickly by using the pre-configured +//! [`STANDARD`][engine::general_purpose::STANDARD] engine, which is also available +//! in the [`prelude`] module as shown here, if you prefer a minimal `use` +//! footprint. //! -//! ## Config +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::prelude::*; //! -//! In addition to an `Alphabet`, constructing an `Engine` also requires an [engine::Config]. Each -//! `Engine` has a corresponding `Config` implementation since different `Engine`s may offer different -//! levels of configurability. +//! # fn main() -> Result<(), base64::DecodeError> { +//! assert_eq!(BASE64_STANDARD.decode(b"+uwgVQA=")?, b"\xFA\xEC\x20\x55\0"); +//! assert_eq!(BASE64_STANDARD.encode(b"\xFF\xEC\x20\x55\0"), "/+wgVQA="); +//! # Ok(()) +//! # } +//! ``` //! -//! # Encoding +//! [rfc-alphabet]: https://datatracker.ietf.org/doc/html/rfc4648#section-4 //! -//! Several different encoding methods on [Engine] are available to you depending on your desire for -//! convenience vs performance. +//! Other common alphabets are available in the [`alphabet`] module. //! -//! | Method | Output | Allocates | -//! | ------------------------ | ---------------------------- | ------------------------------ | -//! | [Engine::encode] | Returns a new `String` | Always | -//! | [Engine::encode_string] | Appends to provided `String` | Only if `String` needs to grow | -//! | [Engine::encode_slice] | Writes to provided `&[u8]` | Never - fastest | +//! #### URL-safe alphabet //! -//! All of the encoding methods will pad as per the engine's config. +//! The standard alphabet uses `+` and `/` as its two non-alphanumeric tokens, +//! which cannot be safely used in URL’s without encoding them as `%2B` and +//! `%2F`. //! -//! # Decoding +//! To avoid that, some applications use a [“URL-safe” alphabet][alphabet::URL_SAFE], +//! which uses `-` and `_` instead. To use that alternative alphabet, use the +//! [`URL_SAFE`][engine::general_purpose::URL_SAFE] engine. This example doesn't +//! use [`prelude`] to show what a more explicit `use` would look like. //! -//! Just as for encoding, there are different decoding methods available. +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::{engine::general_purpose::URL_SAFE, Engine as _}; //! -//! | Method | Output | Allocates | -//! | ------------------------ | ----------------------------- | ------------------------------ | -//! | [Engine::decode] | Returns a new `Vec` | Always | -//! | [Engine::decode_vec] | Appends to provided `Vec` | Only if `Vec` needs to grow | -//! | [Engine::decode_slice] | Writes to provided `&[u8]` | Never - fastest | +//! # fn main() -> Result<(), base64::DecodeError> { +//! assert_eq!(URL_SAFE.decode(b"-uwgVQA=")?, b"\xFA\xEC\x20\x55\0"); +//! assert_eq!(URL_SAFE.encode(b"\xFF\xEC\x20\x55\0"), "_-wgVQA="); +//! # Ok(()) +//! # } +//! ``` //! -//! Unlike encoding, where all possible input is valid, decoding can fail (see [DecodeError]). +//! ### Padding characters //! -//! Input can be invalid because it has invalid characters or invalid padding. The nature of how -//! padding is checked depends on the engine's config. -//! Whitespace in the input is invalid, just like any other non-base64 byte. +//! Each base64 character represents 6 bits (2⁶ = 64) of the original binary +//! data, and every 3 bytes of input binary data will encode to 4 base64 +//! characters (8 bits × 3 = 6 bits × 4 = 24 bits). //! -//! # `Read` and `Write` +//! When the input is not an even multiple of 3 bytes in length, [canonical][] +//! base64 encoders insert padding characters at the end, so that the output +//! length is always a multiple of 4: //! -//! To decode a [std::io::Read] of b64 bytes, wrap a reader (file, network socket, etc) with -//! [read::DecoderReader]. +//! [canonical]: https://datatracker.ietf.org/doc/html/rfc4648#section-3.5 //! -//! To write raw bytes and have them b64 encoded on the fly, wrap a [std::io::Write] with -//! [write::EncoderWriter]. +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::{engine::general_purpose::STANDARD, Engine as _}; //! -//! There is some performance overhead (15% or so) because of the necessary buffer shuffling -- -//! still fast enough that almost nobody cares. Also, these implementations do not heap allocate. +//! assert_eq!(STANDARD.encode(b""), ""); +//! assert_eq!(STANDARD.encode(b"f"), "Zg=="); +//! assert_eq!(STANDARD.encode(b"fo"), "Zm8="); +//! assert_eq!(STANDARD.encode(b"foo"), "Zm9v"); +//! ``` //! -//! # `Display` +//! Canonical encoding ensures that base64 encodings will be exactly the same, +//! byte-for-byte, regardless of input length. But the `=` padding characters +//! aren’t necessary for decoding, and they may be omitted by using a +//! [`NO_PAD`][engine::general_purpose::NO_PAD] configuration: //! -//! See [display] for how to transparently base64 data via a `Display` implementation. +#![cfg_attr(feature = "alloc", doc = "```")] +#![cfg_attr(not(feature = "alloc"), doc = "```ignore")] +//! use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _}; //! -//! # Examples +//! assert_eq!(STANDARD_NO_PAD.encode(b""), ""); +//! assert_eq!(STANDARD_NO_PAD.encode(b"f"), "Zg"); +//! assert_eq!(STANDARD_NO_PAD.encode(b"fo"), "Zm8"); +//! assert_eq!(STANDARD_NO_PAD.encode(b"foo"), "Zm9v"); +//! ``` //! -//! ## Using predefined engines +//! The pre-configured `NO_PAD` engines will reject inputs containing padding +//! `=` characters. To encode without padding and still accept padding while +//! decoding, create an [engine][engine::general_purpose::GeneralPurpose] with +//! that [padding mode][engine::DecodePaddingMode]. //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] -//! use base64::{Engine as _, engine::general_purpose}; -//! -//! let orig = b"data"; -//! let encoded: String = general_purpose::STANDARD_NO_PAD.encode(orig); -//! assert_eq!("ZGF0YQ", encoded); -//! assert_eq!(orig.as_slice(), &general_purpose::STANDARD_NO_PAD.decode(encoded).unwrap()); -//! -//! // or, URL-safe -//! let encoded_url = general_purpose::URL_SAFE_NO_PAD.encode(orig); +//! # use base64::{engine::general_purpose::STANDARD_NO_PAD, Engine as _}; +//! assert_eq!(STANDARD_NO_PAD.decode(b"Zm8="), Err(base64::DecodeError::InvalidPadding)); //! ``` //! -//! ## Custom alphabet, config, and engine +//! ### Further customization +//! +//! Decoding and encoding behavior can be customized by creating an +//! [engine][engine::GeneralPurpose] with an [alphabet][alphabet::Alphabet] and +//! [padding configuration][engine::GeneralPurposeConfig]: //! #![cfg_attr(feature = "alloc", doc = "```")] #![cfg_attr(not(feature = "alloc"), doc = "```ignore")] @@ -117,6 +141,81 @@ //! //! ``` //! +//! ## Memory allocation +//! +//! The [decode][Engine::decode()] and [encode][Engine::encode()] engine methods +//! allocate memory for their results – `decode` returns a `Vec` and +//! `encode` returns a `String`. To instead decode or encode into a buffer that +//! you allocated, use one of the alternative methods: +//! +//! #### Decoding +//! +//! | Method | Output | Allocates memory | +//! | -------------------------- | ----------------------------- | ----------------------------- | +//! | [`Engine::decode`] | returns a new `Vec` | always | +//! | [`Engine::decode_vec`] | appends to provided `Vec` | if `Vec` lacks capacity | +//! | [`Engine::decode_slice`] | writes to provided `&[u8]` | never +//! +//! #### Encoding +//! +//! | Method | Output | Allocates memory | +//! | -------------------------- | ---------------------------- | ------------------------------ | +//! | [`Engine::encode`] | returns a new `String` | always | +//! | [`Engine::encode_string`] | appends to provided `String` | if `String` lacks capacity | +//! | [`Engine::encode_slice`] | writes to provided `&[u8]` | never | +//! +//! ## Input and output +//! +//! The `base64` crate can [decode][Engine::decode()] and +//! [encode][Engine::encode()] values in memory, or +//! [`DecoderReader`][read::DecoderReader] and +//! [`EncoderWriter`][write::EncoderWriter] provide streaming decoding and +//! encoding for any [readable][std::io::Read] or [writable][std::io::Write] +//! byte stream. +//! +//! #### Decoding +//! +#![cfg_attr(feature = "std", doc = "```")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] +//! # use std::io; +//! use base64::{engine::general_purpose::STANDARD, read::DecoderReader}; +//! +//! # fn main() -> Result<(), Box> { +//! let mut input = io::stdin(); +//! let mut decoder = DecoderReader::new(&mut input, &STANDARD); +//! io::copy(&mut decoder, &mut io::stdout())?; +//! # Ok(()) +//! # } +//! ``` +//! +//! #### Encoding +//! +#![cfg_attr(feature = "std", doc = "```")] +#![cfg_attr(not(feature = "std"), doc = "```ignore")] +//! # use std::io; +//! use base64::{engine::general_purpose::STANDARD, write::EncoderWriter}; +//! +//! # fn main() -> Result<(), Box> { +//! let mut output = io::stdout(); +//! let mut encoder = EncoderWriter::new(&mut output, &STANDARD); +//! io::copy(&mut io::stdin(), &mut encoder)?; +//! # Ok(()) +//! # } +//! ``` +//! +//! #### Display +//! +//! If you only need a base64 representation for implementing the +//! [`Display`][std::fmt::Display] trait, use +//! [`Base64Display`][display::Base64Display]: +//! +//! ``` +//! use base64::{display::Base64Display, engine::general_purpose::STANDARD}; +//! +//! let value = Base64Display::new(b"\0\x01\x02\x03", &STANDARD); +//! assert_eq!("base64: AAECAw==", format!("base64: {}", value)); +//! ``` +//! //! # Panics //! //! If length calculations result in overflowing `usize`, a panic will result. @@ -129,8 +228,7 @@ unused_extern_crates, unused_import_braces, unused_results, - variant_size_differences, - warnings + variant_size_differences )] #![forbid(unsafe_code)] // Allow globally until https://github.com/rust-lang/rust-clippy/issues/8768 is resolved. diff --git a/vendor/base64/src/read/decoder.rs b/vendor/base64/src/read/decoder.rs index b656ae3d..781f6f88 100644 --- a/vendor/base64/src/read/decoder.rs +++ b/vendor/base64/src/read/decoder.rs @@ -1,4 +1,4 @@ -use crate::{engine::Engine, DecodeError, PAD_BYTE}; +use crate::{engine::Engine, DecodeError, DecodeSliceError, PAD_BYTE}; use std::{cmp, fmt, io}; // This should be large, but it has to fit on the stack. @@ -35,37 +35,39 @@ pub struct DecoderReader<'e, E: Engine, R: io::Read> { /// Where b64 data is read from inner: R, - // Holds b64 data read from the delegate reader. + /// Holds b64 data read from the delegate reader. b64_buffer: [u8; BUF_SIZE], - // The start of the pending buffered data in b64_buffer. + /// The start of the pending buffered data in `b64_buffer`. b64_offset: usize, - // The amount of buffered b64 data. + /// The amount of buffered b64 data after `b64_offset` in `b64_len`. b64_len: usize, - // Since the caller may provide us with a buffer of size 1 or 2 that's too small to copy a - // decoded chunk in to, we have to be able to hang on to a few decoded bytes. - // Technically we only need to hold 2 bytes but then we'd need a separate temporary buffer to - // decode 3 bytes into and then juggle copying one byte into the provided read buf and the rest - // into here, which seems like a lot of complexity for 1 extra byte of storage. - decoded_buffer: [u8; DECODED_CHUNK_SIZE], - // index of start of decoded data + /// Since the caller may provide us with a buffer of size 1 or 2 that's too small to copy a + /// decoded chunk in to, we have to be able to hang on to a few decoded bytes. + /// Technically we only need to hold 2 bytes, but then we'd need a separate temporary buffer to + /// decode 3 bytes into and then juggle copying one byte into the provided read buf and the rest + /// into here, which seems like a lot of complexity for 1 extra byte of storage. + decoded_chunk_buffer: [u8; DECODED_CHUNK_SIZE], + /// Index of start of decoded data in `decoded_chunk_buffer` decoded_offset: usize, - // length of decoded data + /// Length of decoded data after `decoded_offset` in `decoded_chunk_buffer` decoded_len: usize, - // used to provide accurate offsets in errors - total_b64_decoded: usize, - // offset of previously seen padding, if any + /// Input length consumed so far. + /// Used to provide accurate offsets in errors + input_consumed_len: usize, + /// offset of previously seen padding, if any padding_offset: Option, } +// exclude b64_buffer as it's uselessly large impl<'e, E: Engine, R: io::Read> fmt::Debug for DecoderReader<'e, E, R> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("DecoderReader") .field("b64_offset", &self.b64_offset) .field("b64_len", &self.b64_len) - .field("decoded_buffer", &self.decoded_buffer) + .field("decoded_chunk_buffer", &self.decoded_chunk_buffer) .field("decoded_offset", &self.decoded_offset) .field("decoded_len", &self.decoded_len) - .field("total_b64_decoded", &self.total_b64_decoded) + .field("input_consumed_len", &self.input_consumed_len) .field("padding_offset", &self.padding_offset) .finish() } @@ -80,10 +82,10 @@ impl<'e, E: Engine, R: io::Read> DecoderReader<'e, E, R> { b64_buffer: [0; BUF_SIZE], b64_offset: 0, b64_len: 0, - decoded_buffer: [0; DECODED_CHUNK_SIZE], + decoded_chunk_buffer: [0; DECODED_CHUNK_SIZE], decoded_offset: 0, decoded_len: 0, - total_b64_decoded: 0, + input_consumed_len: 0, padding_offset: None, } } @@ -100,7 +102,7 @@ impl<'e, E: Engine, R: io::Read> DecoderReader<'e, E, R> { debug_assert!(copy_len <= self.decoded_len); buf[..copy_len].copy_from_slice( - &self.decoded_buffer[self.decoded_offset..self.decoded_offset + copy_len], + &self.decoded_chunk_buffer[self.decoded_offset..self.decoded_offset + copy_len], ); self.decoded_offset += copy_len; @@ -131,6 +133,10 @@ impl<'e, E: Engine, R: io::Read> DecoderReader<'e, E, R> { /// caller's responsibility to choose the number of b64 bytes to decode correctly. /// /// Returns a Result with the number of decoded bytes written to `buf`. + /// + /// # Panics + /// + /// panics if `buf` is too small fn decode_to_buf(&mut self, b64_len_to_decode: usize, buf: &mut [u8]) -> io::Result { debug_assert!(self.b64_len >= b64_len_to_decode); debug_assert!(self.b64_offset + self.b64_len <= BUF_SIZE); @@ -144,22 +150,35 @@ impl<'e, E: Engine, R: io::Read> DecoderReader<'e, E, R> { buf, self.engine.internal_decoded_len_estimate(b64_len_to_decode), ) - .map_err(|e| match e { - DecodeError::InvalidByte(offset, byte) => { - // This can be incorrect, but not in a way that probably matters to anyone: - // if there was padding handled in a previous decode, and we are now getting - // InvalidByte due to more padding, we should arguably report InvalidByte with - // PAD_BYTE at the original padding position (`self.padding_offset`), but we - // don't have a good way to tie those two cases together, so instead we - // just report the invalid byte as if the previous padding, and its possibly - // related downgrade to a now invalid byte, didn't happen. - DecodeError::InvalidByte(self.total_b64_decoded + offset, byte) + .map_err(|dse| match dse { + DecodeSliceError::DecodeError(de) => { + match de { + DecodeError::InvalidByte(offset, byte) => { + match (byte, self.padding_offset) { + // if there was padding in a previous block of decoding that happened to + // be correct, and we now find more padding that happens to be incorrect, + // to be consistent with non-reader decodes, record the error at the first + // padding + (PAD_BYTE, Some(first_pad_offset)) => { + DecodeError::InvalidByte(first_pad_offset, PAD_BYTE) + } + _ => { + DecodeError::InvalidByte(self.input_consumed_len + offset, byte) + } + } + } + DecodeError::InvalidLength(len) => { + DecodeError::InvalidLength(self.input_consumed_len + len) + } + DecodeError::InvalidLastSymbol(offset, byte) => { + DecodeError::InvalidLastSymbol(self.input_consumed_len + offset, byte) + } + DecodeError::InvalidPadding => DecodeError::InvalidPadding, + } } - DecodeError::InvalidLength => DecodeError::InvalidLength, - DecodeError::InvalidLastSymbol(offset, byte) => { - DecodeError::InvalidLastSymbol(self.total_b64_decoded + offset, byte) + DecodeSliceError::OutputSliceTooSmall => { + unreachable!("buf is sized correctly in calling code") } - DecodeError::InvalidPadding => DecodeError::InvalidPadding, }) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; @@ -176,8 +195,8 @@ impl<'e, E: Engine, R: io::Read> DecoderReader<'e, E, R> { self.padding_offset = self.padding_offset.or(decode_metadata .padding_offset - .map(|offset| self.total_b64_decoded + offset)); - self.total_b64_decoded += b64_len_to_decode; + .map(|offset| self.input_consumed_len + offset)); + self.input_consumed_len += b64_len_to_decode; self.b64_offset += b64_len_to_decode; self.b64_len -= b64_len_to_decode; @@ -283,7 +302,7 @@ impl<'e, E: Engine, R: io::Read> io::Read for DecoderReader<'e, E, R> { let to_decode = cmp::min(self.b64_len, BASE64_CHUNK_SIZE); let decoded = self.decode_to_buf(to_decode, &mut decoded_chunk[..])?; - self.decoded_buffer[..decoded].copy_from_slice(&decoded_chunk[..decoded]); + self.decoded_chunk_buffer[..decoded].copy_from_slice(&decoded_chunk[..decoded]); self.decoded_offset = 0; self.decoded_len = decoded; diff --git a/vendor/base64/src/read/decoder_tests.rs b/vendor/base64/src/read/decoder_tests.rs index 099dd638..f3431457 100644 --- a/vendor/base64/src/read/decoder_tests.rs +++ b/vendor/base64/src/read/decoder_tests.rs @@ -77,7 +77,7 @@ fn trailing_junk() { break; } Ok(0) => break, - Ok(_) => (), + Ok(_len) => (), } } diff --git a/vendor/cipher/.cargo-checksum.json b/vendor/cipher/.cargo-checksum.json new file mode 100644 index 00000000..c02f8c21 --- /dev/null +++ b/vendor/cipher/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"76b65408515ba9ab7b04742e8ac7269ea7ec18001c218ac7739a0513b6dc055f","Cargo.toml":"14da8d3fa5933ee2ccfe67432b260db0c50a732db4c1e13303abadd09af9e634","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"5c7bd92d1f096f12203dc1b601e3cb17484fa1b023e30b6b8edcc80e416237ec","README.md":"be7477bf37a82e5286846153ee87ac556550f0cea503ba42a4e8d9065f848e4d","src/block.rs":"d360a0dbedc71a1702d7ada005a4b1fc7da98aae24e099e7a41ffedcb2b6b5c0","src/dev.rs":"82e51f2d453c922ccd40f16e9e2353e7f0e4fe0db74b810a75410f375709f3d7","src/dev/block.rs":"f4a4e194907751768242e95ddb702827399d3b742848b381de62e5e859610129","src/dev/stream.rs":"8b0cfcaf037cf469ed4112e63afeb0782e3c6e09477e3065842aaec65d66041e","src/errors.rs":"d2c026ff03556c6d0a284cbd81d8ddadf5e2b6ca66d47c39ee9d4393fb96e089","src/lib.rs":"5582e304d673d1dd9ffc16e8fa3d240bb43538471341ca3c99d841ea1be0581e","src/stream.rs":"9ab2d14811de520578dc66af29db7200f3fd9b04fecfc916acf524b9da46c0a6","src/stream_core.rs":"0546f72cdf1a91e095235044047ca52eda73a7fd972a45bc287e17407094bb13","src/stream_wrapper.rs":"bcf4c76bacd006d7a0a65605f23fe43dc4d6c535a59a37103ee6e044e692f7d7"},"package":"773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"} \ No newline at end of file diff --git a/vendor/cipher/CHANGELOG.md b/vendor/cipher/CHANGELOG.md new file mode 100644 index 00000000..4a388fb3 --- /dev/null +++ b/vendor/cipher/CHANGELOG.md @@ -0,0 +1,121 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.4.4 (2022-03-09) +### Changed +- Move `ParBlocks`/`ParBlocksSizeUser` to the `crypto-common` crate ([#1052]) + +### Fixed +- Unsoundness triggered by zero block size ([#1277]) + +[#1052]: https://github.com/RustCrypto/traits/pull/1052 +[#1277]: https://github.com/RustCrypto/traits/pull/1277 + +## 0.4.3 (2022-02-22) +### Fixed +- Do not enable the `alloc` feature by default ([#953]) + +[#953]: https://github.com/RustCrypto/traits/pull/953 + +## 0.4.2 (2022-02-16) [YANKED] +### Fixed +- Rename `BlockDecryptMut::decrypt_padded_vec` to `decrypt_padded_vec_mut` for consistency with other methods ([#941]) + +[#941]: https://github.com/RustCrypto/traits/pull/941 + +## 0.4.1 (2022-02-16) [YANKED] +### Added +- Allocating padded encrypt/decrypt ([#936]) + +### Fixed +- Minimal versions build ([#940]) + +[#940]: https://github.com/RustCrypto/traits/pull/940 +[#936]: https://github.com/RustCrypto/traits/pull/936 + +## 0.4.0 (2022-02-10) +### Changed +- Major rework of traits. Core functionality of block and stream ciphers +is defined using rank-2 closures with convenience methods built on top of +it. Expose block-level trait for stream ciphers and add generic wrapper +around it. The async stream cipher trait is defined as sub-trait of +mutable block cipher traits. ([#849]) + +### Added +- Re-export `rand_core` ([#683]) + +[#683]: https://github.com/RustCrypto/traits/pull/683 +[#849]: https://github.com/RustCrypto/traits/pull/849 + +## 0.3.0 (2021-04-28) +### Added +- Encrypt/decrypt-only block cipher traits ([#352]) +- Re-export `blobby` from root ([#435]) +- Block cipher trait blanket impls for refs ([#441]) +- `generate_key` method to `New*` trait ([#513]) + +### Changed +- Consolidate error types ([#373]) +- Change `SeekNum` impls to fit with the new `BlockBuffer` ([#435]) +- Reorganize modules ([#435]) +- Renamed `new_var` to `new_from_slice(s)` ([#442]) + +[#352]: https://github.com/RustCrypto/traits/pull/352 +[#373]: https://github.com/RustCrypto/traits/pull/373 +[#435]: https://github.com/RustCrypto/traits/pull/435 +[#441]: https://github.com/RustCrypto/traits/pull/441 +[#442]: https://github.com/RustCrypto/traits/pull/442 +[#513]: https://github.com/RustCrypto/traits/pull/513 + +## 0.2.5 (2020-11-01) +### Fixed +- Nested macros used old deprecated names ([#360]) + +[#360]: https://github.com/RustCrypto/traits/pull/360 + +## 0.2.4 (2020-11-01) +### Fixed +- Macro expansion error ([#358]) + +[#358]: https://github.com/RustCrypto/traits/pull/358 + +## 0.2.3 (2020-11-01) [YANKED] +### Fixed +- Legacy macro wrappers ([#356]) + +[#356]: https://github.com/RustCrypto/traits/pull/356 + +## 0.2.2 (2020-11-01) [YANKED] +### Added +- `BlockCipher::{encrypt_slice, decrypt_slice}` methods ([#351]) + +### Changed +- Revamp macro names ([#350]) + +[#351]: https://github.com/RustCrypto/traits/pull/351 +[#350]: https://github.com/RustCrypto/traits/pull/350 + +## 0.2.1 (2020-10-16) +### Added +- Re-export `generic_array` from toplevel ([#343]) + +### Fixed +- `dev` macro imports ([#345]) + +[#343]: https://github.com/RustCrypto/traits/pull/343 +[#345]: https://github.com/RustCrypto/traits/pull/345 + +## 0.2.0 (2020-10-15) [YANKED] +### Changed +- Unify `block-cipher` and `stream-cipher` into `cipher` ([#337]) + +[#337]: https://github.com/RustCrypto/traits/pull/337 + +## 0.1.1 (2015-06-25) + +## 0.1.0 (2015-06-24) +- Initial release diff --git a/vendor/cipher/Cargo.toml b/vendor/cipher/Cargo.toml new file mode 100644 index 00000000..d345a123 --- /dev/null +++ b/vendor/cipher/Cargo.toml @@ -0,0 +1,65 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "cipher" +version = "0.4.4" +authors = ["RustCrypto Developers"] +description = "Traits for describing block ciphers and stream ciphers" +documentation = "https://docs.rs/cipher" +readme = "README.md" +keywords = [ + "crypto", + "block-cipher", + "stream-cipher", + "trait", +] +categories = [ + "cryptography", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/traits" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.blobby] +version = "0.3" +optional = true + +[dependencies.crypto-common] +version = "0.1.6" + +[dependencies.inout] +version = "0.1" + +[dependencies.zeroize] +version = "1.5" +optional = true +default-features = false + +[features] +alloc = [] +block-padding = ["inout/block-padding"] +dev = ["blobby"] +rand_core = ["crypto-common/rand_core"] +std = [ + "alloc", + "crypto-common/std", + "inout/std", +] diff --git a/vendor/cipher/LICENSE-APACHE b/vendor/cipher/LICENSE-APACHE new file mode 100644 index 00000000..78173fa2 --- /dev/null +++ b/vendor/cipher/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 [yyyy] [name of copyright owner] + +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/vendor/cipher/LICENSE-MIT b/vendor/cipher/LICENSE-MIT new file mode 100644 index 00000000..f3a832c3 --- /dev/null +++ b/vendor/cipher/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016-2020 RustCrypto 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/vendor/cipher/README.md b/vendor/cipher/README.md new file mode 100644 index 00000000..9d117626 --- /dev/null +++ b/vendor/cipher/README.md @@ -0,0 +1,62 @@ +# RustCrypto: Cipher Traits + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] +[![Build Status][build-image]][build-link] + +Traits which define the functionality of [block ciphers] and [stream ciphers]. + +See [RustCrypto/block-ciphers] and [RustCrypto/stream-ciphers] for algorithm +implementations which use these traits. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +Rust **1.56** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/cipher.svg +[crate-link]: https://crates.io/crates/cipher +[docs-image]: https://docs.rs/cipher/badge.svg +[docs-link]: https://docs.rs/cipher/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260050-traits +[build-image]: https://github.com/RustCrypto/traits/workflows/cipher/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/traits/actions?query=workflow:cipher + +[//]: # (general links) + +[block ciphers]: https://en.wikipedia.org/wiki/Block_cipher +[stream ciphers]: https://en.wikipedia.org/wiki/Stream_cipher +[RustCrypto/block-ciphers]: https://github.com/RustCrypto/block-ciphers +[RustCrypto/stream-ciphers]: https://github.com/RustCrypto/stream-ciphers diff --git a/vendor/cipher/src/block.rs b/vendor/cipher/src/block.rs new file mode 100644 index 00000000..0742ced1 --- /dev/null +++ b/vendor/cipher/src/block.rs @@ -0,0 +1,721 @@ +//! Traits used to define functionality of [block ciphers][1] and [modes of operation][2]. +//! +//! # About block ciphers +//! +//! Block ciphers are keyed, deterministic permutations of a fixed-sized input +//! "block" providing a reversible transformation to/from an encrypted output. +//! They are one of the fundamental structural components of [symmetric cryptography][3]. +//! +//! [1]: https://en.wikipedia.org/wiki/Block_cipher +//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation +//! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm + +use crate::{ParBlocks, ParBlocksSizeUser}; +#[cfg(all(feature = "block-padding", feature = "alloc"))] +use alloc::{vec, vec::Vec}; +#[cfg(feature = "block-padding")] +use inout::{ + block_padding::{Padding, UnpadError}, + InOutBufReserved, PadError, +}; +use inout::{InOut, InOutBuf, NotEqualError}; + +pub use crypto_common::{generic_array::ArrayLength, typenum::Unsigned, Block, BlockSizeUser}; + +/// Marker trait for block ciphers. +pub trait BlockCipher: BlockSizeUser {} + +/// Trait implemented by block cipher encryption and decryption backends. +pub trait BlockBackend: ParBlocksSizeUser { + /// Process single inout block. + fn proc_block(&mut self, block: InOut<'_, '_, Block>); + + /// Process inout blocks in parallel. + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { + for i in 0..Self::ParBlocksSize::USIZE { + self.proc_block(blocks.get(i)); + } + } + + /// Process buffer of inout blocks. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn proc_tail_blocks(&mut self, blocks: InOutBuf<'_, '_, Block>) { + assert!(blocks.len() < Self::ParBlocksSize::USIZE); + for block in blocks { + self.proc_block(block); + } + } + + /// Process single block in-place. + #[inline(always)] + fn proc_block_inplace(&mut self, block: &mut Block) { + self.proc_block(block.into()); + } + + /// Process blocks in parallel in-place. + #[inline(always)] + fn proc_par_blocks_inplace(&mut self, blocks: &mut ParBlocks) { + self.proc_par_blocks(blocks.into()); + } + + /// Process buffer of blocks in-place. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn proc_tail_blocks_inplace(&mut self, blocks: &mut [Block]) { + self.proc_tail_blocks(blocks.into()); + } +} + +/// Trait for [`BlockBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait BlockClosure: BlockSizeUser { + /// Execute closure with the provided block cipher backend. + fn call>(self, backend: &mut B); +} + +/// Encrypt-only functionality for block ciphers. +pub trait BlockEncrypt: BlockSizeUser + Sized { + /// Encrypt data using backend provided to the rank-2 closure. + fn encrypt_with_backend(&self, f: impl BlockClosure); + + /// Encrypt single `inout` block. + #[inline] + fn encrypt_block_inout(&self, block: InOut<'_, '_, Block>) { + self.encrypt_with_backend(BlockCtx { block }); + } + + /// Encrypt `inout` blocks. + #[inline] + fn encrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block>) { + self.encrypt_with_backend(BlocksCtx { blocks }); + } + + /// Encrypt single block in-place. + #[inline] + fn encrypt_block(&self, block: &mut Block) { + let block = block.into(); + self.encrypt_with_backend(BlockCtx { block }); + } + + /// Encrypt `in_block` and write result to `out_block`. + #[inline] + fn encrypt_block_b2b(&self, in_block: &Block, out_block: &mut Block) { + let block = (in_block, out_block).into(); + self.encrypt_with_backend(BlockCtx { block }); + } + + /// Encrypt blocks in-place. + #[inline] + fn encrypt_blocks(&self, blocks: &mut [Block]) { + let blocks = blocks.into(); + self.encrypt_with_backend(BlocksCtx { blocks }); + } + + /// Encrypt blocks buffer-to-buffer. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + #[inline] + fn encrypt_blocks_b2b( + &self, + in_blocks: &[Block], + out_blocks: &mut [Block], + ) -> Result<(), NotEqualError> { + InOutBuf::new(in_blocks, out_blocks) + .map(|blocks| self.encrypt_with_backend(BlocksCtx { blocks })) + } + + /// Pad input and encrypt. Returns resulting ciphertext slice. + /// + /// Returns [`PadError`] if length of output buffer is not sufficient. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn encrypt_padded_inout<'inp, 'out, P: Padding>( + &self, + data: InOutBufReserved<'inp, 'out, u8>, + ) -> Result<&'out [u8], PadError> { + let mut buf = data.into_padded_blocks::()?; + self.encrypt_blocks_inout(buf.get_blocks()); + if let Some(block) = buf.get_tail_block() { + self.encrypt_block_inout(block); + } + Ok(buf.into_out()) + } + + /// Pad input and encrypt in-place. Returns resulting ciphertext slice. + /// + /// Returns [`PadError`] if length of output buffer is not sufficient. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn encrypt_padded<'a, P: Padding>( + &self, + buf: &'a mut [u8], + msg_len: usize, + ) -> Result<&'a [u8], PadError> { + let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?; + self.encrypt_padded_inout::

(buf) + } + + /// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice. + /// + /// Returns [`PadError`] if length of output buffer is not sufficient. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn encrypt_padded_b2b<'a, P: Padding>( + &self, + msg: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], PadError> { + let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?; + self.encrypt_padded_inout::

(buf) + } + + /// Pad input and encrypt into a newly allocated Vec. Returns resulting ciphertext Vec. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn encrypt_padded_vec>(&self, msg: &[u8]) -> Vec { + let mut out = allocate_out_vec::(msg.len()); + let len = self + .encrypt_padded_b2b::

(msg, &mut out) + .expect("enough space for encrypting is allocated") + .len(); + out.truncate(len); + out + } +} + +/// Decrypt-only functionality for block ciphers. +pub trait BlockDecrypt: BlockSizeUser { + /// Decrypt data using backend provided to the rank-2 closure. + fn decrypt_with_backend(&self, f: impl BlockClosure); + + /// Decrypt single `inout` block. + #[inline] + fn decrypt_block_inout(&self, block: InOut<'_, '_, Block>) { + self.decrypt_with_backend(BlockCtx { block }); + } + + /// Decrypt `inout` blocks. + #[inline] + fn decrypt_blocks_inout(&self, blocks: InOutBuf<'_, '_, Block>) { + self.decrypt_with_backend(BlocksCtx { blocks }); + } + + /// Decrypt single block in-place. + #[inline] + fn decrypt_block(&self, block: &mut Block) { + let block = block.into(); + self.decrypt_with_backend(BlockCtx { block }); + } + + /// Decrypt `in_block` and write result to `out_block`. + #[inline] + fn decrypt_block_b2b(&self, in_block: &Block, out_block: &mut Block) { + let block = (in_block, out_block).into(); + self.decrypt_with_backend(BlockCtx { block }); + } + + /// Decrypt blocks in-place. + #[inline] + fn decrypt_blocks(&self, blocks: &mut [Block]) { + let blocks = blocks.into(); + self.decrypt_with_backend(BlocksCtx { blocks }); + } + + /// Decrypt blocks buffer-to-buffer. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + #[inline] + fn decrypt_blocks_b2b( + &self, + in_blocks: &[Block], + out_blocks: &mut [Block], + ) -> Result<(), NotEqualError> { + InOutBuf::new(in_blocks, out_blocks) + .map(|blocks| self.decrypt_with_backend(BlocksCtx { blocks })) + } + + /// Decrypt input and unpad it. Returns resulting ciphertext slice. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn decrypt_padded_inout<'inp, 'out, P: Padding>( + &self, + data: InOutBuf<'inp, 'out, u8>, + ) -> Result<&'out [u8], UnpadError> { + let (mut blocks, tail) = data.into_chunks(); + if !tail.is_empty() { + return Err(UnpadError); + } + self.decrypt_blocks_inout(blocks.reborrow()); + P::unpad_blocks(blocks.into_out()) + } + + /// Decrypt input and unpad it in-place. Returns resulting ciphertext slice. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn decrypt_padded<'a, P: Padding>( + &self, + buf: &'a mut [u8], + ) -> Result<&'a [u8], UnpadError> { + self.decrypt_padded_inout::

(buf.into()) + } + + /// Decrypt input and unpad it buffer-to-buffer. Returns resulting + /// ciphertext slice. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn decrypt_padded_b2b<'a, P: Padding>( + &self, + in_buf: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], UnpadError> { + if out_buf.len() < in_buf.len() { + return Err(UnpadError); + } + let n = in_buf.len(); + // note: `new` always returns `Ok` here + let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?; + self.decrypt_padded_inout::

(buf) + } + + /// Decrypt input and unpad it in a newly allocated Vec. Returns resulting + /// ciphertext Vec. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn decrypt_padded_vec>( + &self, + buf: &[u8], + ) -> Result, UnpadError> { + let mut out = vec![0; buf.len()]; + let len = self.decrypt_padded_b2b::

(buf, &mut out)?.len(); + out.truncate(len); + Ok(out) + } +} + +/// Encrypt-only functionality for block ciphers and modes with mutable access to `self`. +/// +/// The main use case for this trait is blocks modes, but it also can be used +/// for hardware cryptographic engines which require `&mut self` access to an +/// underlying hardware peripheral. +pub trait BlockEncryptMut: BlockSizeUser + Sized { + /// Encrypt data using backend provided to the rank-2 closure. + fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure); + + /// Encrypt single `inout` block. + #[inline] + fn encrypt_block_inout_mut(&mut self, block: InOut<'_, '_, Block>) { + self.encrypt_with_backend_mut(BlockCtx { block }); + } + + /// Encrypt `inout` blocks. + #[inline] + fn encrypt_blocks_inout_mut(&mut self, blocks: InOutBuf<'_, '_, Block>) { + self.encrypt_with_backend_mut(BlocksCtx { blocks }); + } + + /// Encrypt single block in-place. + #[inline] + fn encrypt_block_mut(&mut self, block: &mut Block) { + let block = block.into(); + self.encrypt_with_backend_mut(BlockCtx { block }); + } + + /// Encrypt `in_block` and write result to `out_block`. + #[inline] + fn encrypt_block_b2b_mut(&mut self, in_block: &Block, out_block: &mut Block) { + let block = (in_block, out_block).into(); + self.encrypt_with_backend_mut(BlockCtx { block }); + } + + /// Encrypt blocks in-place. + #[inline] + fn encrypt_blocks_mut(&mut self, blocks: &mut [Block]) { + let blocks = blocks.into(); + self.encrypt_with_backend_mut(BlocksCtx { blocks }); + } + + /// Encrypt blocks buffer-to-buffer. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + #[inline] + fn encrypt_blocks_b2b_mut( + &mut self, + in_blocks: &[Block], + out_blocks: &mut [Block], + ) -> Result<(), NotEqualError> { + InOutBuf::new(in_blocks, out_blocks) + .map(|blocks| self.encrypt_with_backend_mut(BlocksCtx { blocks })) + } + + /// Pad input and encrypt. Returns resulting ciphertext slice. + /// + /// Returns [`PadError`] if length of output buffer is not sufficient. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn encrypt_padded_inout_mut<'inp, 'out, P: Padding>( + mut self, + data: InOutBufReserved<'inp, 'out, u8>, + ) -> Result<&'out [u8], PadError> { + let mut buf = data.into_padded_blocks::()?; + self.encrypt_blocks_inout_mut(buf.get_blocks()); + if let Some(block) = buf.get_tail_block() { + self.encrypt_block_inout_mut(block); + } + Ok(buf.into_out()) + } + + /// Pad input and encrypt in-place. Returns resulting ciphertext slice. + /// + /// Returns [`PadError`] if length of output buffer is not sufficient. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn encrypt_padded_mut>( + self, + buf: &mut [u8], + msg_len: usize, + ) -> Result<&[u8], PadError> { + let buf = InOutBufReserved::from_mut_slice(buf, msg_len).map_err(|_| PadError)?; + self.encrypt_padded_inout_mut::

(buf) + } + + /// Pad input and encrypt buffer-to-buffer. Returns resulting ciphertext slice. + /// + /// Returns [`PadError`] if length of output buffer is not sufficient. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn encrypt_padded_b2b_mut<'a, P: Padding>( + self, + msg: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], PadError> { + let buf = InOutBufReserved::from_slices(msg, out_buf).map_err(|_| PadError)?; + self.encrypt_padded_inout_mut::

(buf) + } + + /// Pad input and encrypt into a newly allocated Vec. Returns resulting ciphertext Vec. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn encrypt_padded_vec_mut>(self, msg: &[u8]) -> Vec { + let mut out = allocate_out_vec::(msg.len()); + let len = self + .encrypt_padded_b2b_mut::

(msg, &mut out) + .expect("enough space for encrypting is allocated") + .len(); + out.truncate(len); + out + } +} + +/// Decrypt-only functionality for block ciphers and modes with mutable access to `self`. +/// +/// The main use case for this trait is blocks modes, but it also can be used +/// for hardware cryptographic engines which require `&mut self` access to an +/// underlying hardware peripheral. +pub trait BlockDecryptMut: BlockSizeUser + Sized { + /// Decrypt data using backend provided to the rank-2 closure. + fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure); + + /// Decrypt single `inout` block. + #[inline] + fn decrypt_block_inout_mut(&mut self, block: InOut<'_, '_, Block>) { + self.decrypt_with_backend_mut(BlockCtx { block }); + } + + /// Decrypt `inout` blocks. + #[inline] + fn decrypt_blocks_inout_mut(&mut self, blocks: InOutBuf<'_, '_, Block>) { + self.decrypt_with_backend_mut(BlocksCtx { blocks }); + } + + /// Decrypt single block in-place. + #[inline] + fn decrypt_block_mut(&mut self, block: &mut Block) { + let block = block.into(); + self.decrypt_with_backend_mut(BlockCtx { block }); + } + + /// Decrypt `in_block` and write result to `out_block`. + #[inline] + fn decrypt_block_b2b_mut(&mut self, in_block: &Block, out_block: &mut Block) { + let block = (in_block, out_block).into(); + self.decrypt_with_backend_mut(BlockCtx { block }); + } + + /// Decrypt blocks in-place. + #[inline] + fn decrypt_blocks_mut(&mut self, blocks: &mut [Block]) { + let blocks = blocks.into(); + self.decrypt_with_backend_mut(BlocksCtx { blocks }); + } + + /// Decrypt blocks buffer-to-buffer. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + #[inline] + fn decrypt_blocks_b2b_mut( + &mut self, + in_blocks: &[Block], + out_blocks: &mut [Block], + ) -> Result<(), NotEqualError> { + InOutBuf::new(in_blocks, out_blocks) + .map(|blocks| self.decrypt_with_backend_mut(BlocksCtx { blocks })) + } + + /// Decrypt input and unpad it. Returns resulting ciphertext slice. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn decrypt_padded_inout_mut<'inp, 'out, P: Padding>( + mut self, + data: InOutBuf<'inp, 'out, u8>, + ) -> Result<&'out [u8], UnpadError> { + let (mut blocks, tail) = data.into_chunks(); + if !tail.is_empty() { + return Err(UnpadError); + } + self.decrypt_blocks_inout_mut(blocks.reborrow()); + P::unpad_blocks(blocks.into_out()) + } + + /// Decrypt input and unpad it in-place. Returns resulting ciphertext slice. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn decrypt_padded_mut>( + self, + buf: &mut [u8], + ) -> Result<&[u8], UnpadError> { + self.decrypt_padded_inout_mut::

(buf.into()) + } + + /// Decrypt input and unpad it buffer-to-buffer. Returns resulting + /// ciphertext slice. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(feature = "block-padding")] + #[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] + #[inline] + fn decrypt_padded_b2b_mut<'a, P: Padding>( + self, + in_buf: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], UnpadError> { + if out_buf.len() < in_buf.len() { + return Err(UnpadError); + } + let n = in_buf.len(); + // note: `new` always returns `Ok` here + let buf = InOutBuf::new(in_buf, &mut out_buf[..n]).map_err(|_| UnpadError)?; + self.decrypt_padded_inout_mut::

(buf) + } + + /// Decrypt input and unpad it in a newly allocated Vec. Returns resulting + /// ciphertext Vec. + /// + /// Returns [`UnpadError`] if padding is malformed or if input length is + /// not multiple of `Self::BlockSize`. + #[cfg(all(feature = "block-padding", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "block-padding", feature = "alloc"))))] + #[inline] + fn decrypt_padded_vec_mut>( + self, + buf: &[u8], + ) -> Result, UnpadError> { + let mut out = vec![0; buf.len()]; + let len = self.decrypt_padded_b2b_mut::

(buf, &mut out)?.len(); + out.truncate(len); + Ok(out) + } +} + +impl BlockEncryptMut for Alg { + fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure) { + self.encrypt_with_backend(f); + } +} + +impl BlockDecryptMut for Alg { + fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure) { + self.decrypt_with_backend(f); + } +} + +impl BlockCipher for &Alg {} + +impl BlockEncrypt for &Alg { + fn encrypt_with_backend(&self, f: impl BlockClosure) { + Alg::encrypt_with_backend(self, f); + } +} + +impl BlockDecrypt for &Alg { + fn decrypt_with_backend(&self, f: impl BlockClosure) { + Alg::decrypt_with_backend(self, f); + } +} + +/// Closure used in methods which operate over separate blocks. +struct BlockCtx<'inp, 'out, BS: ArrayLength> { + block: InOut<'inp, 'out, Block>, +} + +impl<'inp, 'out, BS: ArrayLength> BlockSizeUser for BlockCtx<'inp, 'out, BS> { + type BlockSize = BS; +} + +impl<'inp, 'out, BS: ArrayLength> BlockClosure for BlockCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + backend.proc_block(self.block); + } +} + +/// Closure used in methods which operate over slice of blocks. +struct BlocksCtx<'inp, 'out, BS: ArrayLength> { + blocks: InOutBuf<'inp, 'out, Block>, +} + +impl<'inp, 'out, BS: ArrayLength> BlockSizeUser for BlocksCtx<'inp, 'out, BS> { + type BlockSize = BS; +} + +impl<'inp, 'out, BS: ArrayLength> BlockClosure for BlocksCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, tail) = self.blocks.into_chunks(); + for chunk in chunks { + backend.proc_par_blocks(chunk); + } + backend.proc_tail_blocks(tail); + } else { + for block in self.blocks { + backend.proc_block(block); + } + } + } +} + +#[cfg(all(feature = "block-padding", feature = "alloc"))] +fn allocate_out_vec(len: usize) -> Vec { + let bs = BS::BlockSize::USIZE; + vec![0; bs * (len / bs + 1)] +} + +/// Implement simple block backend +#[macro_export] +macro_rules! impl_simple_block_encdec { + ( + <$($N:ident$(:$b0:ident$(+$b:ident)*)?),*> + $cipher:ident, $block_size:ty, $state:ident, $block:ident, + encrypt: $enc_block:block + decrypt: $dec_block:block + ) => { + impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockSizeUser for $cipher<$($N),*> { + type BlockSize = $block_size; + } + + impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockEncrypt for $cipher<$($N),*> { + fn encrypt_with_backend(&self, f: impl $crate::BlockClosure) { + struct EncBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>); + + impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for EncBack<'a, $($N),*> { + type BlockSize = $block_size; + } + + impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for EncBack<'a, $($N),*> { + type ParBlocksSize = $crate::consts::U1; + } + + impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for EncBack<'a, $($N),*> { + #[inline(always)] + fn proc_block( + &mut self, + mut $block: $crate::inout::InOut<'_, '_, $crate::Block> + ) { + let $state: &$cipher<$($N),*> = self.0; + $enc_block + } + } + + f.call(&mut EncBack(self)) + } + } + + impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockDecrypt for $cipher<$($N),*> { + fn decrypt_with_backend(&self, f: impl $crate::BlockClosure) { + struct DecBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>); + + impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for DecBack<'a, $($N),*> { + type BlockSize = $block_size; + } + + impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for DecBack<'a, $($N),*> { + type ParBlocksSize = $crate::consts::U1; + } + + impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for DecBack<'a, $($N),*> { + #[inline(always)] + fn proc_block( + &mut self, + mut $block: $crate::inout::InOut<'_, '_, $crate::Block> + ) { + let $state: &$cipher<$($N),*> = self.0; + $dec_block + } + } + + f.call(&mut DecBack(self)) + } + } + }; + ( + $cipher:ident, $block_size:ty, $state:ident, $block:ident, + encrypt: $enc_block:block + decrypt: $dec_block:block + ) => { + $crate::impl_simple_block_encdec!( + <> $cipher, $block_size, $state, $block, + encrypt: $enc_block + decrypt: $dec_block + ); + }; +} diff --git a/vendor/cipher/src/dev.rs b/vendor/cipher/src/dev.rs new file mode 100644 index 00000000..6bedbe98 --- /dev/null +++ b/vendor/cipher/src/dev.rs @@ -0,0 +1,2 @@ +mod block; +mod stream; diff --git a/vendor/cipher/src/dev/block.rs b/vendor/cipher/src/dev/block.rs new file mode 100644 index 00000000..d3115c5d --- /dev/null +++ b/vendor/cipher/src/dev/block.rs @@ -0,0 +1,389 @@ +//! Development-related functionality + +pub use blobby; + +/// Define block cipher test +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! block_cipher_test { + ($name:ident, $test_name:expr, $cipher:ty $(,)?) => { + #[test] + fn $name() { + use cipher::{ + blobby::Blob3Iterator, generic_array::GenericArray, typenum::Unsigned, + BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyInit, + }; + + fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool { + let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap(); + + let mut block = GenericArray::clone_from_slice(pt); + state.encrypt_block_mut(&mut block); + if ct != block.as_slice() { + return false; + } + + state.decrypt_block_mut(&mut block); + if pt != block.as_slice() { + return false; + } + + true + } + + fn run_par_test(key: &[u8], pt: &[u8]) -> bool { + type Block = cipher::Block<$cipher>; + + let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap(); + + let block = Block::clone_from_slice(pt); + let mut blocks1 = vec![block; 101]; + for (i, b) in blocks1.iter_mut().enumerate() { + *b = block; + b[0] = b[0].wrapping_add(i as u8); + } + let mut blocks2 = blocks1.clone(); + + // check that `encrypt_blocks` and `encrypt_block` + // result in the same ciphertext + state.encrypt_blocks_mut(&mut blocks1); + for b in blocks2.iter_mut() { + state.encrypt_block_mut(b); + } + if blocks1 != blocks2 { + return false; + } + + // check that `encrypt_blocks` and `encrypt_block` + // result in the same plaintext + state.decrypt_blocks_mut(&mut blocks1); + for b in blocks2.iter_mut() { + state.decrypt_block_mut(b); + } + if blocks1 != blocks2 { + return false; + } + + true + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { + let [key, pt, ct] = row.unwrap(); + if !run_test(key, pt, ct) { + panic!( + "\n\ + Failed test №{}\n\ + key:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n", + i, key, pt, ct, + ); + } + + // test parallel blocks encryption/decryption + if !run_par_test(key, pt) { + panic!( + "\n\ + Failed parallel test №{}\n\ + key:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n", + i, key, pt, ct, + ); + } + } + } + }; +} + +/// Define block mode encryption test +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! block_mode_enc_test { + ($name:ident, $test_name:expr, $cipher:ty $(,)?) => { + #[test] + fn $name() { + use cipher::{ + blobby::Blob4Iterator, generic_array::GenericArray, inout::InOutBuf, + typenum::Unsigned, BlockEncryptMut, BlockSizeUser, KeyIvInit, + }; + + fn run_test(key: &[u8], iv: &[u8], pt: &[u8], ct: &[u8]) -> bool { + assert_eq!(pt.len(), ct.len()); + // test block-by-block processing + let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap(); + + let mut out = vec![0u8; ct.len()]; + let mut buf = InOutBuf::new(pt, &mut out).unwrap(); + let (blocks, tail) = buf.reborrow().into_chunks(); + assert_eq!(tail.len(), 0); + for block in blocks { + state.encrypt_block_inout_mut(block); + } + if buf.get_out() != ct { + return false; + } + + // test multi-block processing + let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap(); + buf.get_out().iter_mut().for_each(|b| *b = 0); + let (blocks, _) = buf.reborrow().into_chunks(); + state.encrypt_blocks_inout_mut(blocks); + if buf.get_out() != ct { + return false; + } + + true + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { + let [key, iv, pt, ct] = row.unwrap(); + if !run_test(key, iv, pt, ct) { + panic!( + "\n\ + Failed test №{}\n\ + key:\t{:?}\n\ + iv:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n", + i, key, iv, pt, ct, + ); + } + } + } + }; +} + +/// Define block mode decryption test +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! block_mode_dec_test { + ($name:ident, $test_name:expr, $cipher:ty $(,)?) => { + #[test] + fn $name() { + use cipher::{ + blobby::Blob4Iterator, generic_array::GenericArray, inout::InOutBuf, + typenum::Unsigned, BlockDecryptMut, BlockSizeUser, KeyIvInit, + }; + + fn run_test(key: &[u8], iv: &[u8], pt: &[u8], ct: &[u8]) -> bool { + assert_eq!(pt.len(), ct.len()); + // test block-by-block processing + let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap(); + + let mut out = vec![0u8; pt.len()]; + let mut buf = InOutBuf::new(ct, &mut out).unwrap(); + let (blocks, tail) = buf.reborrow().into_chunks(); + assert_eq!(tail.len(), 0); + for block in blocks { + state.decrypt_block_inout_mut(block); + } + if buf.get_out() != pt { + return false; + } + + // test multi-block processing + let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap(); + buf.get_out().iter_mut().for_each(|b| *b = 0); + let (blocks, _) = buf.reborrow().into_chunks(); + state.decrypt_blocks_inout_mut(blocks); + if buf.get_out() != pt { + return false; + } + + true + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { + let [key, iv, pt, ct] = row.unwrap(); + if !run_test(key, iv, pt, ct) { + panic!( + "\n\ + Failed test №{}\n\ + key:\t{:?}\n\ + iv:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n", + i, key, iv, pt, ct, + ); + } + } + } + }; +} + +/// Define `IvState` test +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! iv_state_test { + ($name:ident, $cipher:ty, encrypt $(,)?) => { + $crate::iv_state_test!($name, $cipher, encrypt_blocks_mut); + }; + ($name:ident, $cipher:ty, decrypt $(,)?) => { + $crate::iv_state_test!($name, $cipher, decrypt_blocks_mut); + }; + ($name:ident, $cipher:ty, apply_ks $(,)?) => { + $crate::iv_state_test!($name, $cipher, apply_keystream_blocks); + }; + ($name:ident, $cipher:ty, $method:ident $(,)?) => { + #[test] + fn $name() { + use cipher::*; + + let mut blocks = [Block::<$cipher>::default(); 32]; + + for (i, block) in blocks.iter_mut().enumerate() { + for (j, b) in block.iter_mut().enumerate() { + *b = (i + j) as u8; + } + } + + let mut key = Key::<$cipher>::default(); + let mut iv = Iv::<$cipher>::default(); + key.iter_mut().for_each(|b| *b = 0x42); + iv.iter_mut().for_each(|b| *b = 0x24); + + let mut cipher = <$cipher>::new(&key, &iv); + let mut target = blocks.clone(); + cipher.$method(&mut target); + + for i in 0..32 { + let mut blocks = blocks.clone(); + let (b1, b2) = blocks.split_at_mut(i); + let mut cipher1 = <$cipher>::new(&key, &iv); + cipher1.$method(b1); + let temp_iv = cipher1.iv_state(); + let mut cipher2 = <$cipher>::new(&key, &temp_iv); + cipher2.$method(b2); + assert_eq!(blocks, target); + } + } + }; +} + +/// Define block encryptor benchmark +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! block_encryptor_bench { + (Key: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => { + $crate::block_encryptor_bench!( + { + use $crate::KeyInit; + let key = test::black_box(Default::default()); + <$cipher>::new(&key) + }, + $cipher, + $block_name, + $blocks_name, + ); + }; + (KeyIv: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => { + $crate::block_encryptor_bench!( + { + use $crate::KeyIvInit; + let key = test::black_box(Default::default()); + let iv = test::black_box(Default::default()); + <$cipher>::new(&key, &iv) + }, + $cipher, + $block_name, + $blocks_name, + ); + }; + ($init:block, $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => { + #[bench] + pub fn $block_name(bh: &mut test::Bencher) { + use cipher::BlockEncryptMut; + + let mut cipher = $init; + let mut blocks = vec![Default::default(); 1024]; + + bh.iter(|| { + for block in blocks.iter_mut() { + cipher.encrypt_block_mut(block); + } + test::black_box(&blocks); + }); + bh.bytes = (blocks.len() * blocks[0].len()) as u64; + } + + #[bench] + pub fn $blocks_name(bh: &mut test::Bencher) { + use cipher::BlockEncryptMut; + + let mut cipher = $init; + let mut blocks = vec![Default::default(); 1024]; + + bh.iter(|| { + cipher.encrypt_blocks_mut(&mut blocks); + test::black_box(&blocks); + }); + bh.bytes = (blocks.len() * blocks[0].len()) as u64; + } + }; +} + +/// Define block decryptor benchmark +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! block_decryptor_bench { + (Key: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => { + $crate::block_decryptor_bench!( + { + use $crate::KeyInit; + let key = test::black_box(Default::default()); + <$cipher>::new(&key) + }, + $cipher, + $block_name, + $blocks_name, + ); + }; + (KeyIv: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => { + $crate::block_decryptor_bench!( + { + use $crate::KeyIvInit; + let key = test::black_box(Default::default()); + let iv = test::black_box(Default::default()); + <$cipher>::new(&key, &iv) + }, + $cipher, + $block_name, + $blocks_name, + ); + }; + ($init:block, $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => { + #[bench] + pub fn $block_name(bh: &mut test::Bencher) { + use cipher::BlockDecryptMut; + + let mut cipher = $init; + let mut blocks = vec![Default::default(); 1024]; + + bh.iter(|| { + for block in blocks.iter_mut() { + cipher.decrypt_block_mut(block); + } + test::black_box(&blocks); + }); + bh.bytes = (blocks.len() * blocks[0].len()) as u64; + } + + #[bench] + pub fn $blocks_name(bh: &mut test::Bencher) { + use cipher::BlockDecryptMut; + + let mut cipher = $init; + let mut blocks = vec![Default::default(); 1024]; + + bh.iter(|| { + cipher.decrypt_blocks_mut(&mut blocks); + test::black_box(&blocks); + }); + bh.bytes = (blocks.len() * blocks[0].len()) as u64; + } + }; +} diff --git a/vendor/cipher/src/dev/stream.rs b/vendor/cipher/src/dev/stream.rs new file mode 100644 index 00000000..0496345d --- /dev/null +++ b/vendor/cipher/src/dev/stream.rs @@ -0,0 +1,145 @@ +//! Development-related functionality + +/// Test core functionality of synchronous stream cipher +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! stream_cipher_test { + ($name:ident, $test_name:expr, $cipher:ty $(,)?) => { + #[test] + fn $name() { + use cipher::generic_array::GenericArray; + use cipher::{blobby::Blob4Iterator, KeyIvInit, StreamCipher}; + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { + let [key, iv, pt, ct] = row.unwrap(); + + for chunk_n in 1..256 { + let mut mode = <$cipher>::new_from_slices(key, iv).unwrap(); + let mut pt = pt.to_vec(); + for chunk in pt.chunks_mut(chunk_n) { + mode.apply_keystream(chunk); + } + if pt != &ct[..] { + panic!( + "Failed main test №{}, chunk size: {}\n\ + key:\t{:?}\n\ + iv:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n", + i, chunk_n, key, iv, pt, ct, + ); + } + } + } + } + }; +} + +/// Test stream synchronous stream cipher seeking capabilities +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! stream_cipher_seek_test { + ($name:ident, $cipher:ty) => { + #[test] + fn $name() { + use cipher::generic_array::GenericArray; + use cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; + + fn get_cipher() -> $cipher { + <$cipher>::new(&Default::default(), &Default::default()) + } + + const MAX_SEEK: usize = 512; + + let mut ct = [0u8; MAX_SEEK]; + get_cipher().apply_keystream(&mut ct[..]); + + for n in 0..MAX_SEEK { + let mut cipher = get_cipher(); + assert_eq!(cipher.current_pos::(), 0); + cipher.seek(n); + assert_eq!(cipher.current_pos::(), n); + let mut buf = [0u8; MAX_SEEK]; + cipher.apply_keystream(&mut buf[n..]); + assert_eq!(cipher.current_pos::(), MAX_SEEK); + assert_eq!(&buf[n..], &ct[n..]); + } + + const MAX_CHUNK: usize = 128; + const MAX_LEN: usize = 1024; + + let mut buf = [0u8; MAX_CHUNK]; + let mut cipher = get_cipher(); + assert_eq!(cipher.current_pos::(), 0); + cipher.apply_keystream(&mut []); + assert_eq!(cipher.current_pos::(), 0); + for n in 1..MAX_CHUNK { + assert_eq!(cipher.current_pos::(), 0); + for m in 1.. { + cipher.apply_keystream(&mut buf[..n]); + assert_eq!(cipher.current_pos::(), n * m); + if n * m > MAX_LEN { + break; + } + } + cipher.seek(0); + } + } + }; +} + +/// Create stream cipher benchmarks +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! stream_cipher_bench { + ( + $cipher:ty; + $($name:ident $bs:expr;)* + ) => { + $crate::stream_cipher_bench!( + Init: { + use $crate::KeyIvInit; + let key = test::black_box(Default::default()); + let iv = test::black_box(Default::default()); + <$cipher>::new(&key, &iv) + }; + $($name $bs;)* + ); + }; + ( + Key: $cipher:ty; + $($name:ident $bs:expr;)* + ) => { + $crate::stream_cipher_bench!( + Init: { + use $crate::KeyInit; + let key = test::black_box(Default::default()); + let iv = test::black_box(Default::default()); + <$cipher>::new(&key, &iv) + }; + $($name $bs;)* + ); + }; + ( + Init: $init:expr; + $($name:ident $bs:expr;)* + ) => { + $( + #[bench] + fn $name(b: &mut test::Bencher) { + use $crate::StreamCipher; + + let mut cipher = $init; + let mut buf = vec![0; $bs]; + + b.iter(|| { + cipher.apply_keystream(&mut buf); + test::black_box(&buf); + }); + + b.bytes = $bs; + } + )* + }; +} diff --git a/vendor/cipher/src/errors.rs b/vendor/cipher/src/errors.rs new file mode 100644 index 00000000..0dc32740 --- /dev/null +++ b/vendor/cipher/src/errors.rs @@ -0,0 +1,43 @@ +//! Error types. + +use core::fmt; + +/// This error is returned by the [`StreamCipher`][crate::stream::StreamCipher] +/// trait methods. +/// +/// Usually it's used in cases when stream cipher has reached the end +/// of a keystream, but also can be used if lengths of provided input +/// and output buffers are not equal. +#[derive(Copy, Clone, Debug)] +pub struct StreamCipherError; + +impl fmt::Display for StreamCipherError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Loop Error") + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for StreamCipherError {} + +/// The error type returned when a cipher position can not be represented +/// by the requested type. +#[derive(Copy, Clone, Debug)] +pub struct OverflowError; + +impl fmt::Display for OverflowError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Overflow Error") + } +} + +impl From for StreamCipherError { + fn from(_: OverflowError) -> StreamCipherError { + StreamCipherError + } +} + +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for OverflowError {} diff --git a/vendor/cipher/src/lib.rs b/vendor/cipher/src/lib.rs new file mode 100644 index 00000000..87041c19 --- /dev/null +++ b/vendor/cipher/src/lib.rs @@ -0,0 +1,60 @@ +//! This crate defines a set of traits which describe the functionality of +//! [block ciphers][1], [block modes][2], and [stream ciphers][3]. +//! +//! [1]: https://en.wikipedia.org/wiki/Block_cipher +//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation +//! [3]: https://en.wikipedia.org/wiki/Stream_cipher + +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![warn(missing_docs, rust_2018_idioms)] + +pub use crypto_common; +pub use inout; + +#[cfg(all(feature = "block-padding", feature = "alloc"))] +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +#[cfg(feature = "rand_core")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] +pub use crypto_common::rand_core; + +#[cfg(feature = "block-padding")] +#[cfg_attr(docsrs, doc(cfg(feature = "block-padding")))] +pub use inout::block_padding; + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +pub use zeroize; + +#[cfg(feature = "dev")] +pub use blobby; + +mod block; +#[cfg(feature = "dev")] +mod dev; +mod errors; +mod stream; +mod stream_core; +mod stream_wrapper; + +pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*}; +pub use crypto_common::{ + generic_array, + typenum::{self, consts}, + AlgorithmName, Block, InnerIvInit, InvalidLength, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, + KeySizeUser, ParBlocks, ParBlocksSizeUser, +}; + +/// Trait for loading current IV state. +pub trait IvState: IvSizeUser { + /// Returns current IV state. + fn iv_state(&self) -> Iv; +} diff --git a/vendor/cipher/src/stream.rs b/vendor/cipher/src/stream.rs new file mode 100644 index 00000000..3ac454e6 --- /dev/null +++ b/vendor/cipher/src/stream.rs @@ -0,0 +1,226 @@ +//! Traits which define functionality of stream ciphers. +//! +//! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers) +//! for ciphers implementation. + +use crate::errors::{OverflowError, StreamCipherError}; +use crate::stream_core::Counter; +use crate::{Block, BlockDecryptMut, BlockEncryptMut}; +use inout::{InOutBuf, NotEqualError}; + +/// Marker trait for block-level asynchronous stream ciphers +pub trait AsyncStreamCipher: Sized { + /// Encrypt data using `InOutBuf`. + fn encrypt_inout(mut self, data: InOutBuf<'_, '_, u8>) + where + Self: BlockEncryptMut, + { + let (blocks, mut tail) = data.into_chunks(); + self.encrypt_blocks_inout_mut(blocks); + let n = tail.len(); + if n != 0 { + let mut block = Block::::default(); + block[..n].copy_from_slice(tail.get_in()); + self.encrypt_block_mut(&mut block); + tail.get_out().copy_from_slice(&block[..n]); + } + } + + /// Decrypt data using `InOutBuf`. + fn decrypt_inout(mut self, data: InOutBuf<'_, '_, u8>) + where + Self: BlockDecryptMut, + { + let (blocks, mut tail) = data.into_chunks(); + self.decrypt_blocks_inout_mut(blocks); + let n = tail.len(); + if n != 0 { + let mut block = Block::::default(); + block[..n].copy_from_slice(tail.get_in()); + self.decrypt_block_mut(&mut block); + tail.get_out().copy_from_slice(&block[..n]); + } + } + /// Encrypt data in place. + fn encrypt(self, buf: &mut [u8]) + where + Self: BlockEncryptMut, + { + self.encrypt_inout(buf.into()); + } + + /// Decrypt data in place. + fn decrypt(self, buf: &mut [u8]) + where + Self: BlockDecryptMut, + { + self.decrypt_inout(buf.into()); + } + + /// Encrypt data from buffer to buffer. + fn encrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError> + where + Self: BlockEncryptMut, + { + InOutBuf::new(in_buf, out_buf).map(|b| self.encrypt_inout(b)) + } + + /// Decrypt data from buffer to buffer. + fn decrypt_b2b(self, in_buf: &[u8], out_buf: &mut [u8]) -> Result<(), NotEqualError> + where + Self: BlockDecryptMut, + { + InOutBuf::new(in_buf, out_buf).map(|b| self.decrypt_inout(b)) + } +} + +/// Synchronous stream cipher core trait. +pub trait StreamCipher { + /// Apply keystream to `inout` data. + /// + /// If end of the keystream will be achieved with the given data length, + /// method will return [`StreamCipherError`] without modifying provided `data`. + fn try_apply_keystream_inout( + &mut self, + buf: InOutBuf<'_, '_, u8>, + ) -> Result<(), StreamCipherError>; + + /// Apply keystream to data behind `buf`. + /// + /// If end of the keystream will be achieved with the given data length, + /// method will return [`StreamCipherError`] without modifying provided `data`. + #[inline] + fn try_apply_keystream(&mut self, buf: &mut [u8]) -> Result<(), StreamCipherError> { + self.try_apply_keystream_inout(buf.into()) + } + + /// Apply keystream to `inout` data. + /// + /// It will XOR generated keystream with the data behind `in` pointer + /// and will write result to `out` pointer. + /// + /// # Panics + /// If end of the keystream will be reached with the given data length, + /// method will panic without modifying the provided `data`. + #[inline] + fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, '_, u8>) { + self.try_apply_keystream_inout(buf).unwrap(); + } + + /// Apply keystream to data in-place. + /// + /// It will XOR generated keystream with `data` and will write result + /// to the same buffer. + /// + /// # Panics + /// If end of the keystream will be reached with the given data length, + /// method will panic without modifying the provided `data`. + #[inline] + fn apply_keystream(&mut self, buf: &mut [u8]) { + self.try_apply_keystream(buf).unwrap(); + } + + /// Apply keystream to data buffer-to-buffer. + /// + /// It will XOR generated keystream with data from the `input` buffer + /// and will write result to the `output` buffer. + /// + /// Returns [`StreamCipherError`] if provided `in_blocks` and `out_blocks` + /// have different lengths or if end of the keystream will be reached with + /// the given input data length. + #[inline] + fn apply_keystream_b2b( + &mut self, + input: &[u8], + output: &mut [u8], + ) -> Result<(), StreamCipherError> { + InOutBuf::new(input, output) + .map_err(|_| StreamCipherError) + .and_then(|buf| self.try_apply_keystream_inout(buf)) + } +} + +/// Trait for seekable stream ciphers. +/// +/// Methods of this trait are generic over the [`SeekNum`] trait, which is +/// implemented for primitive numeric types, i.e.: `i32`, `u32`, `u64`, +/// `u128`, and `usize`. +pub trait StreamCipherSeek { + /// Try to get current keystream position + /// + /// Returns [`OverflowError`] if position can not be represented by type `T` + fn try_current_pos(&self) -> Result; + + /// Try to seek to the given position + /// + /// Returns [`StreamCipherError`] if provided position value is bigger than + /// keystream length. + fn try_seek(&mut self, pos: T) -> Result<(), StreamCipherError>; + + /// Get current keystream position + /// + /// # Panics + /// If position can not be represented by type `T` + fn current_pos(&self) -> T { + self.try_current_pos().unwrap() + } + + /// Seek to the given position + /// + /// # Panics + /// If provided position value is bigger than keystream length + fn seek(&mut self, pos: T) { + self.try_seek(pos).unwrap() + } +} + +impl StreamCipher for &mut C { + #[inline] + fn try_apply_keystream_inout( + &mut self, + buf: InOutBuf<'_, '_, u8>, + ) -> Result<(), StreamCipherError> { + C::try_apply_keystream_inout(self, buf) + } +} + +/// Trait implemented for numeric types which can be used with the +/// [`StreamCipherSeek`] trait. +/// +/// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`. +/// It is not intended to be implemented in third-party crates. +pub trait SeekNum: Sized { + /// Try to get position for block number `block`, byte position inside + /// block `byte`, and block size `bs`. + fn from_block_byte(block: T, byte: u8, bs: u8) -> Result; + + /// Try to get block number and bytes position for given block size `bs`. + fn into_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>; +} + +macro_rules! impl_seek_num { + {$($t:ty )*} => { + $( + impl SeekNum for $t { + fn from_block_byte(block: T, byte: u8, bs: u8) -> Result { + debug_assert!(byte < bs); + let mut block: Self = block.try_into().map_err(|_| OverflowError)?; + if byte != 0 { + block -= 1; + } + let pos = block.checked_mul(bs as Self).ok_or(OverflowError)? + (byte as Self); + Ok(pos) + } + + fn into_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError> { + let bs = bs as Self; + let byte = self % bs; + let block = T::try_from(self/bs).map_err(|_| OverflowError)?; + Ok((block, byte as u8)) + } + } + )* + }; +} + +impl_seek_num! { i32 u32 u64 u128 usize } diff --git a/vendor/cipher/src/stream_core.rs b/vendor/cipher/src/stream_core.rs new file mode 100644 index 00000000..1e4b302e --- /dev/null +++ b/vendor/cipher/src/stream_core.rs @@ -0,0 +1,301 @@ +use crate::{ParBlocks, ParBlocksSizeUser, StreamCipherError}; +use crypto_common::{ + generic_array::{ArrayLength, GenericArray}, + typenum::Unsigned, + Block, BlockSizeUser, +}; +use inout::{InOut, InOutBuf}; + +/// Trait implemented by stream cipher backends. +pub trait StreamBackend: ParBlocksSizeUser { + /// Generate keystream block. + fn gen_ks_block(&mut self, block: &mut Block); + + /// Generate keystream blocks in parallel. + #[inline(always)] + fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks) { + for block in blocks { + self.gen_ks_block(block); + } + } + + /// Generate keystream blocks. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn gen_tail_blocks(&mut self, blocks: &mut [Block]) { + assert!(blocks.len() < Self::ParBlocksSize::USIZE); + for block in blocks { + self.gen_ks_block(block); + } + } +} + +/// Trait for [`StreamBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait StreamClosure: BlockSizeUser { + /// Execute closure with the provided stream cipher backend. + fn call>(self, backend: &mut B); +} + +/// Block-level synchronous stream ciphers. +pub trait StreamCipherCore: BlockSizeUser + Sized { + /// Return number of remaining blocks before cipher wraps around. + /// + /// Returns `None` if number of remaining blocks can not be computed + /// (e.g. in ciphers based on the sponge construction) or it's too big + /// to fit into `usize`. + fn remaining_blocks(&self) -> Option; + + /// Process data using backend provided to the rank-2 closure. + fn process_with_backend(&mut self, f: impl StreamClosure); + + /// Write keystream block. + /// + /// WARNING: this method does not check number of remaining blocks! + #[inline] + fn write_keystream_block(&mut self, block: &mut Block) { + self.process_with_backend(WriteBlockCtx { block }); + } + + /// Write keystream blocks. + /// + /// WARNING: this method does not check number of remaining blocks! + #[inline] + fn write_keystream_blocks(&mut self, blocks: &mut [Block]) { + self.process_with_backend(WriteBlocksCtx { blocks }); + } + + /// Apply keystream block. + /// + /// WARNING: this method does not check number of remaining blocks! + #[inline] + fn apply_keystream_block_inout(&mut self, block: InOut<'_, '_, Block>) { + self.process_with_backend(ApplyBlockCtx { block }); + } + + /// Apply keystream blocks. + /// + /// WARNING: this method does not check number of remaining blocks! + #[inline] + fn apply_keystream_blocks(&mut self, blocks: &mut [Block]) { + self.process_with_backend(ApplyBlocksCtx { + blocks: blocks.into(), + }); + } + + /// Apply keystream blocks. + /// + /// WARNING: this method does not check number of remaining blocks! + #[inline] + fn apply_keystream_blocks_inout(&mut self, blocks: InOutBuf<'_, '_, Block>) { + self.process_with_backend(ApplyBlocksCtx { blocks }); + } + + /// Try to apply keystream to data not divided into blocks. + /// + /// Consumes cipher since it may consume final keystream block only + /// partially. + /// + /// Returns an error if number of remaining blocks is not sufficient + /// for processing the input data. + #[inline] + fn try_apply_keystream_partial( + mut self, + mut buf: InOutBuf<'_, '_, u8>, + ) -> Result<(), StreamCipherError> { + if let Some(rem) = self.remaining_blocks() { + let blocks = if buf.len() % Self::BlockSize::USIZE == 0 { + buf.len() % Self::BlockSize::USIZE + } else { + buf.len() % Self::BlockSize::USIZE + 1 + }; + if blocks > rem { + return Err(StreamCipherError); + } + } + + if buf.len() > Self::BlockSize::USIZE { + let (blocks, tail) = buf.into_chunks(); + self.apply_keystream_blocks_inout(blocks); + buf = tail; + } + let n = buf.len(); + if n == 0 { + return Ok(()); + } + let mut block = Block::::default(); + block[..n].copy_from_slice(buf.get_in()); + let t = InOutBuf::from_mut(&mut block); + self.apply_keystream_blocks_inout(t); + buf.get_out().copy_from_slice(&block[..n]); + Ok(()) + } + + /// Try to apply keystream to data not divided into blocks. + /// + /// Consumes cipher since it may consume final keystream block only + /// partially. + /// + /// # Panics + /// If number of remaining blocks is not sufficient for processing the + /// input data. + #[inline] + fn apply_keystream_partial(self, buf: InOutBuf<'_, '_, u8>) { + self.try_apply_keystream_partial(buf).unwrap() + } +} + +// note: unfortunately, currently we can not write blanket impls of +// `BlockEncryptMut` and `BlockDecryptMut` for `T: StreamCipherCore` +// since it requires mutually exclusive traits, see: +// https://github.com/rust-lang/rfcs/issues/1053 + +/// Counter type usable with [`StreamCipherCore`]. +/// +/// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`. +/// It's not intended to be implemented in third-party crates, but doing so +/// is not forbidden. +pub trait Counter: + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + TryInto + + TryInto + + TryInto +{ +} + +/// Block-level seeking trait for stream ciphers. +pub trait StreamCipherSeekCore: StreamCipherCore { + /// Counter type used inside stream cipher. + type Counter: Counter; + + /// Get current block position. + fn get_block_pos(&self) -> Self::Counter; + + /// Set block position. + fn set_block_pos(&mut self, pos: Self::Counter); +} + +macro_rules! impl_counter { + {$($t:ty )*} => { + $( impl Counter for $t { } )* + }; +} + +impl_counter! { u32 u64 u128 } + +/// Partition buffer into 2 parts: buffer of arrays and tail. +/// +/// In case if `N` is less or equal to 1, buffer of arrays has length +/// of zero and tail is equal to `self`. +#[inline] +fn into_chunks>(buf: &mut [T]) -> (&mut [GenericArray], &mut [T]) { + use core::slice; + if N::USIZE <= 1 { + return (&mut [], buf); + } + let chunks_len = buf.len() / N::USIZE; + let tail_pos = N::USIZE * chunks_len; + let tail_len = buf.len() - tail_pos; + unsafe { + let ptr = buf.as_mut_ptr(); + let chunks = slice::from_raw_parts_mut(ptr as *mut GenericArray, chunks_len); + let tail = slice::from_raw_parts_mut(ptr.add(tail_pos), tail_len); + (chunks, tail) + } +} + +struct WriteBlockCtx<'a, BS: ArrayLength> { + block: &'a mut Block, +} +impl<'a, BS: ArrayLength> BlockSizeUser for WriteBlockCtx<'a, BS> { + type BlockSize = BS; +} +impl<'a, BS: ArrayLength> StreamClosure for WriteBlockCtx<'a, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + backend.gen_ks_block(self.block); + } +} + +struct WriteBlocksCtx<'a, BS: ArrayLength> { + blocks: &'a mut [Block], +} +impl<'a, BS: ArrayLength> BlockSizeUser for WriteBlocksCtx<'a, BS> { + type BlockSize = BS; +} +impl<'a, BS: ArrayLength> StreamClosure for WriteBlocksCtx<'a, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, tail) = into_chunks::<_, B::ParBlocksSize>(self.blocks); + for chunk in chunks { + backend.gen_par_ks_blocks(chunk); + } + backend.gen_tail_blocks(tail); + } else { + for block in self.blocks { + backend.gen_ks_block(block); + } + } + } +} + +struct ApplyBlockCtx<'inp, 'out, BS: ArrayLength> { + block: InOut<'inp, 'out, Block>, +} + +impl<'inp, 'out, BS: ArrayLength> BlockSizeUser for ApplyBlockCtx<'inp, 'out, BS> { + type BlockSize = BS; +} + +impl<'inp, 'out, BS: ArrayLength> StreamClosure for ApplyBlockCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(mut self, backend: &mut B) { + let mut t = Default::default(); + backend.gen_ks_block(&mut t); + self.block.xor_in2out(&t); + } +} + +struct ApplyBlocksCtx<'inp, 'out, BS: ArrayLength> { + blocks: InOutBuf<'inp, 'out, Block>, +} + +impl<'inp, 'out, BS: ArrayLength> BlockSizeUser for ApplyBlocksCtx<'inp, 'out, BS> { + type BlockSize = BS; +} + +impl<'inp, 'out, BS: ArrayLength> StreamClosure for ApplyBlocksCtx<'inp, 'out, BS> { + #[inline(always)] + #[allow(clippy::needless_range_loop)] + fn call>(self, backend: &mut B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, mut tail) = self.blocks.into_chunks::(); + for mut chunk in chunks { + let mut tmp = Default::default(); + backend.gen_par_ks_blocks(&mut tmp); + chunk.xor_in2out(&tmp); + } + let n = tail.len(); + let mut buf = GenericArray::<_, B::ParBlocksSize>::default(); + let ks = &mut buf[..n]; + backend.gen_tail_blocks(ks); + for i in 0..n { + tail.get(i).xor_in2out(&ks[i]); + } + } else { + for mut block in self.blocks { + let mut t = Default::default(); + backend.gen_ks_block(&mut t); + block.xor_in2out(&t); + } + } + } +} diff --git a/vendor/cipher/src/stream_wrapper.rs b/vendor/cipher/src/stream_wrapper.rs new file mode 100644 index 00000000..e3495bc1 --- /dev/null +++ b/vendor/cipher/src/stream_wrapper.rs @@ -0,0 +1,242 @@ +use crate::{ + errors::StreamCipherError, Block, OverflowError, SeekNum, StreamCipher, StreamCipherCore, + StreamCipherSeek, StreamCipherSeekCore, +}; +use crypto_common::{ + typenum::{IsLess, Le, NonZero, Unsigned, U256}, + BlockSizeUser, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser, +}; +use inout::InOutBuf; +#[cfg(feature = "zeroize")] +use zeroize::{Zeroize, ZeroizeOnDrop}; + +/// Wrapper around [`StreamCipherCore`] implementations. +/// +/// It handles data buffering and implements the slice-based traits. +#[derive(Clone, Default)] +pub struct StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + core: T, + buffer: Block, + pos: u8, +} + +impl StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + /// Return reference to the core type. + pub fn get_core(&self) -> &T { + &self.core + } + + /// Return reference to the core type. + pub fn from_core(core: T) -> Self { + Self { + core, + buffer: Default::default(), + pos: 0, + } + } + + /// Return current cursor position. + #[inline] + fn get_pos(&self) -> usize { + let pos = self.pos as usize; + if T::BlockSize::USIZE == 0 { + panic!("Block size can not be equal to zero"); + } + if pos >= T::BlockSize::USIZE { + debug_assert!(false); + // SAFETY: `pos` is set only to values smaller than block size + unsafe { core::hint::unreachable_unchecked() } + } + self.pos as usize + } + + /// Return size of the internal buffer in bytes. + #[inline] + fn size(&self) -> usize { + T::BlockSize::USIZE + } + + #[inline] + fn set_pos_unchecked(&mut self, pos: usize) { + debug_assert!(pos < T::BlockSize::USIZE); + self.pos = pos as u8; + } + + /// Return number of remaining bytes in the internal buffer. + #[inline] + fn remaining(&self) -> usize { + self.size() - self.get_pos() + } + + fn check_remaining(&self, dlen: usize) -> Result<(), StreamCipherError> { + let rem_blocks = match self.core.remaining_blocks() { + Some(v) => v, + None => return Ok(()), + }; + + let bytes = if self.pos == 0 { + dlen + } else { + let rem = self.remaining(); + if dlen > rem { + dlen - rem + } else { + return Ok(()); + } + }; + let bs = T::BlockSize::USIZE; + let blocks = if bytes % bs == 0 { + bytes / bs + } else { + bytes / bs + 1 + }; + if blocks > rem_blocks { + Err(StreamCipherError) + } else { + Ok(()) + } + } +} + +impl StreamCipher for StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + #[inline] + fn try_apply_keystream_inout( + &mut self, + mut data: InOutBuf<'_, '_, u8>, + ) -> Result<(), StreamCipherError> { + self.check_remaining(data.len())?; + + let pos = self.get_pos(); + if pos != 0 { + let rem = &self.buffer[pos..]; + let n = data.len(); + if n < rem.len() { + data.xor_in2out(&rem[..n]); + self.set_pos_unchecked(pos + n); + return Ok(()); + } + let (mut left, right) = data.split_at(rem.len()); + data = right; + left.xor_in2out(rem); + } + + let (blocks, mut leftover) = data.into_chunks(); + self.core.apply_keystream_blocks_inout(blocks); + + let n = leftover.len(); + if n != 0 { + self.core.write_keystream_block(&mut self.buffer); + leftover.xor_in2out(&self.buffer[..n]); + } + self.set_pos_unchecked(n); + + Ok(()) + } +} + +impl StreamCipherSeek for StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + fn try_current_pos(&self) -> Result { + let Self { core, pos, .. } = self; + SN::from_block_byte(core.get_block_pos(), *pos, T::BlockSize::U8) + } + + fn try_seek(&mut self, new_pos: SN) -> Result<(), StreamCipherError> { + let Self { core, buffer, pos } = self; + let (block_pos, byte_pos) = new_pos.into_block_byte(T::BlockSize::U8)?; + core.set_block_pos(block_pos); + if byte_pos != 0 { + self.core.write_keystream_block(buffer); + } + *pos = byte_pos; + Ok(()) + } +} + +// Note: ideally we would only implement the InitInner trait and everything +// else would be handled by blanket impls, but unfortunately it will +// not work properly without mutually exclusive traits, see: +// https://github.com/rust-lang/rfcs/issues/1053 + +impl KeySizeUser for StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + type KeySize = T::KeySize; +} + +impl IvSizeUser for StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + type IvSize = T::IvSize; +} + +impl KeyIvInit for StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + #[inline] + fn new(key: &Key, iv: &Iv) -> Self { + Self { + core: T::new(key, iv), + buffer: Default::default(), + pos: 0, + } + } +} + +impl KeyInit for StreamCipherCoreWrapper +where + T::BlockSize: IsLess, + Le: NonZero, +{ + #[inline] + fn new(key: &Key) -> Self { + Self { + core: T::new(key), + buffer: Default::default(), + pos: 0, + } + } +} + +#[cfg(feature = "zeroize")] +impl Drop for StreamCipherCoreWrapper +where + T: BlockSizeUser, + T::BlockSize: IsLess, + Le: NonZero, +{ + fn drop(&mut self) { + self.buffer.zeroize(); + self.pos.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for StreamCipherCoreWrapper +where + T: BlockSizeUser + ZeroizeOnDrop, + T::BlockSize: IsLess, + Le: NonZero, +{ +} diff --git a/vendor/ctr/.cargo-checksum.json b/vendor/ctr/.cargo-checksum.json new file mode 100644 index 00000000..43f41005 --- /dev/null +++ b/vendor/ctr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d2ea00689fde9856e01df8b11473c509e13089569d69d3e4bf4a67f0b2d96380","Cargo.toml":"ca12229e75889f61e4f519a0995154a9019ad52f060ba1b54a0deb25010d5c94","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"63af4bea227c94d021e99427f6ca3a4b8efddadcca93ab6130f708cf6138cf68","README.md":"3bdb08d24b4ea6b7e51345758b1aaf6a188ea2451864e039512175398ff6a670","benches/aes128.rs":"cbe3685afed5ef473e914962319c034c2e3e39c8baaace12323e2949865f4a09","src/backend.rs":"2156de18ff04f8ca609b2f6ee147892344763addef1a0036c9c4d3d2e170a711","src/ctr_core.rs":"bddcab2fecda06d4d259555982b1e6509f7a940657c716180ace5e3f203ef597","src/flavors.rs":"9b86714f061cdd9dace8bc36567469fcfae98b02c2874a2777a90532a6e84804","src/flavors/ctr128.rs":"c20215de65bd21fa96a66b43bf1f4547a57358d9a6f07526c467a415d075560e","src/flavors/ctr32.rs":"526a0280ad62d71169479b97d8c0e054e52c8978e8a91c6aa137d5b29a1c1fd5","src/flavors/ctr64.rs":"f4d62efca435a10741e11a29a71a515d30b59436b1cb5a2c3df431d423ac8a20","src/lib.rs":"1b21ece7e9f46f7fef5e6cdff1666de97c00684b6cc0450fdd372f10f277823d","tests/ctr128/data/aes128-ctr.blb":"352e39148ee059c5398935c86585db078a04fe9529440006c8a90dcd4084ba65","tests/ctr128/data/aes256-ctr.blb":"4970e3dd51b252cfb8e1879a37b098e4653b70bac2e1d2b45b1994cec7a6468a","tests/ctr128/mod.rs":"81ceaa9518f4154dcf0417ac0a612c20d59779dd4fc00aefad0a6daf1ad5f7ec","tests/ctr32/be.rs":"5e59f724af38ec8fc841a9a18a79a52c3f1e7a05b7c03a3dad19fc155726f4b8","tests/ctr32/le.rs":"a8dbce587f2bea9f8fa8bcc7c2154a17ffa6b675551130b2989c2b5c3d4927c8","tests/ctr32/mod.rs":"b99d6c66e80c01daecf359e7ef091522557a24e2d483964b963224a265640679","tests/gost/mod.rs":"3525e7df4724f6026f946d86202051271e052da0b2d6b5225c856d490456a229","tests/mod.rs":"7ad05b663e5d8a1be10de069cf2f3424c5c5552be1716cc7c1bbe940605d3656"},"package":"0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"} \ No newline at end of file diff --git a/vendor/ctr/CHANGELOG.md b/vendor/ctr/CHANGELOG.md new file mode 100644 index 00000000..b60f31da --- /dev/null +++ b/vendor/ctr/CHANGELOG.md @@ -0,0 +1,79 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.9.2 (2022-09-30) +### Changed +- Implement `Clone` directly for `CtrCore`, so it would work with non-`Clone` flavors ([#24]) + +[#24]: https://github.com/RustCrypto/block-modes/pull/24 + +## 0.9.1 (2022-02-17) +### Fixed +- Minimal versions build ([#9]) + +[#9]: https://github.com/RustCrypto/block-modes/pull/9 + +## 0.9.0 (2022-02-10) +### Changed +- Update `cipher` dependency to v0.4 and move crate +to the [RustCrypto/block-modes] repository ([#2]) + +[#2]: https://github.com/RustCrypto/block-modes/pull/2 +[RustCrypto/block-modes]: https://github.com/RustCrypto/block-modes + +## 0.8.0 (2021-07-08) +### Changed +- Make implementation generic over block size (previously it +was generic only over 128-bit block ciphers). Breaking changes +in the `CtrFlavor` API. ([#252]). + +[#252]: https://github.com/RustCrypto/stream-ciphers/pull/252 + +## 0.7.0 (2020-04-29) +### Changed +- Generic implementation of CTR ([#195]) +- Removed `Ctr32LE` mask bit ([#197]) +- Bump `cipher` dependency to v0.3 ([#226]) + +[#195]: https://github.com/RustCrypto/stream-ciphers/pull/195 +[#197]: https://github.com/RustCrypto/stream-ciphers/pull/197 +[#226]: https://github.com/RustCrypto/stream-ciphers/pull/226 + +## 0.6.0 (2020-10-16) +### Added +- `Ctr32BE` and `Ctr32LE` ([#170]) + +### Changed +- Replace `block-cipher`/`stream-cipher` with `cipher` crate ([#177]) + +[#177]: https://github.com/RustCrypto/stream-ciphers/pull/177 +[#170]: https://github.com/RustCrypto/stream-ciphers/pull/170 + +## 0.5.0 (2020-08-26) +### Changed +- Bump `stream-cipher` dependency to v0.7, implement the `FromBlockCipher` trait ([#161], [#164]) + +[#161]: https://github.com/RustCrypto/stream-ciphers/pull/161 +[#164]: https://github.com/RustCrypto/stream-ciphers/pull/164 + +## 0.4.0 (2020-06-06) +### Changed +- Upgrade to the `stream-cipher` v0.4 crate ([#116], [#138]) +- Upgrade to Rust 2018 edition ([#116]) + +[#138]: https://github.com/RustCrypto/stream-ciphers/pull/138 +[#116]: https://github.com/RustCrypto/stream-ciphers/pull/121 + +## 0.3.2 (2019-03-11) + +## 0.3.0 (2018-11-01) + +## 0.2.0 (2018-10-13) + +## 0.1.1 (2018-10-13) + +## 0.1.0 (2018-07-30) diff --git a/vendor/ctr/Cargo.toml b/vendor/ctr/Cargo.toml new file mode 100644 index 00000000..2feab944 --- /dev/null +++ b/vendor/ctr/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "ctr" +version = "0.9.2" +authors = ["RustCrypto Developers"] +description = "CTR block modes of operation" +documentation = "https://docs.rs/ctr" +readme = "README.md" +keywords = [ + "crypto", + "block-mode", + "stream-cipher", + "ciphers", +] +categories = [ + "cryptography", + "no-std", +] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/block-modes" +resolver = "1" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.cipher] +version = "0.4.2" + +[dev-dependencies.aes] +version = "0.8" + +[dev-dependencies.cipher] +version = "0.4.2" +features = ["dev"] + +[dev-dependencies.hex-literal] +version = "0.3.3" + +[dev-dependencies.kuznyechik] +version = "0.8" + +[dev-dependencies.magma] +version = "0.8" + +[features] +alloc = ["cipher/alloc"] +block-padding = ["cipher/block-padding"] +std = [ + "cipher/std", + "alloc", +] +zeroize = ["cipher/zeroize"] diff --git a/vendor/ctr/LICENSE-APACHE b/vendor/ctr/LICENSE-APACHE new file mode 100644 index 00000000..78173fa2 --- /dev/null +++ b/vendor/ctr/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 [yyyy] [name of copyright owner] + +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/vendor/ctr/LICENSE-MIT b/vendor/ctr/LICENSE-MIT new file mode 100644 index 00000000..d19d409a --- /dev/null +++ b/vendor/ctr/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2018-2022 RustCrypto Developers +Copyright (c) 2018 Artyom Pavlov + +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/vendor/ctr/README.md b/vendor/ctr/README.md new file mode 100644 index 00000000..a2a30431 --- /dev/null +++ b/vendor/ctr/README.md @@ -0,0 +1,59 @@ +# RustCrypto: CTR + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Project Chat][chat-image]][chat-link] +[![Build Status][build-image]][build-link] + +Generic implementation of the [Counter][CTR] (CTR) block cipher mode of operation. + + + +See [documentation][cipher-doc] of the `cipher` crate for additional information. + +## Minimum Supported Rust Version + +Rust **1.56** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/ctr.svg +[crate-link]: https://crates.io/crates/ctr +[docs-image]: https://docs.rs/ctr/badge.svg +[docs-link]: https://docs.rs/ctr/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg +[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg +[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/308460-block-modes +[build-image]: https://github.com/RustCrypto/block-modes/workflows/ctr/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/block-modes/actions?query=workflow%3Actr+branch%3Amaster + +[//]: # (general links) + +[CTR]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR) +[cipher-doc]: https://docs.rs/cipher/ diff --git a/vendor/ctr/benches/aes128.rs b/vendor/ctr/benches/aes128.rs new file mode 100644 index 00000000..ad30e34f --- /dev/null +++ b/vendor/ctr/benches/aes128.rs @@ -0,0 +1,26 @@ +#![feature(test)] +extern crate test; + +cipher::stream_cipher_bench!( + ctr::Ctr32LE; + ctr_32le_aes128_stream_bench1_16b 16; + ctr_32le_aes128_stream_bench2_256b 256; + ctr_32le_aes128_stream_bench3_1kib 1024; + ctr_32le_aes128_stream_bench4_16kib 16384; +); + +cipher::stream_cipher_bench!( + ctr::Ctr64LE; + ctr_64le_aes128_stream_bench1_16b 16; + ctr_64le_aes128_stream_bench2_256b 256; + ctr_64le_aes128_stream_bench3_1kib 1024; + ctr_64le_aes128_stream_bench4_16kib 16384; +); + +cipher::stream_cipher_bench!( + ctr::Ctr128BE; + ctr_128be_aes128_stream_bench1_16b 16; + ctr_128be_aes128_stream_bench2_256b 256; + ctr_128be_aes128_stream_bench3_1kib 1024; + ctr_128be_aes128_stream_bench4_16kib 16384; +); diff --git a/vendor/ctr/src/backend.rs b/vendor/ctr/src/backend.rs new file mode 100644 index 00000000..a94fd43f --- /dev/null +++ b/vendor/ctr/src/backend.rs @@ -0,0 +1,83 @@ +use crate::CtrFlavor; +use cipher::{ + generic_array::ArrayLength, Block, BlockBackend, BlockClosure, BlockSizeUser, ParBlocks, + ParBlocksSizeUser, StreamBackend, StreamClosure, +}; + +struct Backend<'a, F, B> +where + F: CtrFlavor, + B: BlockBackend, +{ + ctr_nonce: &'a mut F::CtrNonce, + backend: &'a mut B, +} + +impl<'a, F, B> BlockSizeUser for Backend<'a, F, B> +where + F: CtrFlavor, + B: BlockBackend, +{ + type BlockSize = B::BlockSize; +} + +impl<'a, F, B> ParBlocksSizeUser for Backend<'a, F, B> +where + F: CtrFlavor, + B: BlockBackend, +{ + type ParBlocksSize = B::ParBlocksSize; +} + +impl<'a, F, B> StreamBackend for Backend<'a, F, B> +where + F: CtrFlavor, + B: BlockBackend, +{ + #[inline(always)] + fn gen_ks_block(&mut self, block: &mut Block) { + let tmp = F::next_block(self.ctr_nonce); + self.backend.proc_block((&tmp, block).into()); + } + + #[inline(always)] + fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks) { + let mut tmp = ParBlocks::::default(); + for block in tmp.iter_mut() { + *block = F::next_block(self.ctr_nonce); + } + self.backend.proc_par_blocks((&tmp, blocks).into()); + } +} + +pub(crate) struct Closure<'a, F, BS, SC> +where + F: CtrFlavor, + BS: ArrayLength, + SC: StreamClosure, +{ + pub(crate) ctr_nonce: &'a mut F::CtrNonce, + pub(crate) f: SC, +} + +impl<'a, F, BS, SC> BlockSizeUser for Closure<'a, F, BS, SC> +where + F: CtrFlavor, + BS: ArrayLength, + SC: StreamClosure, +{ + type BlockSize = BS; +} + +impl<'a, F, BS, SC> BlockClosure for Closure<'a, F, BS, SC> +where + F: CtrFlavor, + BS: ArrayLength, + SC: StreamClosure, +{ + #[inline(always)] + fn call>(self, backend: &mut B) { + let Self { ctr_nonce, f } = self; + f.call(&mut Backend:: { ctr_nonce, backend }) + } +} diff --git a/vendor/ctr/src/ctr_core.rs b/vendor/ctr/src/ctr_core.rs new file mode 100644 index 00000000..c1935961 --- /dev/null +++ b/vendor/ctr/src/ctr_core.rs @@ -0,0 +1,156 @@ +use crate::{backend::Closure, CtrFlavor}; +use cipher::{ + crypto_common::{InnerUser, IvSizeUser}, + AlgorithmName, BlockCipher, BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, + StreamCipherCore, StreamCipherSeekCore, StreamClosure, +}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::ZeroizeOnDrop; + +/// Generic CTR block mode instance. +pub struct CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + cipher: C, + ctr_nonce: F::CtrNonce, +} + +impl BlockSizeUser for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + type BlockSize = C::BlockSize; +} + +impl StreamCipherCore for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + #[inline] + fn remaining_blocks(&self) -> Option { + F::remaining(&self.ctr_nonce) + } + + #[inline] + fn process_with_backend(&mut self, f: impl StreamClosure) { + let Self { cipher, ctr_nonce } = self; + cipher.encrypt_with_backend_mut(Closure:: { ctr_nonce, f }); + } +} + +impl StreamCipherSeekCore for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + type Counter = F::Backend; + + #[inline] + fn get_block_pos(&self) -> Self::Counter { + F::as_backend(&self.ctr_nonce) + } + + #[inline] + fn set_block_pos(&mut self, pos: Self::Counter) { + F::set_from_backend(&mut self.ctr_nonce, pos); + } +} + +impl InnerUser for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + type Inner = C; +} + +impl IvSizeUser for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + type IvSize = C::BlockSize; +} + +impl InnerIvInit for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + #[inline] + fn inner_iv_init(cipher: C, iv: &Iv) -> Self { + Self { + cipher, + ctr_nonce: F::from_nonce(iv), + } + } +} + +impl IvState for CtrCore +where + C: BlockEncryptMut + BlockCipher, + F: CtrFlavor, +{ + #[inline] + fn iv_state(&self) -> Iv { + F::current_block(&self.ctr_nonce) + } +} + +impl AlgorithmName for CtrCore +where + C: BlockEncryptMut + BlockCipher + AlgorithmName, + F: CtrFlavor, +{ + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Ctr")?; + f.write_str(F::NAME)?; + f.write_str("<")?; + ::write_alg_name(f)?; + f.write_str(">") + } +} + +impl Clone for CtrCore +where + C: BlockEncryptMut + BlockCipher + Clone, + F: CtrFlavor, +{ + #[inline] + fn clone(&self) -> Self { + Self { + cipher: self.cipher.clone(), + ctr_nonce: self.ctr_nonce.clone(), + } + } +} + +impl fmt::Debug for CtrCore +where + C: BlockEncryptMut + BlockCipher + AlgorithmName, + F: CtrFlavor, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("Ctr")?; + f.write_str(F::NAME)?; + f.write_str("<")?; + ::write_alg_name(f)?; + f.write_str("> { ... }") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for CtrCore +where + C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop, + F: CtrFlavor, + F::CtrNonce: ZeroizeOnDrop, +{ +} diff --git a/vendor/ctr/src/flavors.rs b/vendor/ctr/src/flavors.rs new file mode 100644 index 00000000..30361c82 --- /dev/null +++ b/vendor/ctr/src/flavors.rs @@ -0,0 +1,44 @@ +//! CTR mode flavors + +use cipher::{ + generic_array::{ArrayLength, GenericArray}, + Counter, +}; + +mod ctr128; +mod ctr32; +mod ctr64; + +pub use ctr128::{Ctr128BE, Ctr128LE}; +pub use ctr32::{Ctr32BE, Ctr32LE}; +pub use ctr64::{Ctr64BE, Ctr64LE}; + +/// Trait implemented by different CTR flavors. +pub trait CtrFlavor> { + /// Inner representation of nonce. + type CtrNonce: Clone; + /// Backend numeric type + type Backend: Counter; + /// Flavor name + const NAME: &'static str; + + /// Return number of remaining blocks. + /// + /// If result does not fit into `usize`, returns `None`. + fn remaining(cn: &Self::CtrNonce) -> Option; + + /// Generate block for given `nonce` and current counter value. + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray; + + /// Generate block for given `nonce` and current counter value. + fn current_block(cn: &Self::CtrNonce) -> GenericArray; + + /// Initialize from bytes. + fn from_nonce(block: &GenericArray) -> Self::CtrNonce; + + /// Convert from a backend value + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend); + + /// Convert to a backend value + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend; +} diff --git a/vendor/ctr/src/flavors/ctr128.rs b/vendor/ctr/src/flavors/ctr128.rs new file mode 100644 index 00000000..9d10385d --- /dev/null +++ b/vendor/ctr/src/flavors/ctr128.rs @@ -0,0 +1,158 @@ +//! 128-bit counter falvors. +use super::CtrFlavor; +use cipher::{ + generic_array::{ArrayLength, GenericArray}, + typenum::{PartialDiv, PartialQuot, Unsigned, U16}, +}; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +type ChunkSize = U16; +type Chunks = PartialQuot; +const CS: usize = ChunkSize::USIZE; + +#[derive(Clone)] +pub struct CtrNonce128> { + ctr: u128, + nonce: GenericArray, +} + +#[cfg(feature = "zeroize")] +impl> Drop for CtrNonce128 { + fn drop(&mut self) { + self.ctr.zeroize(); + self.nonce.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl> ZeroizeOnDrop for CtrNonce128 {} + +/// 128-bit big endian counter flavor. +pub enum Ctr128BE {} + +impl CtrFlavor for Ctr128BE +where + B: ArrayLength + PartialDiv, + Chunks: ArrayLength, +{ + type CtrNonce = CtrNonce128>; + type Backend = u128; + const NAME: &'static str = "128BE"; + + #[inline] + fn remaining(cn: &Self::CtrNonce) -> Option { + (core::u128::MAX - cn.ctr).try_into().ok() + } + + #[inline(always)] + fn current_block(cn: &Self::CtrNonce) -> GenericArray { + let mut block = GenericArray::::default(); + for i in 0..Chunks::::USIZE { + let t = if i == Chunks::::USIZE - 1 { + cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes() + } else { + cn.nonce[i].to_ne_bytes() + }; + block[CS * i..][..CS].copy_from_slice(&t); + } + block + } + + #[inline] + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray { + let block = Self::current_block(cn); + cn.ctr = cn.ctr.wrapping_add(1); + block + } + + #[inline] + fn from_nonce(block: &GenericArray) -> Self::CtrNonce { + let mut nonce = GenericArray::>::default(); + for i in 0..Chunks::::USIZE { + let chunk = block[CS * i..][..CS].try_into().unwrap(); + nonce[i] = if i == Chunks::::USIZE - 1 { + u128::from_be_bytes(chunk) + } else { + u128::from_ne_bytes(chunk) + } + } + let ctr = 0; + Self::CtrNonce { ctr, nonce } + } + + #[inline] + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { + cn.ctr + } + + #[inline] + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { + cn.ctr = v; + } +} + +/// 128-bit big endian counter flavor. +pub enum Ctr128LE {} + +impl CtrFlavor for Ctr128LE +where + B: ArrayLength + PartialDiv, + Chunks: ArrayLength, +{ + type CtrNonce = CtrNonce128>; + type Backend = u128; + const NAME: &'static str = "128LE"; + + #[inline] + fn remaining(cn: &Self::CtrNonce) -> Option { + (core::u128::MAX - cn.ctr).try_into().ok() + } + + #[inline(always)] + fn current_block(cn: &Self::CtrNonce) -> GenericArray { + let mut block = GenericArray::::default(); + for i in 0..Chunks::::USIZE { + let t = if i == 0 { + cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes() + } else { + cn.nonce[i].to_ne_bytes() + }; + block[CS * i..][..CS].copy_from_slice(&t); + } + block + } + + #[inline] + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray { + let block = Self::current_block(cn); + cn.ctr = cn.ctr.wrapping_add(1); + block + } + + #[inline] + fn from_nonce(block: &GenericArray) -> Self::CtrNonce { + let mut nonce = GenericArray::>::default(); + for i in 0..Chunks::::USIZE { + let chunk = block[CS * i..][..CS].try_into().unwrap(); + nonce[i] = if i == 0 { + u128::from_le_bytes(chunk) + } else { + u128::from_ne_bytes(chunk) + } + } + let ctr = 0; + Self::CtrNonce { ctr, nonce } + } + + #[inline] + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { + cn.ctr + } + + #[inline] + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { + cn.ctr = v; + } +} diff --git a/vendor/ctr/src/flavors/ctr32.rs b/vendor/ctr/src/flavors/ctr32.rs new file mode 100644 index 00000000..17cb0116 --- /dev/null +++ b/vendor/ctr/src/flavors/ctr32.rs @@ -0,0 +1,158 @@ +//! 32-bit counter falvors. +use super::CtrFlavor; +use cipher::{ + generic_array::{ArrayLength, GenericArray}, + typenum::{PartialDiv, PartialQuot, Unsigned, U4}, +}; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +type ChunkSize = U4; +type Chunks = PartialQuot; +const CS: usize = ChunkSize::USIZE; + +#[derive(Clone)] +pub struct CtrNonce32> { + ctr: u32, + nonce: GenericArray, +} + +#[cfg(feature = "zeroize")] +impl> Drop for CtrNonce32 { + fn drop(&mut self) { + self.ctr.zeroize(); + self.nonce.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl> ZeroizeOnDrop for CtrNonce32 {} + +/// 32-bit big endian counter flavor. +pub enum Ctr32BE {} + +impl CtrFlavor for Ctr32BE +where + B: ArrayLength + PartialDiv, + Chunks: ArrayLength, +{ + type CtrNonce = CtrNonce32>; + type Backend = u32; + const NAME: &'static str = "32BE"; + + #[inline] + fn remaining(cn: &Self::CtrNonce) -> Option { + (core::u32::MAX - cn.ctr).try_into().ok() + } + + #[inline(always)] + fn current_block(cn: &Self::CtrNonce) -> GenericArray { + let mut block = GenericArray::::default(); + for i in 0..Chunks::::USIZE { + let t = if i == Chunks::::USIZE - 1 { + cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes() + } else { + cn.nonce[i].to_ne_bytes() + }; + block[CS * i..][..CS].copy_from_slice(&t); + } + block + } + + #[inline] + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray { + let block = Self::current_block(cn); + cn.ctr = cn.ctr.wrapping_add(1); + block + } + + #[inline] + fn from_nonce(block: &GenericArray) -> Self::CtrNonce { + let mut nonce = GenericArray::>::default(); + for i in 0..Chunks::::USIZE { + let chunk = block[CS * i..][..CS].try_into().unwrap(); + nonce[i] = if i == Chunks::::USIZE - 1 { + u32::from_be_bytes(chunk) + } else { + u32::from_ne_bytes(chunk) + } + } + let ctr = 0; + Self::CtrNonce { ctr, nonce } + } + + #[inline] + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { + cn.ctr + } + + #[inline] + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { + cn.ctr = v; + } +} + +/// 32-bit big endian counter flavor. +pub enum Ctr32LE {} + +impl CtrFlavor for Ctr32LE +where + B: ArrayLength + PartialDiv, + Chunks: ArrayLength, +{ + type CtrNonce = CtrNonce32>; + type Backend = u32; + const NAME: &'static str = "32LE"; + + #[inline] + fn remaining(cn: &Self::CtrNonce) -> Option { + (core::u32::MAX - cn.ctr).try_into().ok() + } + + #[inline(always)] + fn current_block(cn: &Self::CtrNonce) -> GenericArray { + let mut block = GenericArray::::default(); + for i in 0..Chunks::::USIZE { + let t = if i == 0 { + cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes() + } else { + cn.nonce[i].to_ne_bytes() + }; + block[CS * i..][..CS].copy_from_slice(&t); + } + block + } + + #[inline] + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray { + let block = Self::current_block(cn); + cn.ctr = cn.ctr.wrapping_add(1); + block + } + + #[inline] + fn from_nonce(block: &GenericArray) -> Self::CtrNonce { + let mut nonce = GenericArray::>::default(); + for i in 0..Chunks::::USIZE { + let chunk = block[CS * i..][..CS].try_into().unwrap(); + nonce[i] = if i == 0 { + u32::from_le_bytes(chunk) + } else { + u32::from_ne_bytes(chunk) + } + } + let ctr = 0; + Self::CtrNonce { ctr, nonce } + } + + #[inline] + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { + cn.ctr + } + + #[inline] + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { + cn.ctr = v; + } +} diff --git a/vendor/ctr/src/flavors/ctr64.rs b/vendor/ctr/src/flavors/ctr64.rs new file mode 100644 index 00000000..3e63abe5 --- /dev/null +++ b/vendor/ctr/src/flavors/ctr64.rs @@ -0,0 +1,158 @@ +//! 64-bit counter falvors. +use super::CtrFlavor; +use cipher::{ + generic_array::{ArrayLength, GenericArray}, + typenum::{PartialDiv, PartialQuot, Unsigned, U8}, +}; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +type ChunkSize = U8; +type Chunks = PartialQuot; +const CS: usize = ChunkSize::USIZE; + +#[derive(Clone)] +pub struct CtrNonce64> { + ctr: u64, + nonce: GenericArray, +} + +#[cfg(feature = "zeroize")] +impl> Drop for CtrNonce64 { + fn drop(&mut self) { + self.ctr.zeroize(); + self.nonce.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl> ZeroizeOnDrop for CtrNonce64 {} + +/// 64-bit big endian counter flavor. +pub enum Ctr64BE {} + +impl CtrFlavor for Ctr64BE +where + B: ArrayLength + PartialDiv, + Chunks: ArrayLength, +{ + type CtrNonce = CtrNonce64>; + type Backend = u64; + const NAME: &'static str = "64BE"; + + #[inline] + fn remaining(cn: &Self::CtrNonce) -> Option { + (core::u64::MAX - cn.ctr).try_into().ok() + } + + #[inline(always)] + fn current_block(cn: &Self::CtrNonce) -> GenericArray { + let mut block = GenericArray::::default(); + for i in 0..Chunks::::USIZE { + let t = if i == Chunks::::USIZE - 1 { + cn.ctr.wrapping_add(cn.nonce[i]).to_be_bytes() + } else { + cn.nonce[i].to_ne_bytes() + }; + block[CS * i..][..CS].copy_from_slice(&t); + } + block + } + + #[inline] + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray { + let block = Self::current_block(cn); + cn.ctr = cn.ctr.wrapping_add(1); + block + } + + #[inline] + fn from_nonce(block: &GenericArray) -> Self::CtrNonce { + let mut nonce = GenericArray::>::default(); + for i in 0..Chunks::::USIZE { + let chunk = block[CS * i..][..CS].try_into().unwrap(); + nonce[i] = if i == Chunks::::USIZE - 1 { + u64::from_be_bytes(chunk) + } else { + u64::from_ne_bytes(chunk) + } + } + let ctr = 0; + Self::CtrNonce { ctr, nonce } + } + + #[inline] + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { + cn.ctr + } + + #[inline] + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { + cn.ctr = v; + } +} + +/// 64-bit big endian counter flavor. +pub enum Ctr64LE {} + +impl CtrFlavor for Ctr64LE +where + B: ArrayLength + PartialDiv, + Chunks: ArrayLength, +{ + type CtrNonce = CtrNonce64>; + type Backend = u64; + const NAME: &'static str = "64LE"; + + #[inline] + fn remaining(cn: &Self::CtrNonce) -> Option { + (core::u64::MAX - cn.ctr).try_into().ok() + } + + #[inline(always)] + fn current_block(cn: &Self::CtrNonce) -> GenericArray { + let mut block = GenericArray::::default(); + for i in 0..Chunks::::USIZE { + let t = if i == 0 { + cn.ctr.wrapping_add(cn.nonce[i]).to_le_bytes() + } else { + cn.nonce[i].to_ne_bytes() + }; + block[CS * i..][..CS].copy_from_slice(&t); + } + block + } + + #[inline] + fn next_block(cn: &mut Self::CtrNonce) -> GenericArray { + let block = Self::current_block(cn); + cn.ctr = cn.ctr.wrapping_add(1); + block + } + + #[inline] + fn from_nonce(block: &GenericArray) -> Self::CtrNonce { + let mut nonce = GenericArray::>::default(); + for i in 0..Chunks::::USIZE { + let chunk = block[CS * i..][..CS].try_into().unwrap(); + nonce[i] = if i == 0 { + u64::from_le_bytes(chunk) + } else { + u64::from_ne_bytes(chunk) + } + } + let ctr = 0; + Self::CtrNonce { ctr, nonce } + } + + #[inline] + fn as_backend(cn: &Self::CtrNonce) -> Self::Backend { + cn.ctr + } + + #[inline] + fn set_from_backend(cn: &mut Self::CtrNonce, v: Self::Backend) { + cn.ctr = v; + } +} diff --git a/vendor/ctr/src/lib.rs b/vendor/ctr/src/lib.rs new file mode 100644 index 00000000..1199dbc9 --- /dev/null +++ b/vendor/ctr/src/lib.rs @@ -0,0 +1,90 @@ +//! Generic implementations of [CTR mode][1] for block ciphers. +//! +//! +//! +//! +//! Mode functionality is accessed using traits from re-exported [`cipher`] crate. +//! +//! # ⚠️ Security Warning: Hazmat! +//! +//! This crate does not ensure ciphertexts are authentic! Thus ciphertext integrity +//! is not verified, which can lead to serious vulnerabilities! +//! +//! # Example +//! ``` +//! use aes::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; +//! use hex_literal::hex; +//! +//! type Aes128Ctr64LE = ctr::Ctr64LE; +//! +//! let key = [0x42; 16]; +//! let iv = [0x24; 16]; +//! let plaintext = *b"hello world! this is my plaintext."; +//! let ciphertext = hex!( +//! "3357121ebb5a29468bd861467596ce3da59bdee42dcc0614dea955368d8a5dc0cad4" +//! ); +//! +//! // encrypt in-place +//! let mut buf = plaintext.to_vec(); +//! let mut cipher = Aes128Ctr64LE::new(&key.into(), &iv.into()); +//! cipher.apply_keystream(&mut buf); +//! assert_eq!(buf[..], ciphertext[..]); +//! +//! // CTR mode can be used with streaming messages +//! let mut cipher = Aes128Ctr64LE::new(&key.into(), &iv.into()); +//! for chunk in buf.chunks_mut(3) { +//! cipher.apply_keystream(chunk); +//! } +//! assert_eq!(buf[..], plaintext[..]); +//! +//! // CTR mode supports seeking. The parameter is zero-based _bytes_ counter (not _blocks_). +//! cipher.seek(0u32); +//! +//! // encrypt/decrypt from buffer to buffer +//! // buffer length must be equal to input length +//! let mut buf1 = [0u8; 34]; +//! cipher +//! .apply_keystream_b2b(&plaintext, &mut buf1) +//! .unwrap(); +//! assert_eq!(buf1[..], ciphertext[..]); +//! +//! let mut buf2 = [0u8; 34]; +//! cipher.seek(0u32); +//! cipher.apply_keystream_b2b(&buf1, &mut buf2).unwrap(); +//! assert_eq!(buf2[..], plaintext[..]); +//! ``` +//! +//! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CTR + +#![no_std] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![forbid(unsafe_code)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs, rust_2018_idioms)] + +pub mod flavors; + +mod backend; +mod ctr_core; + +pub use cipher; +pub use flavors::CtrFlavor; + +use cipher::StreamCipherCoreWrapper; +pub use ctr_core::CtrCore; + +/// CTR mode with 128-bit big endian counter. +pub type Ctr128BE = StreamCipherCoreWrapper>; +/// CTR mode with 128-bit little endian counter. +pub type Ctr128LE = StreamCipherCoreWrapper>; +/// CTR mode with 64-bit big endian counter. +pub type Ctr64BE = StreamCipherCoreWrapper>; +/// CTR mode with 64-bit little endian counter. +pub type Ctr64LE = StreamCipherCoreWrapper>; +/// CTR mode with 32-bit big endian counter. +pub type Ctr32BE = StreamCipherCoreWrapper>; +/// CTR mode with 32-bit little endian counter. +pub type Ctr32LE = StreamCipherCoreWrapper>; diff --git a/vendor/ctr/tests/ctr128/data/aes128-ctr.blb b/vendor/ctr/tests/ctr128/data/aes128-ctr.blb new file mode 100644 index 00000000..d721e4ec Binary files /dev/null and b/vendor/ctr/tests/ctr128/data/aes128-ctr.blb differ diff --git a/vendor/ctr/tests/ctr128/data/aes256-ctr.blb b/vendor/ctr/tests/ctr128/data/aes256-ctr.blb new file mode 100644 index 00000000..47daaf84 Binary files /dev/null and b/vendor/ctr/tests/ctr128/data/aes256-ctr.blb differ diff --git a/vendor/ctr/tests/ctr128/mod.rs b/vendor/ctr/tests/ctr128/mod.rs new file mode 100644 index 00000000..c5e02068 --- /dev/null +++ b/vendor/ctr/tests/ctr128/mod.rs @@ -0,0 +1,12 @@ +use aes::{Aes128, Aes256}; +use ctr::{flavors, Ctr128BE, CtrCore}; + +cipher::stream_cipher_test!(aes128_ctr_core, "aes128-ctr", Ctr128BE); +cipher::stream_cipher_test!(aes256_ctr_core, "aes256-ctr", Ctr128BE); +cipher::stream_cipher_seek_test!(aes128_ctr_seek, Ctr128BE); +cipher::stream_cipher_seek_test!(aes256_ctr_seek, Ctr128BE); +cipher::iv_state_test!( + aes128_ctr_iv_state, + CtrCore, + apply_ks, +); diff --git a/vendor/ctr/tests/ctr32/be.rs b/vendor/ctr/tests/ctr32/be.rs new file mode 100644 index 00000000..98b13022 --- /dev/null +++ b/vendor/ctr/tests/ctr32/be.rs @@ -0,0 +1,86 @@ +//! Counter Mode with a 32-bit big endian counter + +use cipher::{KeyIvInit, StreamCipher, StreamCipherSeek, StreamCipherSeekCore}; +use hex_literal::hex; + +type Aes128Ctr = ctr::Ctr32BE; + +const KEY: &[u8; 16] = &hex!("000102030405060708090A0B0C0D0E0F"); +const NONCE1: &[u8; 16] = &hex!("11111111111111111111111111111111"); +const NONCE2: &[u8; 16] = &hex!("222222222222222222222222FFFFFFFE"); + +#[test] +fn counter_incr() { + let mut ctr = Aes128Ctr::new(KEY.into(), NONCE1.into()); + assert_eq!(ctr.get_core().get_block_pos(), 0); + + let mut buffer = [0u8; 64]; + ctr.apply_keystream(&mut buffer); + + assert_eq!(ctr.get_core().get_block_pos(), 4); + assert_eq!( + &buffer[..], + &hex!( + "35D14E6D3E3A279CF01E343E34E7DED36EEADB04F42E2251AB4377F257856DBA" + "0AB37657B9C2AA09762E518FC9395D5304E96C34CCD2F0A95CDE7321852D90C0" + )[..] + ); +} + +#[test] +fn counter_seek() { + let mut ctr = Aes128Ctr::new(KEY.into(), NONCE1.into()); + ctr.seek(16); + assert_eq!(ctr.get_core().get_block_pos(), 1); + + let mut buffer = [0u8; 64]; + ctr.apply_keystream(&mut buffer); + + assert_eq!(ctr.get_core().get_block_pos(), 5); + assert_eq!( + &buffer[..], + &hex!( + "6EEADB04F42E2251AB4377F257856DBA0AB37657B9C2AA09762E518FC9395D53" + "04E96C34CCD2F0A95CDE7321852D90C0F7441EAB3811A03FDBD162AEC402F5AA" + )[..] + ); +} + +#[test] +fn keystream_xor() { + let mut ctr = Aes128Ctr::new(KEY.into(), NONCE1.into()); + let mut buffer = [1u8; 64]; + + ctr.apply_keystream(&mut buffer); + assert_eq!( + &buffer[..], + &hex!( + "34D04F6C3F3B269DF11F353F35E6DFD26FEBDA05F52F2350AA4276F356846CBB" + "0BB27756B8C3AB08772F508EC8385C5205E86D35CDD3F1A85DDF7220842C91C1" + )[..] + ); +} + +#[test] +fn counter_wrap() { + let mut ctr = Aes128Ctr::new(KEY.into(), NONCE2.into()); + assert_eq!(ctr.get_core().get_block_pos(), 0); + + let mut buffer = [0u8; 64]; + ctr.apply_keystream(&mut buffer); + + assert_eq!(ctr.get_core().get_block_pos(), 4); + assert_eq!( + &buffer[..], + &hex!( + "58FC849D1CF53C54C63E1B1D15CB3C8AAA335F72135585E9FF943F4DAC77CB63" + "BD1AE8716BE69C3B4D886B222B9B4E1E67548EF896A96E2746D8CA6476D8B183" + )[..] + ); +} + +cipher::iv_state_test!( + iv_state, + ctr::CtrCore, + apply_ks, +); diff --git a/vendor/ctr/tests/ctr32/le.rs b/vendor/ctr/tests/ctr32/le.rs new file mode 100644 index 00000000..21bf3583 --- /dev/null +++ b/vendor/ctr/tests/ctr32/le.rs @@ -0,0 +1,96 @@ +//! Counter Mode with a 32-bit little endian counter + +use cipher::{ + consts::U16, generic_array::GenericArray, KeyIvInit, StreamCipher, StreamCipherSeek, + StreamCipherSeekCore, +}; +use hex_literal::hex; + +type Aes128Ctr = ctr::Ctr32LE; + +const KEY: &[u8; 16] = &hex!("000102030405060708090A0B0C0D0E0F"); +const NONCE1: &[u8; 16] = &hex!("11111111111111111111111111111111"); +const NONCE2: &[u8; 16] = &hex!("FEFFFFFF222222222222222222222222"); + +/// Compute nonce as used by AES-GCM-SIV +fn nonce(bytes: &[u8; 16]) -> GenericArray { + let mut n = *bytes; + n[15] |= 0x80; + n.into() +} + +#[test] +fn counter_incr() { + let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE1)); + assert_eq!(ctr.get_core().get_block_pos(), 0); + + let mut buffer = [0u8; 64]; + ctr.apply_keystream(&mut buffer); + + // assert_eq!(ctr.current_ctr(), 4); + assert_eq!( + &buffer[..], + &hex!( + "2A0680B210CAD45E886D7EF6DAB357C9F18B39AFF6930FDB2D9FCE34261FF699" + "EB96774669D24B560C9AD028C5C39C4580775A82065256B4787DC91C6942B700" + )[..] + ); +} + +#[test] +fn counter_seek() { + let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE1)); + ctr.seek(16); + assert_eq!(ctr.get_core().get_block_pos(), 1); + + let mut buffer = [0u8; 64]; + ctr.apply_keystream(&mut buffer); + + assert_eq!(ctr.get_core().get_block_pos(), 5); + assert_eq!( + &buffer[..], + &hex!( + "F18B39AFF6930FDB2D9FCE34261FF699EB96774669D24B560C9AD028C5C39C45" + "80775A82065256B4787DC91C6942B7001564DDA1B07DCED9201AB71BAF06905B" + )[..] + ); +} + +#[test] +fn keystream_xor() { + let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE1)); + let mut buffer = [1u8; 64]; + + ctr.apply_keystream(&mut buffer); + assert_eq!( + &buffer[..], + &hex!( + "2B0781B311CBD55F896C7FF7DBB256C8F08A38AEF7920EDA2C9ECF35271EF798" + "EA97764768D34A570D9BD129C4C29D4481765B83075357B5797CC81D6843B601" + )[..] + ); +} + +#[test] +fn counter_wrap() { + let mut ctr = Aes128Ctr::new(KEY.into(), &nonce(NONCE2)); + assert_eq!(ctr.get_core().get_block_pos(), 0); + + let mut buffer = [0u8; 64]; + ctr.apply_keystream(&mut buffer); + + assert_eq!(ctr.get_core().get_block_pos(), 4); + assert_eq!( + &buffer[..], + &hex!( + "A1E649D8B382293DC28375C42443BB6A226BAADC9E9CCA8214F56E07A4024E06" + "6355A0DA2E08FB00112FFA38C26189EE55DD5B0B130ED87096FE01B59A665A60" + )[..] + ); +} + +cipher::iv_state_test!( + iv_state, + ctr::CtrCore, + apply_ks, +); diff --git a/vendor/ctr/tests/ctr32/mod.rs b/vendor/ctr/tests/ctr32/mod.rs new file mode 100644 index 00000000..f9c17d41 --- /dev/null +++ b/vendor/ctr/tests/ctr32/mod.rs @@ -0,0 +1,9 @@ +//! Counter Mode with a 32-bit counter. +//! +//! NOTE: AES-128-CTR test vectors used by these tests were generated by first +//! integration testing the implementation in the contexts of AES-GCM and +//! AES-GCM-SIV, with the former tested against the NIST CAVS vectors, and the +//! latter against the RFC8452 test vectors. + +mod be; +mod le; diff --git a/vendor/ctr/tests/gost/mod.rs b/vendor/ctr/tests/gost/mod.rs new file mode 100644 index 00000000..31e5cec8 --- /dev/null +++ b/vendor/ctr/tests/gost/mod.rs @@ -0,0 +1,55 @@ +use cipher::{KeyIvInit, StreamCipher}; +use hex_literal::hex; + +type MagmaCtr = ctr::Ctr32BE; +type KuznyechikCtr = ctr::Ctr64BE; + +/// Test vectors from GOST R 34.13-2015 (Section A.1.2) +#[test] +fn kuznyechik() { + let key = hex!( + "8899aabbccddeeff0011223344556677" + "fedcba98765432100123456789abcdef" + ); + let nonce = hex!("1234567890abcef00000000000000000"); + let mut pt = hex!( + "1122334455667700ffeeddccbbaa9988" + "00112233445566778899aabbcceeff0a" + "112233445566778899aabbcceeff0a00" + "2233445566778899aabbcceeff0a0011" + ); + let ct = hex!( + "f195d8bec10ed1dbd57b5fa240bda1b8" + "85eee733f6a13e5df33ce4b33c45dee4" + "a5eae88be6356ed3d5e877f13564a3a5" + "cb91fab1f20cbab6d1c6d15820bdba73" + ); + let mut cipher = KuznyechikCtr::new(&key.into(), &nonce.into()); + cipher.apply_keystream(&mut pt); + assert_eq!(pt[..], ct[..]); +} + +/// Test vectors from GOST R 34.13-2015 (Section A.2.2) +#[test] +fn magma() { + let key = hex!( + "ffeeddccbbaa99887766554433221100" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" + ); + let nonce = hex!("1234567800000000"); + let mut pt = hex!( + "92def06b3c130a59" + "db54c704f8189d20" + "4a98fb2e67a8024c" + "8912409b17b57e41" + ); + let ct = hex!( + "4e98110c97b7b93c" + "3e250d93d6e85d69" + "136d868807b2dbef" + "568eb680ab52a12d" + ); + let mut cipher = MagmaCtr::new(&key.into(), &nonce.into()); + cipher.apply_keystream(&mut pt); + assert_eq!(pt[..], ct[..]); +} diff --git a/vendor/ctr/tests/mod.rs b/vendor/ctr/tests/mod.rs new file mode 100644 index 00000000..0f91835c --- /dev/null +++ b/vendor/ctr/tests/mod.rs @@ -0,0 +1,5 @@ +//! Counter Mode Tests + +mod ctr128; +mod ctr32; +mod gost; diff --git a/vendor/darling/.cargo-checksum.json b/vendor/darling/.cargo-checksum.json new file mode 100644 index 00000000..40b1c2ac --- /dev/null +++ b/vendor/darling/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"8203eb1635e94607747e1436bd307188f2b1153e6576de00bed9406a3deeb576","Cargo.lock":"d6e704c34bf3603d43bac7ba53e9552657f0c71e1001108105febba35c820ee9","Cargo.toml":"c936b39311a25e46d2b0a5b0f97555e7f915722b223e6b1ecf826c55d9ddd949","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","README.md":"1bdf52bf0ff33a70bb3130e749394d63577921a17bd8ab2ef0ecb3b0e9f551e4","clippy.toml":"c5ef3489cce9d5ed7c766e6486a18a0a3dc0f4c677fcf05166e1d47104f6cd3f","compiletests.sh":"a255ae505d79b4a40bdc80b215a5384eadee228593d042fbed60e99cc278e220","examples/automatic_bounds.rs":"2950c8d33bb40f095decba1990d7d0bcd48dffc6e9b7cefce2fcb3818ecf1d18","examples/consume_fields.rs":"ce436936441f1f6734f47074e6625ebf64f15180b9c126a58e24aaa33613b59c","examples/expr_with.rs":"6398d6bea0003a4d06859a0e80b97367c787c556bf91f3ad83c8fa9645e3a7d9","examples/fallible_read.rs":"a71e00798911c355cd63eddd3a08c24c5f752357c3246968167af958846b1e02","examples/heterogeneous_enum_and_word.rs":"1c3b9dc2fa90e343d8ea4afa66751ce5687492b600ba4df3eb1e70ba2cf70a72","examples/shorthand_or_long_field.rs":"ec2e2b155fd0803c80f98d0ba94e8419dd7307012ccfb916b8f752925a295d55","examples/supports_struct.rs":"08c5cc46400a0e5cf811c0d254a37b42de94b34cd04ac801069105bc792051f6","src/lib.rs":"fe1bbb1932c450dc3ccaa19fa8043a49d9179fa1a02cc805ca86897098b3afe8","src/macros_public.rs":"7d2ce0c5026227ef7854db11d7a885ad891255438b2e49bbdfda56fa2f92feec","tests/accrue_errors.rs":"4f0f5be65c5cd639b107a6a14e9fb51573b27cfa9210a2182fa5f450bc1d56db","tests/attrs_with.rs":"81a24bfdbcd0f0797790cd38ee8093dce6b8b9a37354936a7b0c48121f4c7a74","tests/compile-fail/attrs_with_bad_fn.rs":"70ab2eee7619caaf9a05e0dc0f68ef41d396244dc373bf5a63b5756e754267cc","tests/compile-fail/attrs_with_bad_fn.stderr":"378040af23da6bb6f800e36e2f52bc90aa937363cc90507ba4c505cfe17fcae8","tests/compile-fail/default_expr_wrong_type.rs":"e09889ac3a243bd6096a0ef7076822b146f1481b70aae703e170ea6527071448","tests/compile-fail/default_expr_wrong_type.stderr":"9c7971d8aaf92e683fa5fa698d172fd735bda553f6e70303a6105b81800b53de","tests/compile-fail/duplicate_word_across_variants.rs":"741d879dfe4d1ba630d6c773a32a20135bb9d7e7aa0bc35a604d9a73db967872","tests/compile-fail/duplicate_word_across_variants.stderr":"e25d86df4bd5b558c6588688171767e234ffd3a859b942b6573cf74c0eafd2b8","tests/compile-fail/duplicate_word_on_variant.rs":"eac1353adb1e453f97e7f7014e0a6e3126ceb1650ca049d10a7fbaeaf0997c9e","tests/compile-fail/duplicate_word_on_variant.stderr":"8ba3499b81db67ac00b69b43572fa870fdfaa2b6831d47c0b611a00f1f563885","tests/compile-fail/flatten_meta_conflicts.rs":"daf9a4d71cf9aa079979b492dd0a2f0d98d58ff65aa512a40496faa40246231d","tests/compile-fail/flatten_meta_conflicts.stderr":"6278b76248c56ff41256b452acdab6be81c202f5d60e222a86f955eb4cbf664c","tests/compile-fail/flatten_multiple_fields.rs":"359291f3ddbcab89fd8cbe8f09bd7d03ad7c4bf77142027e9df8e6bbd6e400e7","tests/compile-fail/flatten_multiple_fields.stderr":"f9395a26eef518946d09d270fcff9fe8c7e209cb6168fb6d113837d447e04f60","tests/compile-fail/not_impl_from_meta.rs":"20ef167d88ea06967c26a05234d3b1787f0695d45b4ab1150bf9dc77625f9c74","tests/compile-fail/not_impl_from_meta.stderr":"d945e09111b290f2fa7227332da193fec99ad4ebdcb5f0a4364e3d0c9b0dffed","tests/compile-fail/skip_field_not_impl_default.rs":"5cb7e2e68d7dc42e6508eb0c170869179f127cf641b44f08f6403760f30c469b","tests/compile-fail/skip_field_not_impl_default.stderr":"9f66e34ce32cbab54776006fc03bb776ec4d4a6ed6310139ea66c7cf7ae9920e","tests/compile-fail/word_on_wrong_variant_type.rs":"1f83eaca4da3187d411926d2fef907e7d7000479c326012f8f9fc0ee5be26411","tests/compile-fail/word_on_wrong_variant_type.stderr":"edd5f2ffecdc8dc2c5f3edd5061682ed278a1276f4a9781fd7aeae1c37aca41a","tests/compiletests.rs":"71644363704ae87461895bb107f427128148af8addcd7bb2c745cdf4287dac1a","tests/computed_bound.rs":"aed9c00f2b8373e9426337137207e5b9341d236adef682bd2c9427db9ce1d1ff","tests/custom_bound.rs":"9b823063b7fc6c6b3b23905405ce7f316e8a937d5c67c416b89642e537bf9110","tests/defaults.rs":"078b79f5a1b405ce9ddc9dd847afb674c2f36d27f85fc68ed61efebaef5dd0f7","tests/enums_default.rs":"a545f80f3ab1201886d6409737c98fc875e2baf9d41827220c7b2262c9273be3","tests/enums_newtype.rs":"073c8087ef3a43065b2dfd23192d68789a7226f2babae3bceb3db1e7d7d946da","tests/enums_struct.rs":"36ca3d4996644d566b45c78d8c343c4a74fcaa2eba96b4e012c8a1819eb6f4c6","tests/enums_unit.rs":"7f94f793e6adc265c6cdc4b657aa237da1ab0be03b03bce23d3e2180cd3e8d03","tests/error.rs":"f5f84991472e184e1167f0fe8d5f2cbad3844c4022987c9eff46b4db2bcc804a","tests/flatten.rs":"59303a72b38a27dc881f885ea77163a1f0e9b5adcf38fa761a2debed83cd0bd2","tests/flatten_error_accumulation.rs":"31427b0a94419c4d6d1aa52593fb97fd757a7124c55b93e723ce893abcdaf2d4","tests/flatten_from_field.rs":"b9cb26790319e1b08528180fe8ba5f0b720ea9003ab57389842aec0737a1355e","tests/forward_attrs_to_from_attributes.rs":"2d2a97a1001cfe878ce6c638b5dd98b344375bf5e90a43bf0a7494f58150a596","tests/from_generics.rs":"8be63cc3390e94f2740932dea280c8c44d929a1fcc2cfff68cec4d3bceadc4d9","tests/from_meta.rs":"5545ecf1ced0395fd02d646f3a9d612ecc2b1a71a674786f770085ce55013f60","tests/from_type_param.rs":"94d2766d5ae11d69750497225d6aa3c2f34b09fbc8c3580d61f077d7bb41265b","tests/from_type_param_default.rs":"e00e2f0c779753f66b95e5c0106451f65cbd6fbc28e676381d276290da6254b6","tests/from_variant.rs":"48046b156f6c5d9b3e9c3d0b36b5eebaba1d417447e3babf81ed9c74bee3bfcb","tests/generics.rs":"0c2830acf511148d71ecd4a8b5aa17f80e377aa89f7fe0fc10f6db34671d034a","tests/happy_path.rs":"c7a540fc1755cef757aa5e6cd202a49a47a2040facb0c05c167ec62f8ebbc557","tests/hash_map.rs":"2559783b10108a975466b6944ed89737be6197c64a35c66cfad43a272c085a01","tests/multiple.rs":"1362ec057f4796ffabf7161033b561b51f069b818af7bac85fe66935c62038dd","tests/newtype.rs":"b5ecf605652b194372cab6d6fef96a2dd4b63ac24649cb52ca944ef9647512ad","tests/skip.rs":"11b5f190d6eac837d4a44a7dedd1ba9e623b0c7a8bf2bdc92882e1f8a8d2aeac","tests/split_declaration.rs":"019863370414af227144aac13272fc39a1e256a9ed0bd3ca2dbf1114f1a9e1ba","tests/suggestions.rs":"cffd07a3e4f9b37ec9f907e3c80b16e2714f9129c9adb7bab70f863828556136","tests/supports.rs":"fd27b20893a1b1078eff077d426fea7d715b8decd12ad1e0b940cfbfd4fbbfba","tests/unsupported_attributes.rs":"c7adf2bb86a2dcef8b49da3bd50ea6038e3745ac636a5d2de815964f98e71225"},"package":"6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"} \ No newline at end of file diff --git a/vendor/darling/CHANGELOG.md b/vendor/darling/CHANGELOG.md new file mode 100644 index 00000000..1e213ffa --- /dev/null +++ b/vendor/darling/CHANGELOG.md @@ -0,0 +1,314 @@ +# Changelog + +## v0.20.10 (July 9, 2024) + +- Add `#[allow(clippy::manual_unwrap_or_default)]` to all generated impls to avoid causing clippy fails in crates using `darling` [#296](https://github.com/TedDriggs/darling/pull/296) +- Properly initialize `attrs` magic field in derived `FromAttributes` impls [#297](https://github.com/TedDriggs/darling/pull/297) + +## v0.20.9 (May 15, 2024) + +- Allow word-form for newtype enum variants whose only field produces a value when `from_none` is called on their type [#249](https://github.com/TedDriggs/darling/issues/249) +- Add `FromMeta` impls for the `std::num::NonZero*` types [#288](https://github.com/TedDriggs/darling/pull/288) +- Fix panic in number `FromMeta` impls when the parsed value is too large for the receiver type [#289](https://github.com/TedDriggs/darling/issues/289) + +## v0.20.8 (February 23, 2024) + +- Add `#[darling(with = ...)]` support to `attrs` magic field to allow using custom receiver types for `attrs` [#273](https://github.com/TedDriggs/darling/issues/273) + +## v0.20.7 (February 22, 2024) + +- Add `#[darling(flatten)]` to allow forwarding unknown fields to another struct [#146](https://github.com/TedDriggs/darling/issues/146) +- Don't suggest names of skipped fields in derived impls [#268](https://github.com/TedDriggs/darling/issues/268) + +## v0.20.6 (February 14, 2024) + +- Fix some missing syn invisible group handling in `FromMeta` impls [#263](https://github.com/TedDriggs/darling/pull/263) +- Fix misleading error message on `Error::unexpected_type` so it no longer implies the type was a literal [#264](https://github.com/TedDriggs/darling/pull/264) +- Impl `FromMeta` `Vec` of literals, e.g. `LitStr` [#265](https://github.com/TedDriggs/pull/265) + +## v0.20.5 (January 30, 2024) + +- Add `Flag::span` inherent method, as `Flag` can no longer impl `syn::spanned::Spanned` [#242](https://github.com/TedDriggs/darling/issues/242) + +## v0.20.4 (January 29, 2024) + +- Accept bare paths in `#[darling(default = ...)]` [#258](https://github.com/TedDriggs/darling/pull/258) +- Add `FromMeta` impl for `PathBuf` [#259](https://github.com/TedDriggs/darling/pull/259) +- Improve `FromMeta` implementation for enums [#260](https://github.com/TedDriggs/darling/pull/260) + - Properly implement unit arms in `FromMeta::from_list` to provide a consistent API for heterogeneous enums that include a mix of unit, newtype and struct variants + - Add `#[darling(word)]` attribute for unit enum variants (See [#63](https://github.com/TedDriggs/darling/issues/63) for details) + +## v0.20.3 (July 12, 2023) + +- Add `FromMeta` impl for `u128` and `i128` [#243](https://github.com/TedDriggs/darling/pull/243) + +## v0.20.2 (May 25, 2023) + +- Allow darling users to omit quotation marks for paths and idents [#236](https://github.com/TedDriggs/darling/pull/236) +- Add new util functions for controlling how quotation marks are handled when reading into `Expr` fields [#235](https://github.com/TedDriggs/darling/pull/235) + +## v0.20.1 (May 2, 2023) + +- Add `Clone` impl for `NestedMeta` [#230](https://github.com/TedDriggs/darling/pull/230) + +## v0.20.0 (April 27, 2023) + +- Bump syn to version 2, courtesy of @jonasbb [#227](https://github.com/TedDriggs/darling/issues/227) + +### Breaking Changes + +- Replace all occurrences of syn::NestedMeta with darling::ast::NestedMeta. + +- Replacement for the deprecated AttributeArgs: + +```rust +// Before + +parse_macro_input!(args as AttributeArgs); + +// After + +match NestedMeta::parse_meta_list(args) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(Error::from(e).write_errors()); + } +}; +``` + +- In GenericParamExt, `LifetimeDef` is now `LifetimeParam`. +- In GenericParamExt, `as_lifetime_def` is renamed to `as_lifetime_param`. +- Flag and SpannedValue no longer implement `syn::spanned::Spanned`. +- The MSRV (minimum supported Rust version) is now 1.56, because of syn. + +### Deprecation Warnings + +In previous versions of `darling`, arbitrary expressions were passed in attributes by wrapping them in quotation marks. +v0.20.0 preserves this behavior for `syn::Expr`, but as a result a field expecting a `syn::Expr` cannot accept a string literal - it will incorrectly attempt to parse the contents. If this is an issue for you, please add a comment to [#229](https://github.com/TedDriggs/darling/issues/229). + +## v0.14.4 (March 9, 2023) + +- Add support for child diagnostics when `diagnostics` feature enabled [#224](https://github.com/TedDriggs/darling/issues/224) + +## v0.14.3 (February 3, 2023) + +- Re-export `syn` from `darling` to avoid requiring that consuming crates have a `syn` dependency. +- Change ` as FromMeta>` impl to more precisely capture the _value_ span, as opposed to the span of the entire item. +- Add `darling::util::{AsShape, Shape, ShapeSet}` to improve "shape" validation for structs and variants. [#222](https://github.com/TedDriggs/issues/222) + +## v0.14.2 (October 26, 2022) + +- Derived impls of `FromMeta` will now error on literals, rather than silently ignoring them. [#193](https://github.com/TedDriggs/darling/pull/193) +- Don't include property paths in compile errors when spans are available. [#203](https://github.com/TedDriggs/darling/pull/203) + +## v0.14.1 (April 28, 2022) + +- Fix a bug where using a trait that accepts `#[darling(attributes(...))]` without specifying any attributes would emit code that did not compile. [#183](https://github.com/TedDriggs/darling/issues/183) +- Impl `Clone` for `darling::Error` [#184](https://github.com/TedDriggs/darling/pull/184) +- Impl `From for syn::Error` [#184](https://github.com/TedDriggs/darling/pull/184) +- Add `Error::span` and `Error::explicit_span` methods [#184](https://github.com/TedDriggs/darling/pull/184) + +## v0.14.0 (April 13, 2022) + +- **BREAKING CHANGE:** Remove many trait impls from `util::Flag`. + This type had a number of deref and operator impls that made it usable as sort-of-a-boolean. + Real-world usage showed this type is more useful if it's able to carry a span for good errors, + and that most of those impls were unnecessary. [#179](https://github.com/TedDriggs/darling/pull/179) +- Remove need for `#[darling(default)]` on `Option` and `Flag` fields [#161](https://github.com/TedDriggs/darling/issues/161) +- Improve validation of enum shapes [#178](https://github.com/TedDriggs/darling/pull/178) +- Bump `proc-macro2` dependency to 1.0.37 [#180](https://github.com/TedDriggs/darling/pull/180) +- Bump `quote` dependency to 1.0.18 [#180](https://github.com/TedDriggs/darling/pull/180) +- Bump `syn` dependency to 1.0.91 [#180](https://github.com/TedDriggs/darling/pull/180) + +## v0.13.4 (April 6, 2022) + +- Impl `FromMeta` for `syn::Visibility` [#173](https://github.com/TedDriggs/darling/pull/173) + +## v0.13.3 (April 5, 2022) + +- Add `error::Accumulator` for dealing with multiple errors [#164](https://github.com/TedDriggs/darling/pull/164) +- Impl `FromMeta` for `syn::Type` and its variants [#172](https://github.com/TedDriggs/darling/pulls/172) + +## v0.13.2 (March 30, 2022) + +- Impl `FromMeta` for `syn::ExprPath` [#169](https://github.com/TedDriggs/darling/issues/169) + +## v0.13.1 (December 7, 2021) + +- Add `FromAttributes` trait and macro [#151](https://github.com/TedDriggs/darling/issues/151) + +## v0.13.0 (May 20, 2021) + +- Update darling to 2018 edition [#129](https://github.com/TedDriggs/darling/pull/129) +- Error on duplicate fields in `#[darling(...)]` attributes [#130](https://github.com/TedDriggs/darling/pull/130) +- Impl `Copy` for `SpannedValue` +- Add `SpannedValue::map_ref` + +## v0.13.0-beta (April 20, 2021) + +- Update darling to 2018 edition [#129](https://github.com/TedDriggs/darling/pull/129) +- Error on duplicate fields in `#[darling(...)]` attributes [#130](https://github.com/TedDriggs/darling/pull/130) + +## v0.12.4 (April 20, 2021) + +- Add `and_then` to derive macros for `darling` + +## v0.12.3 (April 8, 2021) + +- Fix `FromMeta` impl for `char` not to panic [#126](https://github.com/TedDriggs/darling/pull/126) + +## v0.12.2 (February 23, 2021) + +- Impl `FromMeta` for `HashMap` and `HashMap` + +## v0.12.1 (February 22, 2021) + +- Impl `FromMeta` for `syn::ExprArray` [#122](https://github.com/TedDriggs/darling/pull/122) +- Remove use of `unreachable` from `darling::ast::Data` [#123](https://github.com/TedDriggs/darling/pull/123) +- Add `darling::ast::Data::try_empty_from` to avoid panics when trying to read a union body [#123](https://github.com/TedDriggs/darling/pull/123) + +## v0.12.0 (January 5, 2021) + +- POSSIBLY BREAKING: Derived impls of `FromDeriveInput`, `FromField`, `FromVariant`, and `FromTypeParam` will now error when encountering an attribute `darling` has been asked to parse that isn't a supported shape. + Any crates using `darling` that relied on those attributes being silently ignored could see new errors reported in their dependent crates. [#113](https://github.com/TedDriggs/darling/pull/113) +- Impl `syn::spanned::Spanned` for `darling::util::SpannedValue` [#113](https://github.com/TedDriggs/darling/pull/113) +- Add `darling::util::parse_attribute_to_meta_list` to provide useful errors during attribute parsing [#113](https://github.com/TedDriggs/darling/pull/113) +- Add `impl From for Error` to losslessly propagate `syn` errors [#116](https://github.com/TedDriggs/darling/pull/116) + +## v0.11.0 (December 14, 2020) + +- Bump minor version due to unexpected breaking change [#107](https://github.com/TedDriggs/darling/issues/107) + +## v0.10.3 (December 10, 2020) + +- Add `discriminant` magic field when deriving `FromVariant` [#105](https://github.com/TedDriggs/darling/pull/105) + +## v0.10.2 (October 30, 2019) + +- Bump syn dependency to 1.0.1 [#83](https://github.com/TedDriggs/darling/pull/83) + +## v0.10.1 (September 25, 2019) + +- Fix test compilation errors [#81](https://github.com/TedDriggs/darling/pull/81) + +## v0.10.0 (August 15, 2019) + +- Bump syn and quote to 1.0 [#79](https://github.com/TedDriggs/darling/pull/79) +- Increase rust version to 1.31 + +## v0.9.0 (March 20, 2019) + +- Enable "did you mean" suggestions by default +- Make `darling_core::{codegen, options}` private [#58](https://github.com/TedDriggs/darling/issues/58) +- Fix `Override::as_mut`: [#66](https://github.com/TedDriggs/darling/issues/66) + +## v0.8.6 (March 18, 2019) + +- Added "did you mean" suggestions for unknown fields behind the `suggestions` flag [#60](https://github.com/TedDriggs/issues/60) +- Added `Error::unknown_field_with_alts` to support the suggestion use-case. +- Added `ast::Fields::len` and `ast::Fields::is_empty` methods. + +## v0.8.5 (February 4, 2019) + +- Accept unquoted positive numeric literals [#52](https://github.com/TedDriggs/issues/52) +- Add `FromMeta` to the `syn::Lit` enum and its variants +- Improve error message for unexpected literal formats to not say "other" + +## v0.8.4 (February 4, 2019) + +- Use `syn::Error` to provide precise errors before `proc_macro::Diagnostic` is available +- Add `diagnostics` feature flag to toggle between stable and unstable error backends +- Attach error information in more contexts +- Add `allow_unknown_fields` to support parsing the same attribute multiple times for different macros [#51](https://github.com/darling/issues/51) +- Proc-macro authors will now see better errors in `darling` attributes + +## v0.8.3 (January 21, 2019) + +- Attach spans to errors in generated trait impls [#37](https://github.com/darling/issues/37) +- Attach spans to errors for types with provided bespoke implementations +- Deprecate `set_span` from 0.8.2, as spans should never be broadened after being initially set + +## v0.8.2 (January 17, 2019) + +- Add spans to errors to make quality warnings and errors easy in darling. This is blocked on diagnostics stabilizing. +- Add `darling::util::SpannedValue` so proc-macro authors can remember position information alongside parsed values. + +## v0.8.0 + +- Update dependency on `syn` to 0.15 [#44](https://github.com/darling/pull/44). Thanks to @hcpl + +## v0.7.0 (July 24, 2018) + +- Update dependencies on `syn` and `proc-macro2` +- Add `util::IdentString`, which acts as an Ident or its string equivalent + +## v0.6.3 (May 22, 2018) + +- Add support for `Uses*` traits in where predicates + +## v0.6.2 (May 22, 2018) + +- Add `usage` module for tracking type param and lifetime usage in generic declarations + - Add `UsesTypeParams` and `CollectsTypeParams` traits [#37](https://github.com/darling/issues/37) + - Add `UsesLifetimes` and `CollectLifetimes` traits [#41](https://github.com/darling/pull/41) +- Don't add `FromMeta` bounds to type parameters only used by skipped fields [#40](https://github.com/darling/pull/40) + +## v0.6.1 (May 17, 2018) + +- Fix an issue where the `syn` update broke shape validation [#36](https://github.com/TedDriggs/darling/issues/36) + +## v0.6.0 (May 15, 2018) + +### Breaking Changes + +- Renamed `FromMetaItem` to `FromMeta`, and renamed `from_meta_item` method to `from_meta` +- Added dedicated `derive(FromMetaItem)` which panics and redirects users to `FromMeta` + +## v0.5.0 (May 10, 2018) + +- Add `ast::Generics` and `ast::GenericParam` to work with generics in a manner similar to `ast::Data` +- Add `ast::GenericParamExt` to support alternate representations of generic parameters +- Add `util::WithOriginal` to get a parsed representation and syn's own struct for a syntax block +- Add `FromGenerics` and `FromGenericParam` traits (without derive support) +- Change generated code for `generics` magic field to invoke `FromGenerics` trait during parsing +- Add `FromTypeParam` trait [#30](https://github.com/TedDriggs/darling/pull/30). Thanks to @upsuper + +## v0.4.0 (April 5, 2018) + +- Update dependencies on `proc-macro`, `quote`, and `syn` [#26](https://github.com/TedDriggs/darling/pull/26). Thanks to @hcpl + +## v0.3.3 (April 2, 2018) + +**YANKED** + +## v0.3.2 (March 13, 2018) + +- Derive `Default` on `darling::Ignored` (fixes [#25](https://github.com/TedDriggs/darling/issues/25)). + +## v0.3.1 (March 7, 2018) + +- Support proc-macro2/nightly [#24](https://github.com/TedDriggs/darling/pull/24). Thanks to @kdy1 + +## v0.3.0 (January 26, 2018) + +### Breaking Changes + +- Update `syn` to 0.12 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong +- Update `quote` to 0.4 [#20](https://github.com/TedDriggs/darling/pull/20). Thanks to @Eijebong +- Rename magic field `body` in derived `FromDeriveInput` structs to `data` to stay in sync with `syn` +- Rename magic field `data` in derived `FromVariant` structs to `fields` to stay in sync with `syn` + +## v0.2.2 (December 5, 2017) + +- Update `lazy_static` to 1.0 [#15](https://github.com/TedDriggs/darling/pull/16). Thanks to @Eijebong + +## v0.2.1 (November 28, 2017) + +- Add `impl FromMetaItem` for integer types [#15](https://github.com/TedDriggs/darling/pull/15) + +## v0.2.0 (June 18, 2017) + +- Added support for returning multiple errors from parsing [#5](https://github.com/TedDriggs/darling/pull/5) +- Derived impls no longer return on first error [#5](https://github.com/TedDriggs/darling/pull/5) +- Removed default types for `V` and `F` from `ast::Body` +- Enum variants are automatically converted to snake_case [#12](https://github.com/TedDriggs/darling/pull/12) diff --git a/vendor/darling/Cargo.lock b/vendor/darling/Cargo.lock new file mode 100644 index 00000000..18d5582d --- /dev/null +++ b/vendor/darling/Cargo.lock @@ -0,0 +1,233 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "darling" +version = "0.20.10" +dependencies = [ + "darling_core", + "darling_macro", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.16", + "trybuild", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.16", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustversion" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "serde" +version = "1.0.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.91", +] + +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "trybuild" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db29f438342820400f2d9acfec0d363e987a38b2950bdb50a7069ed17b2148ee" +dependencies = [ + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", + "toml", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/darling/Cargo.toml b/vendor/darling/Cargo.toml new file mode 100644 index 00000000..9e00a4cb --- /dev/null +++ b/vendor/darling/Cargo.toml @@ -0,0 +1,59 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "darling" +version = "0.20.10" +authors = ["Ted Driggs "] +exclude = [ + "/.travis.yml", + "/publish.sh", + "/.github/**", +] +description = """ +A proc-macro library for reading attributes into structs when +implementing custom derives. +""" +documentation = "https://docs.rs/darling/0.20.10" +readme = "README.md" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" + +[dependencies.darling_core] +version = "=0.20.10" + +[dependencies.darling_macro] +version = "=0.20.10" + +[dev-dependencies.proc-macro2] +version = "1.0.37" + +[dev-dependencies.quote] +version = "1.0.18" + +[dev-dependencies.syn] +version = "2.0.15" + +[features] +default = ["suggestions"] +diagnostics = ["darling_core/diagnostics"] +suggestions = ["darling_core/suggestions"] + +[target."cfg(compiletests)".dev-dependencies.rustversion] +version = "1.0.9" + +[target."cfg(compiletests)".dev-dependencies.trybuild] +version = "1.0.38" + +[badges.maintenance] +status = "actively-developed" diff --git a/vendor/darling/LICENSE b/vendor/darling/LICENSE new file mode 100644 index 00000000..0b48eadc --- /dev/null +++ b/vendor/darling/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +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/vendor/darling/README.md b/vendor/darling/README.md new file mode 100644 index 00000000..5e4aa2a7 --- /dev/null +++ b/vendor/darling/README.md @@ -0,0 +1,149 @@ +# Darling + +[![Build Status](https://github.com/TedDriggs/darling/workflows/CI/badge.svg)](https://github.com/TedDriggs/darling/actions) +[![Latest Version](https://img.shields.io/crates/v/darling.svg)](https://crates.io/crates/darling) +![Rustc Version 1.56+](https://img.shields.io/badge/rustc-1.56+-lightgray.svg) + +`darling` is a crate for proc macro authors, which enables parsing attributes into structs. It is heavily inspired by `serde` both in its internals and in its API. + +# Benefits + +- Easy and declarative parsing of macro input - make your proc-macros highly controllable with minimal time investment. +- Great validation and errors, no work required. When users of your proc-macro make a mistake, `darling` makes sure they get error markers at the right place in their source, and provides "did you mean" suggestions for misspelled fields. + +# Usage + +`darling` provides a set of traits which can be derived or manually implemented. + +1. `FromMeta` is used to extract values from a meta-item in an attribute. Implementations are likely reusable for many libraries, much like `FromStr` or `serde::Deserialize`. Trait implementations are provided for primitives, some std types, and some `syn` types. +2. `FromDeriveInput` is implemented or derived by each proc-macro crate which depends on `darling`. This is the root for input parsing; it gets access to the identity, generics, and visibility of the target type, and can specify which attribute names should be parsed or forwarded from the input AST. +3. `FromField` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity (if it exists), type, and visibility of the field. +4. `FromVariant` is implemented or derived by each proc-macro crate which depends on `darling`. Structs deriving this trait will get access to the identity and contents of the variant, which can be transformed the same as any other `darling` input. +5. `FromAttributes` is a lower-level version of the more-specific `FromDeriveInput`, `FromField`, and `FromVariant` traits. Structs deriving this trait get a meta-item extractor and error collection which works for any syntax element, including traits, trait items, and functions. This is useful for non-derive proc macros. + +## Additional Modules + +- `darling::ast` provides generic types for representing the AST. +- `darling::usage` provides traits and functions for determining where type parameters and lifetimes are used in a struct or enum. +- `darling::util` provides helper types with special `FromMeta` implementations, such as `PathList`. + +# Example + +```rust,ignore +use darling::{FromDeriveInput, FromMeta}; + +#[derive(Default, FromMeta)] +#[darling(default)] +pub struct Lorem { + #[darling(rename = "sit")] + ipsum: bool, + dolor: Option, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(my_crate), forward_attrs(allow, doc, cfg))] +pub struct MyTraitOpts { + ident: syn::Ident, + attrs: Vec, + lorem: Lorem, +} +``` + +The above code will then be able to parse this input: + +```rust,ignore +/// A doc comment which will be available in `MyTraitOpts::attrs`. +#[derive(MyTrait)] +#[my_crate(lorem(dolor = "Hello", sit))] +pub struct ConsumingType; +``` + +# Attribute Macros + +Non-derive attribute macros are supported. +To parse arguments for attribute macros, derive `FromMeta` on the argument receiver type, then use `darling::ast::NestedMeta::parse_meta_list` to convert the arguments `TokenStream` to a `Vec`, then pass that to the derived `from_list` method on your argument receiver type. +This will produce a normal `darling::Result` that can be used the same as a result from parsing a `DeriveInput`. + +## Macro Code + +```rust,ignore +use darling::{Error, FromMeta}; +use darling::ast::NestedMeta; +use syn::ItemFn; +use proc_macro::TokenStream; + +#[derive(Debug, FromMeta)] +struct MacroArgs { + #[darling(default)] + timeout_ms: Option, + path: String, +} + +#[proc_macro_attribute] +pub fn your_attr(args: TokenStream, input: TokenStream) -> TokenStream { + let attr_args = match NestedMeta::parse_meta_list(args.into()) { + Ok(v) => v, + Err(e) => { return TokenStream::from(Error::from(e).write_errors()); } + }; + let _input = syn::parse_macro_input!(input as ItemFn); + + let _args = match MacroArgs::from_list(&attr_args) { + Ok(v) => v, + Err(e) => { return TokenStream::from(e.write_errors()); } + }; + + // do things with `args` + unimplemented!() +} +``` + +## Consuming Code + +```rust,ignore +use your_crate::your_attr; + +#[your_attr(path = "hello", timeout_ms = 15)] +fn do_stuff() { + println!("Hello"); +} +``` + +# Features + +Darling's features are built to work well for real-world projects. + +- **Defaults**: Supports struct- and field-level defaults, using the same path syntax as `serde`. + Additionally, `Option` and `darling::util::Flag` fields are innately optional; you don't need to declare `#[darling(default)]` for those. +- **Field Renaming**: Fields can have different names in usage vs. the backing code. +- **Auto-populated fields**: Structs deriving `FromDeriveInput` and `FromField` can declare properties named `ident`, `vis`, `ty`, `attrs`, and `generics` to automatically get copies of the matching values from the input AST. `FromDeriveInput` additionally exposes `data` to get access to the body of the deriving type, and `FromVariant` exposes `fields`. + - **Transformation of forwarded attributes**: You can add `#[darling(with=path)]` to the `attrs` field to use a custom function to transform the forwarded attributes before they're provided to your struct. The function signature is `fn(Vec) -> darling::Result`, where `T` is the type you declared for the `attrs` field. Returning an error from this function will propagate with all other parsing errors. +- **Mapping function**: Use `#[darling(map="path")]` or `#[darling(and_then="path")]` to specify a function that runs on the result of parsing a meta-item field. This can change the return type, which enables you to parse to an intermediate form and convert that to the type you need in your struct. +- **Skip fields**: Use `#[darling(skip)]` to mark a field that shouldn't be read from attribute meta-items. +- **Multiple-occurrence fields**: Use `#[darling(multiple)]` on a `Vec` field to allow that field to appear multiple times in the meta-item. Each occurrence will be pushed into the `Vec`. +- **Span access**: Use `darling::util::SpannedValue` in a struct to get access to that meta item's source code span. This can be used to emit warnings that point at a specific field from your proc macro. In addition, you can use `darling::Error::write_errors` to automatically get precise error location details in most cases. +- **"Did you mean" suggestions**: Compile errors from derived darling trait impls include suggestions for misspelled fields. +- **Struct flattening**: Use `#[darling(flatten)]` to remove one level of structure when presenting your meta item to users. Fields that are not known to the parent struct will be forwarded to the `flatten` field. + +## Shape Validation + +Some proc-macros only work on structs, while others need enums whose variants are either unit or newtype variants. +Darling makes this sort of validation extremely simple. +On the receiver that derives `FromDeriveInput`, add `#[darling(supports(...))]` and then list the shapes that your macro should accept. + +| Name | Description | +| ---------------- | ------------------------------------------------------------------------- | +| `any` | Accept anything | +| `struct_any` | Accept any struct | +| `struct_named` | Accept structs with named fields, e.g. `struct Example { field: String }` | +| `struct_newtype` | Accept newtype structs, e.g. `struct Example(String)` | +| `struct_tuple` | Accept tuple structs, e.g. `struct Example(String, String)` | +| `struct_unit` | Accept unit structs, e.g. `struct Example;` | +| `enum_any` | Accept any enum | +| `enum_named` | Accept enum variants with named fields | +| `enum_newtype` | Accept newtype enum variants | +| `enum_tuple` | Accept tuple enum variants | +| `enum_unit` | Accept unit enum variants | + +Each one is additive, so listing `#[darling(supports(struct_any, enum_newtype))]` would accept all structs and any enum where every variant is a newtype variant. + +This can also be used when deriving `FromVariant`, without the `enum_` prefix. diff --git a/vendor/darling/clippy.toml b/vendor/darling/clippy.toml new file mode 100644 index 00000000..e221e795 --- /dev/null +++ b/vendor/darling/clippy.toml @@ -0,0 +1,2 @@ +msrv = "1.56.0" +disallowed-names = [] # we want to be able to use placeholder names in tests \ No newline at end of file diff --git a/vendor/darling/compiletests.sh b/vendor/darling/compiletests.sh new file mode 100755 index 00000000..a8ce0428 --- /dev/null +++ b/vendor/darling/compiletests.sh @@ -0,0 +1 @@ +RUSTFLAGS="--cfg=compiletests" cargo +1.65.0 test --test compiletests \ No newline at end of file diff --git a/vendor/darling/examples/automatic_bounds.rs b/vendor/darling/examples/automatic_bounds.rs new file mode 100644 index 00000000..8312afed --- /dev/null +++ b/vendor/darling/examples/automatic_bounds.rs @@ -0,0 +1,73 @@ +use darling::{FromDeriveInput, FromMeta}; + +#[derive(FromMeta, PartialEq, Eq, Debug)] +enum Volume { + Whisper, + Talk, + Shout, +} + +/// A more complex example showing the ability to skip at a field or struct +/// level while still tracking which type parameters need to be bounded. +/// This can be seen by expanding this example using `cargo expand`. +#[derive(FromMeta)] +#[allow(dead_code)] +enum Emphasis { + Constant(Volume), + Variable(darling::util::PathList), + #[darling(skip)] + PerPhoneme(Option), + Strided { + #[darling(skip)] + step: Vec, + #[darling(multiple)] + volume: Vec, + }, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +struct SpeakingOptions { + max_volume: U, + #[darling(skip, default)] + additional_data: Vec, +} + +#[derive(Default)] +struct Phoneme { + #[allow(dead_code)] + first: String, +} + +// This is probably the holy grail for `darling`'s own internal use-case: +// Auto-apply `Default` bound to skipped *field* types in `where` clause. +impl Default for SpeakingOptions +where + Vec: Default, + U: Default, +{ + fn default() -> Self { + Self { + max_volume: Default::default(), + additional_data: Default::default(), + } + } +} + +fn main() { + let derive_input = syn::parse_str( + r#" + #[derive(Speak)] + #[speak(max_volume = "shout")] + enum HtmlElement { + Div(String) + } + "#, + ) + .unwrap(); + + let parsed: SpeakingOptions = + FromDeriveInput::from_derive_input(&derive_input).unwrap(); + assert_eq!(parsed.max_volume, Volume::Shout); + assert_eq!(parsed.additional_data.len(), 0); +} diff --git a/vendor/darling/examples/consume_fields.rs b/vendor/darling/examples/consume_fields.rs new file mode 100644 index 00000000..f5cd435b --- /dev/null +++ b/vendor/darling/examples/consume_fields.rs @@ -0,0 +1,175 @@ +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +//! This example shows how to do struct and field parsing using darling. + +use darling::{ast, FromDeriveInput, FromField, FromMeta}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse_str; + +/// A speaking volume. Deriving `FromMeta` will cause this to be usable +/// as a string value for a meta-item key. +#[derive(Debug, Clone, Copy, FromMeta)] +#[darling(default)] +enum Volume { + Normal, + Whisper, + Shout, +} + +impl Default for Volume { + fn default() -> Self { + Volume::Normal + } +} + +/// Support parsing from a full derive input. Unlike FromMeta, this isn't +/// composable; each darling-dependent crate should have its own struct to handle +/// when its trait is derived. +#[derive(Debug, FromDeriveInput)] +// This line says that we want to process all attributes declared with `my_trait`, +// and that darling should panic if this receiver is given an enum. +#[darling(attributes(my_trait), supports(struct_any))] +struct MyInputReceiver { + /// The struct ident. + ident: syn::Ident, + + /// The type's generics. You'll need these any time your trait is expected + /// to work with types that declare generics. + generics: syn::Generics, + + /// Receives the body of the struct or enum. We don't care about + /// struct fields because we previously told darling we only accept structs. + data: ast::Data<(), MyFieldReceiver>, + + /// The Input Receiver demands a volume, so use `Volume::Normal` if the + /// caller doesn't provide one. + #[darling(default)] + volume: Volume, +} + +impl ToTokens for MyInputReceiver { + fn to_tokens(&self, tokens: &mut TokenStream) { + let MyInputReceiver { + ref ident, + ref generics, + ref data, + volume, + } = *self; + + let (imp, ty, wher) = generics.split_for_impl(); + let fields = data + .as_ref() + .take_struct() + .expect("Should never be enum") + .fields; + + // Generate the format string which shows each field and its name + let fmt_string = fields + .iter() + .enumerate() + .map(|(i, f)| { + // We have to preformat the ident in this case so we can fall back + // to the field index for unnamed fields. It's not easy to read, + // unfortunately. + format!( + "{} = {{}}", + f.ident + .as_ref() + .map(|v| format!("{}", v)) + .unwrap_or_else(|| format!("{}", i)) + ) + }) + .collect::>() + .join(", "); + + // Generate the actual values to fill the format string. + let field_list = fields + .into_iter() + .enumerate() + .map(|(i, f)| { + let field_volume = f.volume.unwrap_or(volume); + + // This works with named or indexed fields, so we'll fall back to the index so we can + // write the output as a key-value pair. + let field_ident = f.ident + .as_ref() + .map(|v| quote!(#v)) + .unwrap_or_else(|| { + let i = syn::Index::from(i); + quote!(#i) + }); + + match field_volume { + Volume::Normal => quote!(self.#field_ident), + Volume::Shout => { + quote!(::std::string::ToString::to_string(&self.#field_ident).to_uppercase()) + } + Volume::Whisper => { + quote!(::std::string::ToString::to_string(&self.#field_ident).to_lowercase()) + } + } + }) + .collect::>(); + + tokens.extend(quote! { + impl #imp Speak for #ident #ty #wher { + fn speak(&self, writer: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(writer, #fmt_string, #(#field_list),*) + } + } + }); + } +} + +#[derive(Debug, FromField)] +#[darling(attributes(my_trait))] +struct MyFieldReceiver { + /// Get the ident of the field. For fields in tuple or newtype structs or + /// enum bodies, this can be `None`. + ident: Option, + + /// This magic field name pulls the type from the input. + ty: syn::Type, + + /// We declare this as an `Option` so that during tokenization we can write + /// `field.volume.unwrap_or(derive_input.volume)` to facilitate field-level + /// overrides of struct-level settings. + /// + /// Because this field is an `Option`, we don't need to include `#[darling(default)]` + volume: Option, +} + +fn main() { + let input = r#"#[derive(MyTrait)] +#[my_trait(volume = "shout")] +pub struct Foo { + #[my_trait(volume = "whisper")] + bar: bool, + + baz: i64, +}"#; + + let parsed = parse_str(input).unwrap(); + let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); + let tokens = quote!(#receiver); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + +EMITS: + +{} + "#, + input, receiver, tokens + ); +} diff --git a/vendor/darling/examples/expr_with.rs b/vendor/darling/examples/expr_with.rs new file mode 100644 index 00000000..037ce252 --- /dev/null +++ b/vendor/darling/examples/expr_with.rs @@ -0,0 +1,19 @@ +use darling::{util::parse_expr, FromDeriveInput}; +use syn::{parse_quote, Expr}; + +#[derive(FromDeriveInput)] +#[darling(attributes(demo))] +pub struct Receiver { + #[darling(with = parse_expr::preserve_str_literal, map = Some)] + example1: Option, +} + +fn main() { + let input = Receiver::from_derive_input(&parse_quote! { + #[demo(example1 = test::path)] + struct Example; + }) + .unwrap(); + + assert_eq!(input.example1, Some(parse_quote!(test::path))); +} diff --git a/vendor/darling/examples/fallible_read.rs b/vendor/darling/examples/fallible_read.rs new file mode 100644 index 00000000..848c3d2e --- /dev/null +++ b/vendor/darling/examples/fallible_read.rs @@ -0,0 +1,85 @@ +//! This example demonstrates techniques for performing custom error handling +//! in a derive-input receiver. +//! +//! 1. Using `darling::Result` as a carrier to preserve the error for later display +//! 1. Using `Result` to attempt a recovery in imperative code +//! 1. Using the `map` darling meta-item to post-process a field before returning +//! 1. Using the `and_then` darling meta-item to post-process the receiver before returning + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_str; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(my_trait), and_then = MyInputReceiver::autocorrect)] +pub struct MyInputReceiver { + /// This field must be present and a string or else parsing will panic. + #[darling(map = MyInputReceiver::make_string_shouty)] + name: String, + + /// If this field fails to parse, the struct can still be built; the field + /// will contain the error. The consuming struct can then decide if this + /// blocks code generation. If so, panic or fail in `and_then`. + frequency: darling::Result, + + /// If this field fails to parse, the struct can still be built; the field + /// will contain an `Err` with the original `syn::Meta`. This can be used + /// for alternate parsing attempts before panicking. + amplitude: Result, +} + +impl MyInputReceiver { + /// This function will be called by `darling` _after_ it's finished parsing the + /// `name` field but before initializing `name` with the resulting value. It's + /// a good place for transforms that are easiest to express on already-built + /// types. + fn make_string_shouty(s: String) -> String { + s.to_uppercase() + } + + /// This function will be called by `darling` _after_ it's finished parsing the + /// input but before returning to the caller. This is a good place to initialize + /// skipped fields or to perform corrections that don't lend themselves to being + /// done elsewhere. + fn autocorrect(self) -> darling::Result { + let Self { + name, + frequency, + amplitude, + } = self; + + // Amplitude doesn't have a sign, so if we received a negative number then + // we'll go ahead and make it positive. + let amplitude = match amplitude { + Ok(amp) => amp, + Err(mi) => (i64::from_meta(&mi)?).unsigned_abs(), + }; + + Ok(Self { + name, + frequency, + amplitude: Ok(amplitude), + }) + } +} + +fn main() { + let input = r#"#[derive(MyTrait)] +#[my_trait(name="Jon", amplitude = "-1", frequency = 1)] +pub struct Foo;"#; + + let parsed = parse_str(input).unwrap(); + let receiver = MyInputReceiver::from_derive_input(&parsed).unwrap(); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + "#, + input, receiver + ); +} diff --git a/vendor/darling/examples/heterogeneous_enum_and_word.rs b/vendor/darling/examples/heterogeneous_enum_and_word.rs new file mode 100644 index 00000000..029549f7 --- /dev/null +++ b/vendor/darling/examples/heterogeneous_enum_and_word.rs @@ -0,0 +1,79 @@ +//! This example demonstrates: +//! +//! - The behavior of a derived `FromMeta` implementation for heterogeneous enums +//! (i.e. enums that include a mix of unit, newtype and struct variants). +//! - Using `#[darling(word)]` to specify a unit variant to use when a receiver field +//! is specified without a value (i.e. a unit variant to use for deriving the +//! `FromMeta::from_word` method). +//! - Using `#[darling(default)]` on a receiver field to fall back to `Default::default()` +//! for the enum's value when the receiver field is not specified by the caller. + +use darling::{Error, FromDeriveInput, FromMeta}; +use syn::parse_quote; + +/// A playback volume. +#[derive(Debug, FromMeta, PartialEq, Eq)] +enum Volume { + Normal, + #[darling(word)] + Low, + High, + #[darling(rename = "dB")] + Decibels(u8), +} + +impl Default for Volume { + fn default() -> Self { + Volume::Normal + } +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(play))] +struct PlayReceiver { + #[darling(default)] + volume: Volume, +} + +fn main() { + // `Default::default()` is used when `volume` is not specified. + let missing_volume = PlayReceiver::from_derive_input(&parse_quote! { + #[play] + struct Player; + }) + .unwrap(); + assert_eq!(Volume::Normal, missing_volume.volume); + + // `#[darling(word)]` unit variant is used when `volume` is specified as a word with no value. + let empty_volume = PlayReceiver::from_derive_input(&parse_quote! { + #[play(volume)] + struct Player; + }) + .unwrap(); + assert_eq!(Volume::Low, empty_volume.volume); + + // Specified `volume` value is used when provided. + let unit_variant_volume = PlayReceiver::from_derive_input(&parse_quote! { + #[play(volume(high))] + struct Player; + }) + .unwrap(); + assert_eq!(Volume::High, unit_variant_volume.volume); + let newtype_volume = PlayReceiver::from_derive_input(&parse_quote! { + #[play(volume(dB = 100))] + struct Player; + }) + .unwrap(); + assert_eq!(Volume::Decibels(100), newtype_volume.volume); + + // Multiple `volume` values result in an error. + let err = PlayReceiver::from_derive_input(&parse_quote! { + #[play(volume(low, dB = 20))] + struct Player; + }) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::too_many_items(1).at("volume").to_string() + ); +} diff --git a/vendor/darling/examples/shorthand_or_long_field.rs b/vendor/darling/examples/shorthand_or_long_field.rs new file mode 100644 index 00000000..750d83ef --- /dev/null +++ b/vendor/darling/examples/shorthand_or_long_field.rs @@ -0,0 +1,79 @@ +//! Example showing potentially-nested meta item parsing with `darling::util::Override`. +//! +//! Based on https://stackoverflow.com/q/68046070/86381 by https://github.com/peterjoel + +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +use std::borrow::Cow; + +use darling::{util::Override, FromDeriveInput, FromMeta}; +use syn::{Ident, Path}; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(myderive))] +struct MyDeriveInput { + ident: Ident, + /// We can infer the right "table" behavior for this derive, but we want the caller to be + /// explicit that they're expecting the inference behavior to avoid cluttering some hypothetical + /// database. Therefore this field is required, but can take word form or key-value form. + /// + /// To make this field optional, we could add `#[darling(default)]`, or we could + /// wrap it in `Option` if the presence or absence of the word makes a difference. + table: Override, +} + +impl MyDeriveInput { + fn table(&self) -> Cow<'_, Table> { + match &self.table { + Override::Explicit(value) => Cow::Borrowed(value), + Override::Inherit => Cow::Owned(Table { + name: self.ident.to_string(), + value: None, + }), + } + } +} + +#[derive(Debug, Clone, FromMeta)] +struct Table { + name: String, + value: Option, +} + +fn from_str(s: &str) -> darling::Result { + FromDeriveInput::from_derive_input(&syn::parse_str(s)?) +} + +fn main() { + let missing = from_str( + r#" + #[derive(MyTrait)] + struct Foo(u64); + "#, + ) + .unwrap_err(); + + let short_form = from_str( + r#" + #[derive(MyTrait)] + #[myderive(table)] + struct Foo(u64); + "#, + ) + .unwrap(); + + let long_form = from_str( + r#" + #[derive(MyTrait)] + #[myderive(table(name = "Custom"))] + struct Foo(u64); + "#, + ) + .unwrap(); + + println!("Error when missing: {}", missing); + println!("Short form: {:?}", short_form.table()); + println!("Long form: {:?}", long_form.table()); +} diff --git a/vendor/darling/examples/supports_struct.rs b/vendor/darling/examples/supports_struct.rs new file mode 100644 index 00000000..97a5bb9c --- /dev/null +++ b/vendor/darling/examples/supports_struct.rs @@ -0,0 +1,61 @@ +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +use darling::{ast, util, FromDeriveInput, FromField}; +use syn::{Ident, Type}; + +#[derive(Debug, FromField)] +#[darling(attributes(lorem))] +pub struct LoremField { + ident: Option, + ty: Type, + #[darling(default)] + skip: bool, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(lorem), supports(struct_named))] +pub struct Lorem { + ident: Ident, + data: ast::Data, +} + +fn main() { + let good_input = r#"#[derive(Lorem)] +pub struct Foo { + #[lorem(skip)] + bar: bool, + + baz: i64, +}"#; + + let bad_input = r#"#[derive(Lorem)] + pub struct BadFoo(String, u32);"#; + + let parsed = syn::parse_str(good_input).unwrap(); + let receiver = Lorem::from_derive_input(&parsed).unwrap(); + let wrong_shape_parsed = syn::parse_str(bad_input).unwrap(); + let wrong_shape = Lorem::from_derive_input(&wrong_shape_parsed).expect_err("Shape was wrong"); + + println!( + r#" +INPUT: + +{} + +PARSED AS: + +{:?} + +BAD INPUT: + +{} + +PRODUCED ERROR: + +{} + "#, + good_input, receiver, bad_input, wrong_shape + ); +} diff --git a/vendor/darling/src/lib.rs b/vendor/darling/src/lib.rs new file mode 100644 index 00000000..031f290f --- /dev/null +++ b/vendor/darling/src/lib.rs @@ -0,0 +1,109 @@ +//! # Darling +//! Darling is a tool for declarative attribute parsing in proc macro implementations. +//! +//! +//! ## Design +//! Darling takes considerable design inspiration from [`serde`](https://serde.rs). A data structure that can be +//! read from any attribute implements `FromMeta` (or has an implementation automatically +//! generated using `derive`). Any crate can provide `FromMeta` implementations, even one not +//! specifically geared towards proc-macro authors. +//! +//! Proc-macro crates should provide their own structs which implement or derive `FromDeriveInput`, +//! `FromField`, `FromVariant`, `FromGenerics`, _et alia_ to gather settings relevant to their operation. +//! +//! ## Attributes +//! There are a number of attributes that `darling` exposes to enable finer-grained control over the code +//! it generates. +//! +//! * **Field renaming**: You can use `#[darling(rename="new_name")]` on a field to change the name Darling looks for. +//! You can also use `#[darling(rename_all="...")]` at the struct or enum level to apply a casing rule to all fields or variants. +//! * **Map function**: You can use `#[darling(map="path::to::function")]` to run code on a field before its stored in the struct. +//! * **Default values**: You can use `#[darling(default)]` at the type or field level to use that type's default value to fill +//! in values not specified by the caller. +//! * **Skipped fields**: You can skip a variant or field using `#[darling(skip)]`. Fields marked with this will fall back to +//! `Default::default()` for their value, but you can override that with an explicit default or a value from the type-level default. +//! +//! ## Forwarded Fields +//! All derivable traits except `FromMeta` support forwarding some fields from the input AST to the derived struct. +//! These fields are matched up by identifier **before** `rename` attribute values are considered, +//! allowing you to use their names for your own properties. +//! The deriving struct is responsible for making sure the types of fields it chooses to declare are compatible with this table. +//! +//! A deriving struct is free to include or exclude any of the fields below. +//! +//! ### `FromDeriveInput` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in type| +//! |`vis`|`syn::Visibility`|The visibility of the passed-in type| +//! |`generics`|`T: darling::FromGenerics`|The generics of the passed-in type. This can be `syn::Generics`, `darling::ast::Generics`, or any compatible type.| +//! |`data`|`darling::ast::Data`|The body of the passed-in type| +//! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in type. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromField` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`Option`|The identifier of the passed-in field, or `None` for tuple fields| +//! |`vis`|`syn::Visibility`|The visibility of the passed-in field| +//! |`ty`|`syn::Type`|The type of the passed-in field| +//! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in field. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromTypeParam` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in type param| +//! |`bounds`|`Vec`|The bounds applied to the type param| +//! |`default`|`Option`|The default type of the parameter, if one exists| +//! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in type param. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromVariant` +//! |Field name|Type|Meaning| +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in variant| +//! |`discriminant`|`Option`|For a variant such as `Example = 2`, the `2`| +//! |`fields`|`darling::ast::Fields where T: FromField`|The fields associated with the variant| +//! |`attrs`|`Vec` (or anything, using `#[darling(with = ...)]`)|The forwarded attributes from the passed in variant. These are controlled using the `forward_attrs` attribute.| +#![warn(rust_2018_idioms)] + +#[allow(unused_imports)] +#[macro_use] +extern crate darling_macro; + +#[doc(hidden)] +pub use darling_macro::*; + +#[doc(inline)] +pub use darling_core::{ + FromAttributes, FromDeriveInput, FromField, FromGenericParam, FromGenerics, FromMeta, + FromTypeParam, FromVariant, +}; + +#[doc(inline)] +pub use darling_core::{Error, Result}; + +#[doc(inline)] +pub use darling_core::{ast, error, usage, util}; + +// XXX exported so that `ExtractAttribute::extractor` can convert a path into tokens. +// This is likely to change in the future, so only generated code should depend on this export. +#[doc(hidden)] +pub use darling_core::ToTokens; + +/// Core/std trait re-exports. This should help produce generated code which doesn't +/// depend on `std` unnecessarily, and avoids problems caused by aliasing `std` or any +/// of the referenced types. +#[doc(hidden)] +pub mod export { + pub use core::convert::From; + pub use core::default::Default; + pub use core::option::Option::{self, None, Some}; + pub use core::result::Result::{self, Err, Ok}; + pub use darling_core::syn; + pub use std::string::ToString; + pub use std::vec::Vec; + + pub use crate::ast::NestedMeta; +} + +#[macro_use] +mod macros_public; diff --git a/vendor/darling/src/macros_public.rs b/vendor/darling/src/macros_public.rs new file mode 100644 index 00000000..c264fcc2 --- /dev/null +++ b/vendor/darling/src/macros_public.rs @@ -0,0 +1,96 @@ +//! Macros that should be exported from both `darling_core` and `darling`. +//! Note that these are **sym-linked** into the main code, and so cannot declare on items that are exported differently +//! in `darling_core` vs. `darling`. + +/// Generator for `UsesTypeParam` impls that unions the used type parameters of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesTypeParams`, or the resulting code won't compile. +/// +/// ```rust +/// # extern crate syn; +/// # use darling_core::uses_type_params; +/// # +/// struct MyField { +/// ty: syn::Type, +/// } +/// +/// uses_type_params!(MyField, ty); +/// +/// fn main() { +/// // no test run +/// } +/// ``` +/// +/// `darling` cannot derive this trait automatically, as it doesn't know which information extracted from +/// proc-macro input is meant to constitute "using" the type parameter, but crate consumers should +/// implement it by hand or using the macro. +#[macro_export] +macro_rules! uses_type_params { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + self.$accessor.uses_type_params(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesTypeParams for $impl_type { + fn uses_type_params<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::IdentSet + ) -> $crate::usage::IdentRefSet<'gen> { + let mut hits = self.$first.uses_type_params(options, type_set); + $( + hits.extend(self.$field.uses_type_params(options, type_set)); + )* + hits + } + } + }; +} + +/// Generator for `UsesLifetimes` impls that unions the used lifetimes of the selected fields. +/// +/// # Usage +/// The macro takes the type implementing the trait as the first argument, then a comma-separated list of +/// fields for the rest of its arguments. +/// +/// The type of each passed-in field must implement `UsesLifetimes`, or the resulting code won't compile. +#[macro_export] +macro_rules! uses_lifetimes { + ($impl_type:ty, $accessor:ident) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + self.$accessor.uses_lifetimes(options, type_set) + } + } + }; + ($impl_type:ty, $first:ident, $($field:ident),+) => { + impl $crate::usage::UsesLifetimes for $impl_type { + fn uses_lifetimes<'gen>( + &self, + options: &$crate::usage::Options, + type_set: &'gen $crate::usage::LifetimeSet + ) -> $crate::usage::LifetimeRefSet<'gen> { + let mut hits = self.$first.uses_lifetimes(options, type_set); + $( + hits.extend(self.$field.uses_lifetimes(options, type_set)); + )* + hits + } + } + }; +} diff --git a/vendor/darling/tests/accrue_errors.rs b/vendor/darling/tests/accrue_errors.rs new file mode 100644 index 00000000..e8799c43 --- /dev/null +++ b/vendor/darling/tests/accrue_errors.rs @@ -0,0 +1,102 @@ +#![allow(dead_code)] +//! These tests verify that multiple errors will be collected up from throughout +//! the parsing process and returned correctly to the caller. + +use darling::{ast, FromDeriveInput, FromField, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(accrue))] +struct Lorem { + ipsum: String, + dolor: Dolor, + data: ast::Data<(), LoremField>, +} + +#[derive(Debug, FromMeta)] +struct Dolor { + sit: bool, +} + +#[derive(Debug, FromField)] +#[darling(attributes(accrue))] +struct LoremField { + ident: Option, + aliased_as: syn::Ident, +} + +#[test] +fn bad_type_and_missing_fields() { + let input = parse_quote! { + #[accrue(ipsum = true, dolor(amet = "Hi"))] + pub struct NonConforming { + foo: () + } + }; + + let s_result: ::darling::Error = Lorem::from_derive_input(&input).unwrap_err(); + let err = s_result.flatten(); + println!("{}", err); + assert_eq!(3, err.len()); +} + +#[test] +fn body_only_issues() { + let input = parse_quote! { + #[accrue(ipsum = "Hello", dolor(sit))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Lorem::from_derive_input(&input).unwrap_err(); + println!("{:?}", s_err); + assert_eq!(2, s_err.len()); +} + +#[derive(Debug, FromMeta)] +enum Week { + Monday, + Tuesday { morning: bool, afternoon: String }, + Wednesday(Dolor), +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(accrue))] +struct Month { + schedule: Week, +} + +#[test] +fn error_in_enum_fields() { + let input = parse_quote! { + #[accrue(schedule(tuesday(morning = "yes")))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Month::from_derive_input(&input).unwrap_err(); + assert_eq!(2, s_err.len()); + let err = s_err.flatten(); + // TODO add tests to check location path is correct + println!("{}", err); +} + +#[test] +fn error_in_newtype_variant() { + let input = parse_quote! { + #[accrue(schedule(wednesday(sit = "yes")))] + pub struct NonConforming { + foo: (), + bar: bool, + } + }; + + let s_err = Month::from_derive_input(&input).unwrap_err(); + assert_eq!(1, s_err.len()); + println!("{}", s_err); + println!("{}", s_err.flatten()); +} diff --git a/vendor/darling/tests/attrs_with.rs b/vendor/darling/tests/attrs_with.rs new file mode 100644 index 00000000..198322dc --- /dev/null +++ b/vendor/darling/tests/attrs_with.rs @@ -0,0 +1,80 @@ +use std::collections::BTreeSet; + +use darling::{util, Error, FromDeriveInput, Result}; +use syn::{parse_quote, Attribute}; + +fn unique_idents(attrs: Vec) -> Result> { + let mut errors = Error::accumulator(); + let idents = attrs + .into_iter() + .filter_map(|attr| { + let path = attr.path(); + errors.handle( + path.get_ident() + .map(std::string::ToString::to_string) + .ok_or_else(|| { + Error::custom(format!("`{}` is not an ident", util::path_to_string(path))) + .with_span(path) + }), + ) + }) + .collect(); + + errors.finish_with(idents) +} + +#[derive(FromDeriveInput)] +#[darling(attributes(a), forward_attrs)] +struct Receiver { + #[darling(with = unique_idents)] + attrs: BTreeSet, + other: Option, +} + +#[test] +fn succeeds_on_no_attrs() { + let di = Receiver::from_derive_input(&parse_quote! { + struct Demo; + }) + .unwrap(); + + assert!(di.attrs.is_empty()); +} + +#[test] +fn succeeds_on_valid_input() { + let di = Receiver::from_derive_input(&parse_quote! { + #[allow(dead_code)] + /// testing + #[another] + struct Demo; + }) + .unwrap(); + + assert_eq!(di.attrs.len(), 3); + assert!(di.attrs.contains("allow")); + assert!(di.attrs.contains("another")); + assert!(di.attrs.contains("doc")); + assert_eq!(di.other, None); +} + +#[test] +fn errors_combined_with_others() { + let e = Receiver::from_derive_input(&parse_quote! { + #[path::to::attr(dead_code)] + #[a(other = 5)] + struct Demo; + }) + .map(|_| "Should have failed") + .unwrap_err(); + + let error = e.to_string(); + + assert_eq!(e.len(), 2); + + // Look for the error on the field `other` + assert!(error.contains("at other")); + + // Look for the invalid path from attrs conversion + assert!(error.contains("`path::to::attr`")); +} diff --git a/vendor/darling/tests/compile-fail/attrs_with_bad_fn.rs b/vendor/darling/tests/compile-fail/attrs_with_bad_fn.rs new file mode 100644 index 00000000..6063f647 --- /dev/null +++ b/vendor/darling/tests/compile-fail/attrs_with_bad_fn.rs @@ -0,0 +1,15 @@ +use darling::FromDeriveInput; +use syn::Attribute; + +fn bad_converter(attrs: Vec) -> Vec { + attrs +} + +#[derive(FromDeriveInput)] +#[darling(forward_attrs)] +struct Receiver { + #[darling(with = bad_converter)] + attrs: Vec, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/attrs_with_bad_fn.stderr b/vendor/darling/tests/compile-fail/attrs_with_bad_fn.stderr new file mode 100644 index 00000000..a1b2672e --- /dev/null +++ b/vendor/darling/tests/compile-fail/attrs_with_bad_fn.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> tests/compile-fail/attrs_with_bad_fn.rs:11:22 + | +11 | #[darling(with = bad_converter)] + | ^^^^^^^^^^^^^ + | | + | expected `Result<_, Error>`, found `Vec` + | arguments to this method are incorrect + | + = note: expected enum `Result<_, darling::Error>` + found struct `Vec` +note: method defined here + --> core/src/error/mod.rs + | + | pub fn handle(&mut self, result: Result) -> Option { + | ^^^^^^ +help: try wrapping the expression in `Ok` + | +11 | #[darling(with = Ok(bad_converter))] + | +++ + diff --git a/vendor/darling/tests/compile-fail/default_expr_wrong_type.rs b/vendor/darling/tests/compile-fail/default_expr_wrong_type.rs new file mode 100644 index 00000000..cd9a0fd1 --- /dev/null +++ b/vendor/darling/tests/compile-fail/default_expr_wrong_type.rs @@ -0,0 +1,12 @@ +use darling::FromMeta; + +#[derive(FromMeta)] +struct Receiver { + #[darling(default = "usize::default")] + not_u32: String, + + #[darling(multiple, default = "usize::default")] + also_not_u32: Vec, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/default_expr_wrong_type.stderr b/vendor/darling/tests/compile-fail/default_expr_wrong_type.stderr new file mode 100644 index 00000000..f577f80a --- /dev/null +++ b/vendor/darling/tests/compile-fail/default_expr_wrong_type.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> tests/compile-fail/default_expr_wrong_type.rs:5:25 + | +5 | #[darling(default = "usize::default")] + | ^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()` + | | + | expected `String`, found `usize` + +error[E0308]: mismatched types + --> tests/compile-fail/default_expr_wrong_type.rs:8:35 + | +8 | #[darling(multiple, default = "usize::default")] + | ^^^^^^^^^^^^^^^^ expected `Vec`, found `usize` + | + = note: expected struct `Vec` + found type `usize` diff --git a/vendor/darling/tests/compile-fail/duplicate_word_across_variants.rs b/vendor/darling/tests/compile-fail/duplicate_word_across_variants.rs new file mode 100644 index 00000000..3c8a8f8b --- /dev/null +++ b/vendor/darling/tests/compile-fail/duplicate_word_across_variants.rs @@ -0,0 +1,12 @@ +use darling::FromMeta; + +#[derive(FromMeta)] +enum Choice { + #[darling(word)] + A, + #[darling(word)] + B, + C, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/duplicate_word_across_variants.stderr b/vendor/darling/tests/compile-fail/duplicate_word_across_variants.stderr new file mode 100644 index 00000000..6f8c4bbc --- /dev/null +++ b/vendor/darling/tests/compile-fail/duplicate_word_across_variants.stderr @@ -0,0 +1,11 @@ +error: `#[darling(word)]` can only be applied to one variant + --> tests/compile-fail/duplicate_word_across_variants.rs:5:15 + | +5 | #[darling(word)] + | ^^^^ + +error: `#[darling(word)]` can only be applied to one variant + --> tests/compile-fail/duplicate_word_across_variants.rs:7:15 + | +7 | #[darling(word)] + | ^^^^ diff --git a/vendor/darling/tests/compile-fail/duplicate_word_on_variant.rs b/vendor/darling/tests/compile-fail/duplicate_word_on_variant.rs new file mode 100644 index 00000000..e2942921 --- /dev/null +++ b/vendor/darling/tests/compile-fail/duplicate_word_on_variant.rs @@ -0,0 +1,10 @@ +use darling::FromMeta; + +#[derive(FromMeta)] +enum Choice { + #[darling(word, word)] + A, + B, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/duplicate_word_on_variant.stderr b/vendor/darling/tests/compile-fail/duplicate_word_on_variant.stderr new file mode 100644 index 00000000..bc489d46 --- /dev/null +++ b/vendor/darling/tests/compile-fail/duplicate_word_on_variant.stderr @@ -0,0 +1,5 @@ +error: Duplicate field `word` + --> tests/compile-fail/duplicate_word_on_variant.rs:5:21 + | +5 | #[darling(word, word)] + | ^^^^ diff --git a/vendor/darling/tests/compile-fail/flatten_meta_conflicts.rs b/vendor/darling/tests/compile-fail/flatten_meta_conflicts.rs new file mode 100644 index 00000000..62543e7f --- /dev/null +++ b/vendor/darling/tests/compile-fail/flatten_meta_conflicts.rs @@ -0,0 +1,21 @@ +use darling::FromMeta; + +#[derive(FromMeta)] +struct Inner { + left: String, + right: String, +} + +#[derive(FromMeta)] +struct Outer { + #[darling(flatten, multiple, with = demo, skip = true)] + field: Inner, +} + +#[derive(FromMeta)] +struct ThisIsFine { + #[darling(flatten, multiple = false)] + field: Inner, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/flatten_meta_conflicts.stderr b/vendor/darling/tests/compile-fail/flatten_meta_conflicts.stderr new file mode 100644 index 00000000..6fa4c287 --- /dev/null +++ b/vendor/darling/tests/compile-fail/flatten_meta_conflicts.stderr @@ -0,0 +1,17 @@ +error: `flatten` and `multiple` cannot be used together + --> tests/compile-fail/flatten_meta_conflicts.rs:11:24 + | +11 | #[darling(flatten, multiple, with = demo, skip = true)] + | ^^^^^^^^ + +error: `flatten` and `with` cannot be used together + --> tests/compile-fail/flatten_meta_conflicts.rs:11:34 + | +11 | #[darling(flatten, multiple, with = demo, skip = true)] + | ^^^^ + +error: `flatten` and `skip` cannot be used together + --> tests/compile-fail/flatten_meta_conflicts.rs:11:47 + | +11 | #[darling(flatten, multiple, with = demo, skip = true)] + | ^^^^ diff --git a/vendor/darling/tests/compile-fail/flatten_multiple_fields.rs b/vendor/darling/tests/compile-fail/flatten_multiple_fields.rs new file mode 100644 index 00000000..a093054b --- /dev/null +++ b/vendor/darling/tests/compile-fail/flatten_multiple_fields.rs @@ -0,0 +1,28 @@ +//! Test that multiple fields cannot be marked `flatten` at once. + +use darling::{FromDeriveInput, FromMeta}; + +#[derive(FromMeta)] +struct Inner { + left: String, + right: String, +} + +#[derive(FromMeta)] +pub struct Example { + #[darling(flatten)] + first: Inner, + #[darling(flatten)] + last: Inner, +} + +#[derive(FromDeriveInput)] +pub struct FdiExample { + ident: syn::Ident, + #[darling(flatten)] + first: Inner, + #[darling(flatten)] + last: Inner, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/flatten_multiple_fields.stderr b/vendor/darling/tests/compile-fail/flatten_multiple_fields.stderr new file mode 100644 index 00000000..7750bfb0 --- /dev/null +++ b/vendor/darling/tests/compile-fail/flatten_multiple_fields.stderr @@ -0,0 +1,23 @@ +error: `#[darling(flatten)]` can only be applied to one field + --> tests/compile-fail/flatten_multiple_fields.rs:13:15 + | +13 | #[darling(flatten)] + | ^^^^^^^ + +error: `#[darling(flatten)]` can only be applied to one field + --> tests/compile-fail/flatten_multiple_fields.rs:15:15 + | +15 | #[darling(flatten)] + | ^^^^^^^ + +error: `#[darling(flatten)]` can only be applied to one field + --> tests/compile-fail/flatten_multiple_fields.rs:22:15 + | +22 | #[darling(flatten)] + | ^^^^^^^ + +error: `#[darling(flatten)]` can only be applied to one field + --> tests/compile-fail/flatten_multiple_fields.rs:24:15 + | +24 | #[darling(flatten)] + | ^^^^^^^ diff --git a/vendor/darling/tests/compile-fail/not_impl_from_meta.rs b/vendor/darling/tests/compile-fail/not_impl_from_meta.rs new file mode 100644 index 00000000..f27d7163 --- /dev/null +++ b/vendor/darling/tests/compile-fail/not_impl_from_meta.rs @@ -0,0 +1,16 @@ +use darling::FromMeta; + +struct NotImplFm; + +#[derive(FromMeta)] +struct OuterFm { + inner: NotImplFm, +} + +#[derive(darling::FromDeriveInput)] +#[darling(attributes(hello))] +struct OuterFdi { + inner: NotImplFm, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/not_impl_from_meta.stderr b/vendor/darling/tests/compile-fail/not_impl_from_meta.stderr new file mode 100644 index 00000000..a9c635fd --- /dev/null +++ b/vendor/darling/tests/compile-fail/not_impl_from_meta.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `NotImplFm: FromMeta` is not satisfied + --> tests/compile-fail/not_impl_from_meta.rs:7:12 + | +7 | inner: NotImplFm, + | ^^^^^^^^^ the trait `FromMeta` is not implemented for `NotImplFm` + | + = help: the following other types implement trait `FromMeta`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others + +error[E0277]: the trait bound `NotImplFm: FromMeta` is not satisfied + --> tests/compile-fail/not_impl_from_meta.rs:13:12 + | +13 | inner: NotImplFm, + | ^^^^^^^^^ the trait `FromMeta` is not implemented for `NotImplFm` + | + = help: the following other types implement trait `FromMeta`: + bool + char + isize + i8 + i16 + i32 + i64 + i128 + and $N others diff --git a/vendor/darling/tests/compile-fail/skip_field_not_impl_default.rs b/vendor/darling/tests/compile-fail/skip_field_not_impl_default.rs new file mode 100644 index 00000000..f0d44c77 --- /dev/null +++ b/vendor/darling/tests/compile-fail/skip_field_not_impl_default.rs @@ -0,0 +1,18 @@ +use darling::FromMeta; + +#[derive(FromMeta)] +struct NoDefault(String); + +#[derive(FromMeta)] +struct Recevier { + #[darling(skip)] + skipped: NoDefault, + + #[darling(skip = true)] + explicitly_skipped: NoDefault, + + #[darling(skip = false)] + not_skipped_no_problem: NoDefault, +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/skip_field_not_impl_default.stderr b/vendor/darling/tests/compile-fail/skip_field_not_impl_default.stderr new file mode 100644 index 00000000..8a728fd6 --- /dev/null +++ b/vendor/darling/tests/compile-fail/skip_field_not_impl_default.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `NoDefault: std::default::Default` is not satisfied + --> tests/compile-fail/skip_field_not_impl_default.rs:8:15 + | +8 | #[darling(skip)] + | ^^^^ the trait `std::default::Default` is not implemented for `NoDefault` + | +help: consider annotating `NoDefault` with `#[derive(Default)]` + | +4 + #[derive(Default)] +5 | struct NoDefault(String); + | + +error[E0277]: the trait bound `NoDefault: std::default::Default` is not satisfied + --> tests/compile-fail/skip_field_not_impl_default.rs:11:22 + | +11 | #[darling(skip = true)] + | ^^^^ the trait `std::default::Default` is not implemented for `NoDefault` + | +help: consider annotating `NoDefault` with `#[derive(Default)]` + | +4 + #[derive(Default)] +5 | struct NoDefault(String); + | diff --git a/vendor/darling/tests/compile-fail/word_on_wrong_variant_type.rs b/vendor/darling/tests/compile-fail/word_on_wrong_variant_type.rs new file mode 100644 index 00000000..4bf99cac --- /dev/null +++ b/vendor/darling/tests/compile-fail/word_on_wrong_variant_type.rs @@ -0,0 +1,10 @@ +use darling::FromMeta; + +#[derive(FromMeta)] +enum Meta { + Unit, + #[darling(word)] + NotUnit(String) +} + +fn main() {} diff --git a/vendor/darling/tests/compile-fail/word_on_wrong_variant_type.stderr b/vendor/darling/tests/compile-fail/word_on_wrong_variant_type.stderr new file mode 100644 index 00000000..4193727c --- /dev/null +++ b/vendor/darling/tests/compile-fail/word_on_wrong_variant_type.stderr @@ -0,0 +1,5 @@ +error: Unexpected field: `word`. `#[darling(word)]` can only be applied to a unit variant + --> tests/compile-fail/word_on_wrong_variant_type.rs:6:15 + | +6 | #[darling(word)] + | ^^^^ diff --git a/vendor/darling/tests/compiletests.rs b/vendor/darling/tests/compiletests.rs new file mode 100644 index 00000000..1d550b0f --- /dev/null +++ b/vendor/darling/tests/compiletests.rs @@ -0,0 +1,16 @@ +#![cfg(compiletests)] + +#[rustversion::stable(1.77)] +#[test] +fn compile_test() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compile-fail/*.rs"); +} + +#[rustversion::not(stable(1.77))] +#[test] +fn wrong_rustc_version() { + panic!( + "This is not the expected version of rustc. Error messages vary across compiler versions so tests may produce spurious errors" + ); +} diff --git a/vendor/darling/tests/computed_bound.rs b/vendor/darling/tests/computed_bound.rs new file mode 100644 index 00000000..abdb1022 --- /dev/null +++ b/vendor/darling/tests/computed_bound.rs @@ -0,0 +1,42 @@ +use darling::{FromDeriveInput, FromMeta}; + +fn parse(src: &str) -> T { + let ast = syn::parse_str(src).unwrap(); + FromDeriveInput::from_derive_input(&ast).unwrap() +} + +#[derive(FromMeta, PartialEq, Eq, Debug)] +enum Volume { + Whisper, + Talk, + Shout, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +struct SpeakingOptions { + max_volume: U, + #[darling(skip)] + #[allow(dead_code)] + additional_data: T, +} + +#[derive(Default)] +struct Phoneme { + #[allow(dead_code)] + first: String, +} + +#[test] +fn skipped_field() { + let parsed: SpeakingOptions = parse( + r#" + #[derive(Speak)] + #[speak(max_volume = "shout")] + enum HtmlElement { + Div(String) + } + "#, + ); + assert_eq!(parsed.max_volume, Volume::Shout); +} diff --git a/vendor/darling/tests/custom_bound.rs b/vendor/darling/tests/custom_bound.rs new file mode 100644 index 00000000..312f1478 --- /dev/null +++ b/vendor/darling/tests/custom_bound.rs @@ -0,0 +1,25 @@ +#![allow(dead_code)] + +use std::ops::Add; + +use darling::{FromDeriveInput, FromMeta}; + +#[derive(Debug, Clone, FromMeta)] +#[darling(bound = "T: FromMeta + Add")] +struct Wrapper(pub T); + +impl Add for Wrapper { + type Output = Wrapper<::Output>; + fn add(self, rhs: Self) -> Wrapper<::Output> { + Wrapper(self.0 + rhs.0) + } +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(hello), bound = "Wrapper: Add, T: FromMeta")] +struct Foo { + lorem: Wrapper, +} + +#[test] +fn expansion() {} diff --git a/vendor/darling/tests/defaults.rs b/vendor/darling/tests/defaults.rs new file mode 100644 index 00000000..b74c7451 --- /dev/null +++ b/vendor/darling/tests/defaults.rs @@ -0,0 +1,189 @@ +use darling::FromDeriveInput; +use syn::parse_quote; + +mod foo { + pub mod bar { + pub fn init() -> String { + String::from("hello") + } + } +} + +#[derive(FromDeriveInput)] +#[darling(attributes(speak))] +pub struct SpeakerOpts { + #[darling(default = foo::bar::init)] + first_word: String, +} + +#[test] +fn path_default() { + let speaker: SpeakerOpts = FromDeriveInput::from_derive_input(&parse_quote! { + struct Foo; + }) + .expect("Unit struct with no attrs should parse"); + + assert_eq!(speaker.first_word, "hello"); +} + +/// Tests in this module capture the somewhat-confusing behavior observed when defaults +/// are set at both the field and container level. +/// +/// The general rule is that more-specific declarations preempt less-specific ones; this is +/// unsurprising and allows for granular control over what happens when parsing an AST. +mod stacked_defaults { + use darling::{FromDeriveInput, FromMeta}; + use syn::parse_quote; + + fn jane() -> String { + "Jane".into() + } + + #[derive(FromMeta)] + #[darling(default)] + struct PersonName { + #[darling(default = "jane")] + first: String, + #[darling(default)] + middle: String, + last: String, + } + + impl Default for PersonName { + fn default() -> Self { + Self { + first: "John".into(), + middle: "T".into(), + last: "Doe".into(), + } + } + } + + #[derive(FromDeriveInput)] + #[darling(attributes(person))] + struct Person { + #[darling(default)] + name: PersonName, + age: u8, + } + + #[test] + fn name_first_only() { + let person = Person::from_derive_input(&parse_quote! { + #[person(name(first = "Bill"), age = 5)] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.name.first, "Bill"); + assert_eq!( + person.name.middle, "", + "Explicit field-level default should preempt container-level default" + ); + assert_eq!( + person.name.last, "Doe", + "Absence of a field-level default falls back to container-level default" + ); + } + + /// This is the most surprising case. The presence of `name()` means we invoke + /// `PersonName::from_list(&[])`. When that finishes parsing each of the zero nested + /// items it has received, it will then start filling in missing fields, using the + /// explicit field-level defaults for `first` and `middle`, while for `last` it will + /// use the `last` field from the container-level default. + #[test] + fn name_empty_list() { + let person = Person::from_derive_input(&parse_quote! { + #[person(name(), age = 5)] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.name.first, "Jane"); + assert_eq!(person.name.middle, ""); + assert_eq!(person.name.last, "Doe"); + } + + #[test] + fn no_name() { + let person = Person::from_derive_input(&parse_quote! { + #[person(age = 5)] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.age, 5); + assert_eq!( + person.name.first, "John", + "If `name` is not specified, `Person`'s field-level default should be used" + ); + assert_eq!(person.name.middle, "T"); + assert_eq!(person.name.last, "Doe"); + } +} + +mod implicit_default { + use darling::{util::Flag, FromDeriveInput}; + use syn::parse_quote; + + // No use of `darling(default)` here at all! + // This struct will fill in missing fields using FromMeta::from_none. + #[derive(FromDeriveInput)] + #[darling(attributes(person))] + struct Person { + first_name: String, + last_name: Option, + lefty: Flag, + } + + #[test] + fn missing_fields_fill() { + let person = Person::from_derive_input(&parse_quote! { + #[person(first_name = "James")] + struct Foo; + }) + .unwrap(); + + assert_eq!(person.first_name, "James"); + assert_eq!(person.last_name, None); + assert!(!person.lefty.is_present()); + } +} + +/// Test that a field-level implicit default using FromMeta::from_none is superseded +/// by the parent declaring `#[darling(default)]`. +mod overridden_implicit_default { + use darling::{util::Flag, FromDeriveInput}; + use syn::parse_quote; + + #[derive(FromDeriveInput)] + #[darling(default, attributes(person))] + struct Person { + first_name: String, + last_name: Option, + lefty: Flag, + } + + impl Default for Person { + fn default() -> Self { + Self { + first_name: "Jane".into(), + last_name: Some("Doe".into()), + lefty: Flag::default(), + } + } + } + + #[test] + fn fill_missing() { + let person = Person::from_derive_input(&parse_quote!( + #[person(last_name = "Archer")] + struct Foo; + )) + .unwrap(); + + assert_eq!(person.first_name, "Jane"); + assert_eq!(person.last_name, Some("Archer".into())); + assert!(!person.lefty.is_present()); + } +} diff --git a/vendor/darling/tests/enums_default.rs b/vendor/darling/tests/enums_default.rs new file mode 100644 index 00000000..fa6829ed --- /dev/null +++ b/vendor/darling/tests/enums_default.rs @@ -0,0 +1,44 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta, PartialEq, Eq)] +enum Dolor { + Sit, + #[darling(word)] + Amet, +} + +impl Default for Dolor { + fn default() -> Self { + Dolor::Sit + } +} + +#[derive(FromDeriveInput)] +#[darling(attributes(hello))] +struct Receiver { + #[darling(default)] + example: Dolor, +} + +#[test] +fn missing_meta() { + let di = Receiver::from_derive_input(&parse_quote! { + #[hello] + struct Example; + }) + .unwrap(); + + assert_eq!(Dolor::Sit, di.example); +} + +#[test] +fn empty_meta() { + let di = Receiver::from_derive_input(&parse_quote! { + #[hello(example)] + struct Example; + }) + .unwrap(); + + assert_eq!(Dolor::Amet, di.example); +} diff --git a/vendor/darling/tests/enums_newtype.rs b/vendor/darling/tests/enums_newtype.rs new file mode 100644 index 00000000..658661bb --- /dev/null +++ b/vendor/darling/tests/enums_newtype.rs @@ -0,0 +1,127 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, Default, PartialEq, Eq, FromMeta)] +#[darling(default)] +pub struct Amet { + hello: bool, + world: String, +} + +#[derive(Debug, PartialEq, Eq, FromMeta)] +#[darling(rename_all = "snake_case")] +pub enum Lorem { + Ipsum(bool), + Dolor(String), + OptDolor(Option), + Sit(Amet), +} + +#[derive(Debug, PartialEq, Eq, FromDeriveInput)] +#[darling(attributes(hello))] +pub struct Holder { + lorem: Lorem, +} + +impl PartialEq for Holder { + fn eq(&self, other: &Lorem) -> bool { + self.lorem == *other + } +} + +#[test] +fn bool_word() { + let di = parse_quote! { + #[hello(lorem(ipsum))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Ipsum(true)); +} + +#[test] +fn bool_literal() { + let di = parse_quote! { + #[hello(lorem(ipsum = false))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Ipsum(false)); +} + +#[test] +fn string_literal() { + let di = parse_quote! { + #[hello(lorem(dolor = "Hello"))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!(pr, Lorem::Dolor("Hello".to_string())); +} + +#[test] +fn option_literal() { + let holder = Holder::from_derive_input(&parse_quote! { + #[hello(lorem(opt_dolor = "Hello"))] + struct Bar; + }) + .unwrap(); + + assert_eq!(holder.lorem, Lorem::OptDolor(Some("Hello".into()))); +} + +/// Make sure newtype variants whose field's type's `from_none` return +/// a `Some` can be used in key-value form. +#[test] +fn option_word_only() { + let holder = Holder::from_derive_input(&parse_quote! { + #[hello(lorem = "opt_dolor")] + struct Bar; + }) + .unwrap(); + + assert_eq!(holder.lorem, Lorem::OptDolor(None)); +} + +/// Make sure that newtype variants which don't produce a from_none value +/// do not allow the word form. +#[test] +#[should_panic] +fn word_only_fails_for_non_option() { + Holder::from_derive_input(&parse_quote! { + #[hello(lorem = "dolor")] + struct Bar; + }) + .unwrap(); +} + +#[test] +fn struct_nested() { + let di = parse_quote! { + #[hello(lorem(sit(world = "Hello", hello = false)))] + pub struct Bar; + }; + + let pr = Holder::from_derive_input(&di).unwrap(); + assert_eq!( + pr, + Lorem::Sit(Amet { + hello: false, + world: "Hello".to_string(), + }) + ); +} + +#[test] +#[should_panic] +fn format_mismatch() { + let di = parse_quote! { + #[hello(lorem(dolor(world = "Hello", hello = false)))] + pub struct Bar; + }; + + Holder::from_derive_input(&di).unwrap(); +} diff --git a/vendor/darling/tests/enums_struct.rs b/vendor/darling/tests/enums_struct.rs new file mode 100644 index 00000000..cae4cd5c --- /dev/null +++ b/vendor/darling/tests/enums_struct.rs @@ -0,0 +1,15 @@ +#![allow(dead_code)] + +//! Test expansion of enums which have struct variants. + +use darling::FromMeta; +#[derive(Debug, FromMeta)] +#[darling(rename_all = "snake_case")] +enum Message { + Hello { user: String, silent: bool }, + Ping, + Goodbye { user: String }, +} + +#[test] +fn expansion() {} diff --git a/vendor/darling/tests/enums_unit.rs b/vendor/darling/tests/enums_unit.rs new file mode 100644 index 00000000..34e01356 --- /dev/null +++ b/vendor/darling/tests/enums_unit.rs @@ -0,0 +1,14 @@ +//! Test expansion of enum variants which have no associated data. + +use darling::FromMeta; + +#[derive(Debug, FromMeta)] +#[darling(rename_all = "snake_case")] +enum Pattern { + Owned, + Immutable, + Mutable, +} + +#[test] +fn expansion() {} diff --git a/vendor/darling/tests/error.rs b/vendor/darling/tests/error.rs new file mode 100644 index 00000000..7274e408 --- /dev/null +++ b/vendor/darling/tests/error.rs @@ -0,0 +1,54 @@ +//! In case of bad input, parsing should fail. The error should have locations set in derived implementations. + +// The use of fields in debug print commands does not count as "used", +// which causes the fields to trigger an unwanted dead code warning. +#![allow(dead_code)] + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta)] +struct Dolor { + #[darling(rename = "amet")] + sit: bool, + world: bool, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(from_ident, attributes(hello))] +struct Lorem { + ident: syn::Ident, + ipsum: Dolor, +} + +impl From for Lorem { + fn from(ident: syn::Ident) -> Self { + Lorem { + ident, + ipsum: Dolor { + sit: false, + world: true, + }, + } + } +} + +#[test] +fn parsing_fail() { + let di = parse_quote! { + #[hello(ipsum(amet = "yes", world = false))] + pub struct Foo; + }; + + println!("{}", Lorem::from_derive_input(&di).unwrap_err()); +} + +#[test] +fn missing_field() { + let di = parse_quote! { + #[hello(ipsum(amet = true))] + pub struct Foo; + }; + + println!("{}", Lorem::from_derive_input(&di).unwrap_err()); +} diff --git a/vendor/darling/tests/flatten.rs b/vendor/darling/tests/flatten.rs new file mode 100644 index 00000000..d7c533cf --- /dev/null +++ b/vendor/darling/tests/flatten.rs @@ -0,0 +1,205 @@ +use darling::{util::Flag, FromDeriveInput, FromMeta}; +use proc_macro2::Ident; +use syn::parse_quote; + +#[derive(FromMeta)] +struct Vis { + public: Flag, + private: Flag, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(sample))] +struct Example { + ident: Ident, + label: String, + #[darling(flatten)] + visibility: Vis, +} + +#[test] +fn happy_path() { + let di = Example::from_derive_input(&parse_quote! { + #[sample(label = "Hello", public)] + struct Demo {} + }); + + let parsed = di.unwrap(); + assert_eq!(parsed.ident, "Demo"); + assert_eq!(&parsed.label, "Hello"); + assert!(parsed.visibility.public.is_present()); + assert!(!parsed.visibility.private.is_present()); +} + +#[test] +fn unknown_field_errors() { + let errors = Example::from_derive_input(&parse_quote! { + #[sample(label = "Hello", republic)] + struct Demo {} + }) + .map(|_| "Should have failed") + .unwrap_err(); + + assert_eq!(errors.len(), 1); +} + +/// This test demonstrates flatten being used recursively. +/// Fields are expected to be consumed by the outermost matching struct. +#[test] +fn recursive_flattening() { + #[derive(FromMeta)] + struct Nested2 { + above: isize, + below: isize, + port: Option, + } + + #[derive(FromMeta)] + struct Nested1 { + port: isize, + starboard: isize, + #[darling(flatten)] + z_axis: Nested2, + } + + #[derive(FromMeta)] + struct Nested0 { + fore: isize, + aft: isize, + #[darling(flatten)] + cross_section: Nested1, + } + + #[derive(FromDeriveInput)] + #[darling(attributes(boat))] + struct BoatPosition { + #[darling(flatten)] + pos: Nested0, + } + + let parsed = BoatPosition::from_derive_input(&parse_quote! { + #[boat(fore = 1, aft = 1, port = 10, starboard = 50, above = 20, below = -3)] + struct Demo; + }) + .unwrap(); + + assert_eq!(parsed.pos.fore, 1); + assert_eq!(parsed.pos.aft, 1); + + assert_eq!(parsed.pos.cross_section.port, 10); + assert_eq!(parsed.pos.cross_section.starboard, 50); + + assert_eq!(parsed.pos.cross_section.z_axis.above, 20); + assert_eq!(parsed.pos.cross_section.z_axis.below, -3); + // This should be `None` because the `port` field in `Nested1` consumed + // the field before the leftovers were passed to `Nested2::from_list`. + assert_eq!(parsed.pos.cross_section.z_axis.port, None); +} + +/// This test confirms that a collection - in this case a HashMap - can +/// be used with `flatten`. +#[test] +fn flattening_into_hashmap() { + #[derive(FromDeriveInput)] + #[darling(attributes(ca))] + struct Catchall { + hello: String, + volume: usize, + #[darling(flatten)] + others: std::collections::HashMap, + } + + let parsed = Catchall::from_derive_input(&parse_quote! { + #[ca(hello = "World", volume = 10, first_name = "Alice", second_name = "Bob")] + struct Demo; + }) + .unwrap(); + + assert_eq!(parsed.hello, "World"); + assert_eq!(parsed.volume, 10); + assert_eq!(parsed.others.len(), 2); +} + +#[derive(FromMeta)] +#[allow(dead_code)] +struct Person { + first: String, + last: String, + parent: Option>, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(v))] +#[allow(dead_code)] +struct Outer { + #[darling(flatten)] + owner: Person, + #[darling(default)] + blast: bool, +} + +/// This test makes sure that field names from parent structs are not inappropriately +/// offered as alternates for unknown field errors in child structs. +/// +/// A naive implementation that tried to offer all the flattened fields for "did you mean" +/// could inspect all errors returned by the flattened field's `from_list` call and add the +/// parent's field names as alternates to all unknown field errors. +/// +/// THIS WOULD BE INCORRECT. Those unknown field errors may have already come from +/// child fields within the flattened struct, where the parent's field names are not valid. +#[test] +fn do_not_suggest_invalid_alts() { + let errors = Outer::from_derive_input(&parse_quote! { + #[v(first = "Hello", last = "World", parent(first = "Hi", last = "Earth", blasts = "off"))] + struct Demo; + }) + .map(|_| "Should have failed") + .unwrap_err() + .to_string(); + + assert!( + !errors.contains("`blast`"), + "Should not contain `blast`: {}", + errors + ); +} + +#[test] +#[cfg(feature = "suggestions")] +fn suggest_valid_parent_alts() { + let errors = Outer::from_derive_input(&parse_quote! { + #[v(first = "Hello", bladt = false, last = "World", parent(first = "Hi", last = "Earth"))] + struct Demo; + }) + .map(|_| "Should have failed") + .unwrap_err() + .to_string(); + assert!( + errors.contains("`blast`"), + "Should contain `blast` as did-you-mean suggestion: {}", + errors + ); +} + +/// Make sure that flatten works with smart pointer types, e.g. `Box`. +/// +/// The generated `flatten` impl directly calls `FromMeta::from_list` +/// rather than calling `from_meta`, and the default impl of `from_list` +/// will return an unsupported format error; this test ensures that the +/// smart pointer type is properly forwarding the `from_list` call. +#[test] +fn flattening_to_box() { + #[derive(FromDeriveInput)] + #[darling(attributes(v))] + struct Example { + #[darling(flatten)] + items: Box, + } + + let when_omitted = Example::from_derive_input(&parse_quote! { + struct Demo; + }) + .unwrap(); + + assert!(!when_omitted.items.public.is_present()); +} diff --git a/vendor/darling/tests/flatten_error_accumulation.rs b/vendor/darling/tests/flatten_error_accumulation.rs new file mode 100644 index 00000000..5cd6280d --- /dev/null +++ b/vendor/darling/tests/flatten_error_accumulation.rs @@ -0,0 +1,45 @@ +use darling::{util::Flag, Error, FromDeriveInput, FromMeta}; +use proc_macro2::Ident; +use syn::parse_quote; + +#[derive(FromMeta)] +#[darling(and_then = Self::validate)] +struct Vis { + public: Flag, + private: Flag, +} + +impl Vis { + fn validate(self) -> darling::Result { + if self.public.is_present() && self.private.is_present() { + return Err(Error::custom("Cannot be both public and private")); + } + + Ok(self) + } +} + +#[derive(FromDeriveInput)] +#[darling(attributes(sample))] +#[allow(dead_code)] +struct Example { + ident: Ident, + label: String, + volume: usize, + #[darling(flatten)] + visibility: Vis, +} + +#[test] +fn many_errors() { + let e = Example::from_derive_input(&parse_quote! { + #[sample(volume = 10, public, private)] + struct Demo {} + }) + .map(|_| "Should have failed") + .unwrap_err(); + + // We are expecting an error from the Vis::validate method and an error for the + // missing `label` field. + assert_eq!(e.len(), 2); +} diff --git a/vendor/darling/tests/flatten_from_field.rs b/vendor/darling/tests/flatten_from_field.rs new file mode 100644 index 00000000..3338f04a --- /dev/null +++ b/vendor/darling/tests/flatten_from_field.rs @@ -0,0 +1,84 @@ +use darling::{ast, util::Ignored, FromDeriveInput, FromField, FromMeta}; +use proc_macro2::{Ident, Span}; +use syn::parse_quote; + +#[derive(FromMeta)] +struct Vis { + #[darling(default)] + public: bool, + #[darling(default)] + private: bool, +} + +#[derive(FromField)] +#[darling(attributes(v))] +struct Field { + ident: Option, + example: Option, + #[darling(flatten)] + visibility: Vis, +} + +#[derive(FromDeriveInput)] +#[darling(attributes(v))] +struct Input { + data: ast::Data, +} + +#[test] +fn field_flattens() { + let di = Input::from_derive_input(&parse_quote! { + struct Demo { + #[v(public, example = "world")] + hello: String + } + }) + .unwrap(); + + let fields = di.data.take_struct().unwrap(); + let first_field = fields.into_iter().next().unwrap(); + assert_eq!( + first_field.ident, + Some(Ident::new("hello", Span::call_site())) + ); + assert!(first_field.visibility.public); + assert!(!first_field.visibility.private); + assert_eq!(first_field.example.unwrap(), "world"); +} + +#[test] +fn field_flattens_with_no_field_level_attributes() { + let di = Input::from_derive_input(&parse_quote! { + struct Demo { + hello: String + } + }) + .unwrap(); + + let fields = di.data.take_struct().unwrap(); + let first_field = fields.into_iter().next().unwrap(); + assert_eq!( + first_field.ident, + Some(Ident::new("hello", Span::call_site())) + ); + assert!(!first_field.visibility.public); + assert!(!first_field.visibility.private); + assert_eq!(first_field.example, None); +} + +#[test] +fn field_flattens_across_attributes() { + let di = Input::from_derive_input(&parse_quote! { + struct Demo { + #[v(public)] + #[v(private)] + hello: String + } + }) + .unwrap(); + + let fields = di.data.take_struct().unwrap(); + let first_field = fields.into_iter().next().unwrap(); + assert!(first_field.visibility.public); + assert!(first_field.visibility.private); +} diff --git a/vendor/darling/tests/forward_attrs_to_from_attributes.rs b/vendor/darling/tests/forward_attrs_to_from_attributes.rs new file mode 100644 index 00000000..292cd210 --- /dev/null +++ b/vendor/darling/tests/forward_attrs_to_from_attributes.rs @@ -0,0 +1,22 @@ +use darling::FromAttributes; +use syn::parse_quote; + +#[derive(Default, darling::FromAttributes)] +#[darling(attributes(builder), forward_attrs)] +struct Params { + default: Option, + attrs: Vec, +} + +#[test] +fn forward_attrs_with_field() { + let input: syn::DeriveInput = parse_quote! { + #[doc = "Hello"] + #[builder(default = 15)] + struct Example; + }; + + let parsed = Params::from_attributes(&input.attrs).unwrap(); + assert!(parsed.default.is_some()); + assert_eq!(parsed.attrs.len(), 1); +} diff --git a/vendor/darling/tests/from_generics.rs b/vendor/darling/tests/from_generics.rs new file mode 100644 index 00000000..e2cc99ee --- /dev/null +++ b/vendor/darling/tests/from_generics.rs @@ -0,0 +1,175 @@ +//! Tests for `FromGenerics`, and - indirectly - `FromGenericParam`. +//! These tests assume `FromTypeParam` is working and only look at whether the wrappers for magic +//! fields are working as expected. + +use darling::{ + ast::{self, GenericParamExt}, + util::{Ignored, WithOriginal}, + FromDeriveInput, FromTypeParam, Result, +}; + +#[derive(FromDeriveInput)] +#[darling(attributes(lorem))] +struct MyReceiver { + pub generics: ast::Generics>, +} + +#[derive(FromTypeParam)] +#[darling(attributes(lorem))] +struct MyTypeParam { + pub ident: syn::Ident, + #[darling(default)] + pub foo: bool, + pub bar: Option, +} + +fn fdi(src: &str) -> Result { + FromDeriveInput::from_derive_input(&syn::parse_str(src).expect("Source parses")) +} + +/// Verify that `ast::Generics` is populated correctly when there is no generics declaration +#[test] +fn no_generics() { + let rec: MyReceiver = fdi("struct Baz;").expect("Input is well-formed"); + assert!(rec.generics.where_clause.is_none()); + assert_eq!(rec.generics.params.len(), 0); +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +fn expand_some() { + let rec: MyReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U); + "#) + .expect("Input is well-formed"); + assert!(rec.generics.where_clause.is_none()); + + // Make sure we've preserved the lifetime param, though we don't do anything with it. + assert!(rec.generics.params[0].as_lifetime_param().is_some()); + + let mut ty_param_iter = rec.generics.type_params(); + + let first = ty_param_iter + .next() + .expect("type_params should not be empty"); + assert!(first.bar.is_none()); + assert!(first.foo); + assert_eq!(first.ident, "T"); + + let second = ty_param_iter + .next() + .expect("type_params should have a second value"); + assert_eq!( + second + .bar + .as_ref() + .expect("Second type param should set bar"), + "x" + ); + assert_eq!(second.foo, false); + assert_eq!(second.ident, "U"); +} + +/// Verify ≤0.4.1 behavior - where `generics` had to be `syn::Generics` - keeps working. +#[test] +fn passthrough() { + #[derive(FromDeriveInput)] + struct PassthroughReceiver { + pub generics: syn::Generics, + } + + let rec: PassthroughReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U); + "#) + .expect("Input is well-formed"); + + let mut type_param_iter = rec.generics.type_params(); + assert!(type_param_iter.next().is_some()); +} + +/// Verify that `where_clause` is passed through when it exists. +/// As of 0.4.1, there is no `FromWhereClause` trait, so other types aren't supported +/// for that field. +#[test] +fn where_clause() { + let rec: MyReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into; + "#) + .expect("Input is well-formed"); + + assert!(rec.generics.where_clause.is_some()); +} + +/// Test that `WithOriginal` works for generics. +#[test] +fn with_original() { + #[derive(FromDeriveInput)] + struct WorigReceiver { + generics: WithOriginal>, syn::Generics>, + } + + let rec: WorigReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into; + "#) + .expect("Input is well-formed"); + + // Make sure we haven't lost anything in the conversion + assert_eq!(rec.generics.parsed.params.len(), 3); + assert_eq!(rec.generics.original.params.len(), 3); + + let parsed_t: &MyTypeParam = rec.generics.parsed.params[1] + .as_type_param() + .expect("Second argument should be type param"); + + // Make sure the first type param in each case is T + assert_eq!(parsed_t.ident, "T"); + assert_eq!( + rec.generics + .original + .type_params() + .next() + .expect("First type param should exist") + .ident, + "T" + ); + + // Make sure we actually parsed the first type param + assert!(parsed_t.foo); + assert!(parsed_t.bar.is_none()); +} + +/// Make sure generics can be ignored +#[test] +fn ignored() { + #[derive(FromDeriveInput)] + struct IgnoredReceiver { + generics: Ignored, + } + + let rec: IgnoredReceiver = fdi(r#" + struct Baz< + 'a, + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(&'a T, U) where T: Into; + "#) + .expect("Input is well-formed"); + + assert_eq!(Ignored, rec.generics); +} diff --git a/vendor/darling/tests/from_meta.rs b/vendor/darling/tests/from_meta.rs new file mode 100644 index 00000000..886465c9 --- /dev/null +++ b/vendor/darling/tests/from_meta.rs @@ -0,0 +1,109 @@ +use darling::{Error, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta)] +struct Meta { + #[darling(default)] + meta1: Option, + #[darling(default)] + meta2: bool, +} + +#[test] +fn nested_meta_meta_value() { + let meta = Meta::from_list(&[parse_quote! { + meta1 = "thefeature" + }]) + .unwrap(); + assert_eq!(meta.meta1, Some("thefeature".to_string())); + assert!(!meta.meta2); +} + +#[test] +fn nested_meta_meta_bool() { + let meta = Meta::from_list(&[parse_quote! { + meta2 + }]) + .unwrap(); + assert_eq!(meta.meta1, None); + assert!(meta.meta2); +} + +#[test] +fn nested_meta_lit_string_errors() { + let err = Meta::from_list(&[parse_quote! { + "meta2" + }]) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::unsupported_format("literal").to_string() + ); +} + +#[test] +fn nested_meta_lit_integer_errors() { + let err = Meta::from_list(&[parse_quote! { + 2 + }]) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::unsupported_format("literal").to_string() + ); +} + +#[test] +fn nested_meta_lit_bool_errors() { + let err = Meta::from_list(&[parse_quote! { + true + }]) + .unwrap_err(); + assert_eq!( + err.to_string(), + Error::unsupported_format("literal").to_string() + ); +} + +/// Tests behavior of FromMeta implementation for enums. +mod enum_impl { + use darling::{Error, FromMeta}; + use syn::parse_quote; + + /// A playback volume. + #[derive(Debug, Clone, Copy, PartialEq, Eq, FromMeta)] + enum Volume { + Normal, + Low, + High, + #[darling(rename = "dB")] + Decibels(u8), + } + + #[test] + fn string_for_unit_variant() { + let volume = Volume::from_string("low").unwrap(); + assert_eq!(volume, Volume::Low); + } + + #[test] + fn single_value_list() { + let unit_variant = Volume::from_list(&[parse_quote!(high)]).unwrap(); + assert_eq!(unit_variant, Volume::High); + + let newtype_variant = Volume::from_list(&[parse_quote!(dB = 100)]).unwrap(); + assert_eq!(newtype_variant, Volume::Decibels(100)); + } + + #[test] + fn empty_list_errors() { + let err = Volume::from_list(&[]).unwrap_err(); + assert_eq!(err.to_string(), Error::too_few_items(1).to_string()); + } + + #[test] + fn multiple_values_list_errors() { + let err = Volume::from_list(&[parse_quote!(low), parse_quote!(dB = 20)]).unwrap_err(); + assert_eq!(err.to_string(), Error::too_many_items(1).to_string()); + } +} diff --git a/vendor/darling/tests/from_type_param.rs b/vendor/darling/tests/from_type_param.rs new file mode 100644 index 00000000..50ec3061 --- /dev/null +++ b/vendor/darling/tests/from_type_param.rs @@ -0,0 +1,59 @@ +use darling::FromTypeParam; +use syn::{parse_quote, DeriveInput, GenericParam, Ident, TypeParam}; + +#[derive(FromTypeParam)] +#[darling(attributes(lorem), from_ident)] +struct Lorem { + ident: Ident, + bounds: Vec, + foo: bool, + bar: Option, +} + +impl From for Lorem { + fn from(ident: Ident) -> Self { + Lorem { + ident, + foo: false, + bar: None, + bounds: Default::default(), + } + } +} + +fn extract_type(param: &GenericParam) -> &TypeParam { + match *param { + GenericParam::Type(ref ty) => ty, + _ => unreachable!("Not a type param"), + } +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +fn expand_many() { + let di: DeriveInput = parse_quote! { + struct Baz< + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized + >(T, U); + }; + + let params = di.generics.params; + + { + let ty = extract_type(¶ms[0]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.ident, "T"); + assert_eq!(lorem.foo, true); + assert_eq!(lorem.bar, None); + } + + { + let ty = extract_type(¶ms[1]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.ident, "U"); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, Some("x".to_string())); + assert_eq!(lorem.bounds.len(), 2); + } +} diff --git a/vendor/darling/tests/from_type_param_default.rs b/vendor/darling/tests/from_type_param_default.rs new file mode 100644 index 00000000..9d65665b --- /dev/null +++ b/vendor/darling/tests/from_type_param_default.rs @@ -0,0 +1,53 @@ +use darling::FromTypeParam; +use syn::{parse_quote, DeriveInput, GenericParam, TypeParam}; + +#[derive(Default, FromTypeParam)] +#[darling(attributes(lorem), default)] +struct Lorem { + foo: bool, + bar: Option, + default: Option, +} + +fn extract_type(param: &GenericParam) -> &TypeParam { + match *param { + GenericParam::Type(ref ty) => ty, + _ => unreachable!("Not a type param"), + } +} + +#[test] +#[allow(clippy::bool_assert_comparison)] +fn expand_many() { + let di: DeriveInput = parse_quote! { + struct Baz< + #[lorem(foo)] T, + #[lorem(bar = "x")] U: Eq + ?Sized, + #[lorem(foo = false)] V = (), + >(T, U, V); + }; + let params = di.generics.params; + + { + let ty = extract_type(¶ms[0]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, true); + assert_eq!(lorem.bar, None); + } + + { + let ty = extract_type(¶ms[1]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, Some("x".to_string())); + assert!(lorem.default.is_none()); + } + + { + let ty = extract_type(¶ms[2]); + let lorem = Lorem::from_type_param(ty).unwrap(); + assert_eq!(lorem.foo, false); + assert_eq!(lorem.bar, None); + assert!(lorem.default.is_some()); + } +} diff --git a/vendor/darling/tests/from_variant.rs b/vendor/darling/tests/from_variant.rs new file mode 100644 index 00000000..e89b8ff7 --- /dev/null +++ b/vendor/darling/tests/from_variant.rs @@ -0,0 +1,57 @@ +use darling::FromVariant; +use syn::{spanned::Spanned, Expr, ExprLit, LitInt}; + +#[derive(FromVariant)] +#[darling(from_ident, attributes(hello))] +#[allow(dead_code)] +pub struct Lorem { + ident: syn::Ident, + into: Option, + skip: Option, + discriminant: Option, + fields: darling::ast::Fields, +} + +impl From for Lorem { + fn from(ident: syn::Ident) -> Self { + Lorem { + ident, + into: Default::default(), + skip: Default::default(), + discriminant: None, + fields: darling::ast::Style::Unit.into(), + } + } +} + +#[test] +fn discriminant() { + let input: syn::DeriveInput = syn::parse_str( + r#" + pub enum Test { + Works = 1, + AlsoWorks = 2, + } + "#, + ) + .unwrap(); + + let span = input.span(); + if let syn::Data::Enum(enm) = input.data { + let lorem = Lorem::from_variant( + enm.variants + .first() + .expect("Hardcoded input has one variant"), + ) + .expect("FromVariant can process the discriminant"); + assert_eq!( + lorem.discriminant, + Some(Expr::Lit(ExprLit { + attrs: vec![], + lit: LitInt::new("1", span).into(), + })) + ) + } else { + panic!("Data should be enum"); + } +} diff --git a/vendor/darling/tests/generics.rs b/vendor/darling/tests/generics.rs new file mode 100644 index 00000000..ba65781f --- /dev/null +++ b/vendor/darling/tests/generics.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, Clone, FromMeta)] +struct Wrapper(pub T); + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(hello))] +struct Foo { + lorem: Wrapper, +} + +#[test] +fn expansion() { + let di = parse_quote! { + #[hello(lorem = "Hello")] + pub struct Foo; + }; + + Foo::::from_derive_input(&di).unwrap(); +} diff --git a/vendor/darling/tests/happy_path.rs b/vendor/darling/tests/happy_path.rs new file mode 100644 index 00000000..a56aee75 --- /dev/null +++ b/vendor/darling/tests/happy_path.rs @@ -0,0 +1,69 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Default, FromMeta, PartialEq, Debug)] +#[darling(default)] +struct Lorem { + ipsum: bool, + dolor: Option, +} + +#[derive(FromDeriveInput, PartialEq, Debug)] +#[darling(attributes(darling_demo))] +struct Core { + ident: syn::Ident, + vis: syn::Visibility, + generics: syn::Generics, + lorem: Lorem, +} + +#[derive(FromDeriveInput, PartialEq, Debug)] +#[darling(attributes(darling_demo))] +struct TraitCore { + ident: syn::Ident, + generics: syn::Generics, + lorem: Lorem, +} + +#[test] +fn simple() { + let di = parse_quote! { + #[derive(Foo)] + #[darling_demo(lorem(ipsum))] + pub struct Bar; + }; + + assert_eq!( + Core::from_derive_input(&di).unwrap(), + Core { + ident: parse_quote!(Bar), + vis: parse_quote!(pub), + generics: Default::default(), + lorem: Lorem { + ipsum: true, + dolor: None, + }, + } + ); +} + +#[test] +fn trait_type() { + let di = parse_quote! { + #[derive(Foo)] + #[darling_demo(lorem(dolor = "hello"))] + pub struct Bar; + }; + + assert_eq!( + TraitCore::from_derive_input(&di).unwrap(), + TraitCore { + ident: parse_quote!(Bar), + generics: Default::default(), + lorem: Lorem { + ipsum: false, + dolor: Some("hello".to_owned()), + } + } + ); +} diff --git a/vendor/darling/tests/hash_map.rs b/vendor/darling/tests/hash_map.rs new file mode 100644 index 00000000..881cd1cf --- /dev/null +++ b/vendor/darling/tests/hash_map.rs @@ -0,0 +1,42 @@ +use std::collections::HashMap; + +use darling::FromMeta; +use syn::{parse_quote, Attribute, Path}; + +#[derive(Debug, FromMeta, PartialEq, Eq)] +struct MapValue { + name: String, + #[darling(default)] + option: bool, +} + +#[test] +fn parse_map() { + let attr: Attribute = parse_quote! { + #[foo(first(name = "Hello", option), the::second(name = "Second"))] + }; + + let meta = attr.meta; + let map: HashMap = FromMeta::from_meta(&meta).unwrap(); + + let comparison: HashMap = vec![ + ( + parse_quote!(first), + MapValue { + name: "Hello".into(), + option: true, + }, + ), + ( + parse_quote!(the::second), + MapValue { + name: "Second".into(), + option: false, + }, + ), + ] + .into_iter() + .collect(); + + assert_eq!(comparison, map); +} diff --git a/vendor/darling/tests/multiple.rs b/vendor/darling/tests/multiple.rs new file mode 100644 index 00000000..b2243e62 --- /dev/null +++ b/vendor/darling/tests/multiple.rs @@ -0,0 +1,30 @@ +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(FromDeriveInput)] +#[darling(attributes(hello))] +#[allow(dead_code)] +struct Lorem { + ident: syn::Ident, + ipsum: Ipsum, +} + +#[derive(FromMeta)] +struct Ipsum { + #[darling(multiple)] + dolor: Vec, +} + +#[test] +fn expand_many() { + let di = parse_quote! { + #[hello(ipsum(dolor = "Hello", dolor = "World"))] + pub struct Baz; + }; + + let lorem: Lorem = Lorem::from_derive_input(&di).unwrap(); + assert_eq!( + lorem.ipsum.dolor, + vec!["Hello".to_string(), "World".to_string()] + ); +} diff --git a/vendor/darling/tests/newtype.rs b/vendor/darling/tests/newtype.rs new file mode 100644 index 00000000..10d02388 --- /dev/null +++ b/vendor/darling/tests/newtype.rs @@ -0,0 +1,26 @@ +//! A newtype struct should be able to derive `FromMeta` if its member implements it. + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromMeta, PartialEq, Eq)] +struct Lorem(bool); + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(newtype))] +struct DemoContainer { + lorem: Lorem, +} + +#[test] +fn generated() { + let di = parse_quote! { + #[derive(Baz)] + #[newtype(lorem = false)] + pub struct Foo; + }; + + let c = DemoContainer::from_derive_input(&di).unwrap(); + + assert_eq!(c.lorem, Lorem(false)); +} diff --git a/vendor/darling/tests/skip.rs b/vendor/darling/tests/skip.rs new file mode 100644 index 00000000..f930ca5d --- /dev/null +++ b/vendor/darling/tests/skip.rs @@ -0,0 +1,74 @@ +//! Test that skipped fields are not read into structs when they appear in input. + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, PartialEq, Eq, FromDeriveInput)] +#[darling(attributes(skip_test))] +pub struct Lorem { + ipsum: String, + + #[darling(skip)] + dolor: u8, +} + +/// Verify variant-level and field-level skip work correctly for enums. +#[derive(Debug, FromMeta)] +pub enum Sit { + Amet(bool), + + #[darling(skip)] + Foo { + hello: bool, + }, + + Bar { + hello: bool, + #[darling(skip)] + world: u8, + }, +} + +#[test] +fn verify_skipped_field_not_required() { + let di = parse_quote! { + #[skip_test(ipsum = "Hello")] + struct Baz; + }; + + assert_eq!( + Lorem::from_derive_input(&di).unwrap(), + Lorem { + ipsum: "Hello".to_string(), + dolor: 0, + } + ); +} + +/// This test verifies that a skipped field will still prefer an explicit default +/// over the default that would come from its field type. It would be incorrect for +/// `Defaulting::from_derive_input` to fail here, and it would be wrong for the value +/// of `dolor` to be `None`. +#[test] +fn verify_default_supersedes_from_none() { + fn default_dolor() -> Option { + Some(2) + } + + #[derive(Debug, PartialEq, Eq, FromDeriveInput)] + #[darling(attributes(skip_test))] + pub struct Defaulting { + #[darling(skip, default = "default_dolor")] + dolor: Option, + } + + let di = parse_quote! { + #[skip_test] + struct Baz; + }; + + assert_eq!( + Defaulting::from_derive_input(&di).unwrap(), + Defaulting { dolor: Some(2) } + ) +} diff --git a/vendor/darling/tests/split_declaration.rs b/vendor/darling/tests/split_declaration.rs new file mode 100644 index 00000000..8db11d0f --- /dev/null +++ b/vendor/darling/tests/split_declaration.rs @@ -0,0 +1,67 @@ +//! When input is split across multiple attributes on one element, +//! darling should collapse that into one struct. + +use darling::{Error, FromDeriveInput}; +use syn::parse_quote; + +#[derive(Debug, FromDeriveInput, PartialEq, Eq)] +#[darling(attributes(split))] +struct Lorem { + foo: String, + bar: bool, +} + +#[test] +fn split_attributes_accrue_to_instance() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(bar)] + pub struct Foo; + }; + + let parsed = Lorem::from_derive_input(&di).unwrap(); + assert_eq!( + parsed, + Lorem { + foo: "Hello".to_string(), + bar: true, + } + ); +} + +#[test] +fn duplicates_across_split_attrs_error() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(foo = "World", bar)] + pub struct Foo; + }; + + let pr = Lorem::from_derive_input(&di).unwrap_err(); + assert!(pr.has_span()); + assert_eq!(pr.to_string(), Error::duplicate_field("foo").to_string()); +} + +#[test] +fn multiple_errors_accrue_to_instance() { + let di = parse_quote! { + #[split(foo = "Hello")] + #[split(foo = "World")] + pub struct Foo; + }; + + let pr = Lorem::from_derive_input(&di); + let err: Error = pr.unwrap_err(); + assert_eq!(2, err.len()); + let mut errs = err.into_iter().peekable(); + assert_eq!( + errs.peek().unwrap().to_string(), + Error::duplicate_field("foo").to_string() + ); + assert!(errs.next().unwrap().has_span()); + assert_eq!( + errs.next().unwrap().to_string(), + Error::missing_field("bar").to_string() + ); + assert!(errs.next().is_none()); +} diff --git a/vendor/darling/tests/suggestions.rs b/vendor/darling/tests/suggestions.rs new file mode 100644 index 00000000..862084f6 --- /dev/null +++ b/vendor/darling/tests/suggestions.rs @@ -0,0 +1,44 @@ +#![allow(dead_code)] +#![cfg(feature = "suggestions")] + +use darling::{FromDeriveInput, FromMeta}; +use syn::parse_quote; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(suggest))] +struct Lorem { + ipsum: String, + dolor: Dolor, + // This field is included to make sure that skipped fields aren't suggested. + #[darling(skip)] + amet: bool, +} + +#[derive(Debug, FromMeta)] +struct Dolor { + sit: bool, +} + +#[test] +fn suggest_dolor() { + let input: syn::DeriveInput = parse_quote! { + #[suggest(ipsum = "Hello", dolorr(sit))] + pub struct Foo; + }; + + let result = Lorem::from_derive_input(&input).unwrap_err(); + assert_eq!(2, result.len()); + assert!(format!("{}", result).contains("Did you mean")); +} + +#[test] +fn dont_suggest_skipped_field() { + let input: syn::DeriveInput = parse_quote! { + #[suggest(ipsum = "Hello", dolor(sit), amt)] + pub struct Foo; + }; + + let result = Lorem::from_derive_input(&input).unwrap_err(); + assert_eq!(1, result.len()); + assert!(!format!("{}", result).contains("amet")); +} diff --git a/vendor/darling/tests/supports.rs b/vendor/darling/tests/supports.rs new file mode 100644 index 00000000..d6c75567 --- /dev/null +++ b/vendor/darling/tests/supports.rs @@ -0,0 +1,90 @@ +use darling::{ast, FromDeriveInput, FromVariant}; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_variants), supports(enum_any))] +pub struct Container { + // The second type parameter can be anything that implements FromField, since + // FromDeriveInput will produce an error if given a struct. + data: ast::Data, +} + +#[derive(Default, Debug, FromVariant)] +#[darling(default, attributes(from_variants), supports(newtype, unit))] +pub struct Variant { + into: Option, + skip: Option, +} + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(from_struct), supports(struct_named))] +pub struct StructContainer { + // The second type parameter can be anything that implements FromVariant, since + // FromDeriveInput will produce an error if given an enum. + data: ast::Data<(), syn::Field>, +} + +mod source { + use syn::{parse_quote, DeriveInput}; + + pub fn newtype_enum() -> DeriveInput { + parse_quote! { + enum Hello { + World(bool), + String(String), + } + } + } + + pub fn named_field_enum() -> DeriveInput { + parse_quote! { + enum Hello { + Foo(u16), + World { + name: String + }, + } + } + } + + pub fn empty_enum() -> DeriveInput { + parse_quote! { + enum Hello {} + } + } + + pub fn named_struct() -> DeriveInput { + parse_quote! { + struct Hello { + world: bool, + } + } + } + + pub fn tuple_struct() -> DeriveInput { + parse_quote! { struct Hello(String, bool); } + } +} + +#[test] +fn enum_newtype_or_unit() { + // Should pass + let container = Container::from_derive_input(&source::newtype_enum()).unwrap(); + assert!(container.data.is_enum()); + + // Should error + Container::from_derive_input(&source::named_field_enum()).unwrap_err(); + Container::from_derive_input(&source::named_struct()).unwrap_err(); +} + +#[test] +fn struct_named() { + // Should pass + let container = StructContainer::from_derive_input(&source::named_struct()).unwrap(); + assert!(container.data.is_struct()); + + // Should fail + StructContainer::from_derive_input(&source::tuple_struct()).unwrap_err(); + StructContainer::from_derive_input(&source::named_field_enum()).unwrap_err(); + StructContainer::from_derive_input(&source::newtype_enum()).unwrap_err(); + StructContainer::from_derive_input(&source::empty_enum()).unwrap_err(); +} diff --git a/vendor/darling/tests/unsupported_attributes.rs b/vendor/darling/tests/unsupported_attributes.rs new file mode 100644 index 00000000..c0143cec --- /dev/null +++ b/vendor/darling/tests/unsupported_attributes.rs @@ -0,0 +1,31 @@ +use darling::FromDeriveInput; +use syn::{parse_quote, Ident, LitStr, Path}; + +#[derive(Debug, FromDeriveInput)] +#[darling(supports(struct_unit), attributes(bar))] +pub struct Bar { + pub ident: Ident, + pub st: Path, + pub file: LitStr, +} + +/// Per [#96](https://github.com/TedDriggs/darling/issues/96), make sure that an +/// attribute which isn't a valid meta gets an error. +/// Properties can be split across multiple attributes; this test ensures that one +/// non-meta attribute does not interfere with the parsing of other, well-formed attributes. +#[test] +fn non_meta_attribute_does_not_block_others() { + let di = parse_quote! { + #[derive(Bar)] + #[bar(st = RocketEngine: Debug)] + #[bar(file = "motors/example_6.csv")] + pub struct EstesC6; + }; + + let errors: darling::Error = Bar::from_derive_input(&di).unwrap_err().flatten(); + // The number of errors here is 2: + // - The parsing error caused by a where-clause body where it doesn't belong + // - The missing `st` value because the parsing failure blocked that attribute from + // being read. + assert_eq!(2, errors.len()); +} diff --git a/vendor/darling_core/.cargo-checksum.json b/vendor/darling_core/.cargo-checksum.json new file mode 100644 index 00000000..1013c262 --- /dev/null +++ b/vendor/darling_core/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"d566f8998134a7647338af18d9eae4fa1fffb200dabb0eb45ed22c2f9bf404d7","LICENSE":"8ea93490d74a5a1b1af3ff71d786271b3f1e5f0bea79ac16e02ec533cef040d6","src/ast/data.rs":"dd7c64af33afd0224d06367fc8fefa2e8e25ed7edfb6f9e5d8dc02e4baca0fdb","src/ast/generics.rs":"f58bc7cf6be6aabde290f965018bdea236fc40c3b3d234b1f47a101f3d286179","src/ast/mod.rs":"58a58eeb1db7682e5994732cc8eb04088f6ca662805460ef443cf089e5c24e2c","src/codegen/attr_extractor.rs":"9ec3e79a7659bdff066bf1b9ac92e2c8ef63e901e5ba98ab35d7eacf6f0dd7dc","src/codegen/attrs_field.rs":"e06e0830edb63315b40e139c5b99d49429f0949b4fc9ee7c6e20219189e13ffb","src/codegen/default_expr.rs":"5486c8dc264e3bb8be2a871f3258f56ed2812ae39b1eb9f0d16006605407027f","src/codegen/error.rs":"4ef086317234a161bec493413ba38d842cbbecd0b9610dad0a25fe8883c75d3b","src/codegen/field.rs":"15e812bf5f97117ec5108552d89b5ec0b77a6465fcc2f4a3bd9e0ed2236f6902","src/codegen/from_attributes_impl.rs":"07f4eed890028df8f83e1f068eacfddd8a5464159c02b52832f9b811eeaf3524","src/codegen/from_derive_impl.rs":"2a0c8140653f5ef4542406e053ab263e33ab01750d8e8fd415d32c38b7fe747e","src/codegen/from_field.rs":"8e7cd4bb41908ea4c2f2bff119cb8e965303c2eb892ef8c518db2d0e78ed8852","src/codegen/from_meta_impl.rs":"9180f209332226100cdbe257480edcc4a2c2689ecd9e5e1e71e8b65bd9023098","src/codegen/from_type_param.rs":"97c4cb643681a9268d41e8e87114427e6561f58a22ec31c6acac47c26a220346","src/codegen/from_variant_impl.rs":"3530dbe1d6187e65f1fdbcfbeb79eb2838b6940614de912b5e06c2a35aa9f747","src/codegen/mod.rs":"38ee48646cf768b02199f52695515d9d43ae8e1d23cc3455b39eb8d50540dce3","src/codegen/outer_from_impl.rs":"b1e63838daed79c8d1c024ca4c88388f32b51454c5a86241717d68d3c3c92414","src/codegen/postfix_transform.rs":"41c84a239c15671e5a9cb8ce9fbb1b907f20aebe30d5dea4f04f004e3aa584c1","src/codegen/trait_impl.rs":"5b1d706d0c7a2ad99508fe143e1204306742bd1c21cbc1a7f73614f11ddbf8e8","src/codegen/variant.rs":"0050d5d37196e283b78a327782cbac9efce314f42cd4d0840f70a72fc9d8a515","src/codegen/variant_data.rs":"0cd8c404d8cb4228a15139938ff4af90b629cec4ccf78caff3ecbf40a252d2cd","src/derive.rs":"d35f35233eea28bc66bf6f738358415d650741560ca56f8deaee9465b3e88b2a","src/error/child.rs":"a6cc6e21b3a424150a764b2b9a8ffbc525722ccb4c372e197ded5a39021439fc","src/error/kind.rs":"26957bf705802c29fdaa004ee86d6ccaa758070f1355aa4abe42156618c39ea8","src/error/mod.rs":"0aba7222de6316b2dad32e8128b77eb7241e597b8f03811f8fe410af7a7670dc","src/from_attributes.rs":"9c98a34eccdb66526711793d6d00bd5216de1d0e9d3755133996242a27efe272","src/from_derive_input.rs":"a60aba72ebd4deddd6bb9919995652f90aafdf88f6109c00c1a1c4459e439049","src/from_field.rs":"1e22b7750843b6a018fe75ae1510fb9252343be99ab02d2093881421e87d867d","src/from_generic_param.rs":"bdabc80f49212501e6e3574c7e6c03b4e453d0fe241ac46d465a5f004381f4c9","src/from_generics.rs":"b0a156179b2d1d88467183649afc97405403b01a7fdae39e4df8392f6b9f500c","src/from_meta.rs":"b4ca7c37bdfeac60c2a40979796d4373493705f73d316eb29d769f84632604a8","src/from_type_param.rs":"0c8930a42e1f0720429aa968f97f938e207460232dd2169cbf8efec12e7c6f5a","src/from_variant.rs":"dd27ffef65ceea0e68809afde7df82d3751cdedc248773062637aa8c146da6e7","src/lib.rs":"34808fd70c0c871c1eba5636530ebc5792788a1141999aa7165edabe66cfe9e8","src/macros_private.rs":"4373c36e75d516c340fc9b13c52b471d823fff9997cb7faeeb5f93b11d40d0b4","src/macros_public.rs":"7d2ce0c5026227ef7854db11d7a885ad891255438b2e49bbdfda56fa2f92feec","src/options/core.rs":"41936931c0b505663d577bc2a0338295e86ed29e1082dd0d4f21fe1da6084b24","src/options/forward_attrs.rs":"9f98e9f15fe9ff14cdf5b93b23c6a897e15f2b8ba365972b9a6af6c2c9fbf900","src/options/from_attributes.rs":"b82356ab9a31dac1d4e2b12b02966ac068fa48df1b3492f889d45769c8b8dde3","src/options/from_derive.rs":"1e257762d1599df45ecc38112274ced0dbbe5e3faa76971b8bea75dad14763fb","src/options/from_field.rs":"93d025e43c8dba21e0e21d40ad8c0d9814eadb95b1ad3b2738156b1699f7e218","src/options/from_meta.rs":"77ab7106b571a48d4830c06dcf6e5c75fa9edab5013e6678a659d8ad8d084fb5","src/options/from_type_param.rs":"d8f68a9927c57321b3e4d717d15fe917ffa91ee561d7e298625bcaf25441d849","src/options/from_variant.rs":"104565175aeb238edf9ee68f7ffe2a665620796c50f7f9f3e1e3ef23751214aa","src/options/input_field.rs":"7233974b2eb905c47559d800d67b6cc5248f4e0ff5b8d7aac6ad9d7c3ebe72af","src/options/input_variant.rs":"b4e3d647fe90869ceff6a03a133132b1fd2b31611e49bd401246fa165a8b99b3","src/options/mod.rs":"a91a8419f9f9e7759a4a55a751b03771dfdd7a13511d6748c36f1304ec8aaa81","src/options/outer_from.rs":"ddc5ada98b5b5afc54ca42d8daba809b26ea58c13bd1b61b0a4d51a751193225","src/options/shape.rs":"4e676e0fce9c0cec625fcb391897dfc6b7cfc338912b76ff72cd6179affb836d","src/usage/generics_ext.rs":"b2d15e2ff75c47f43f3ce305b2108e800dd3d89e3a21fadf82bda455837b8090","src/usage/ident_set.rs":"30edb2f0a599284967e3c6b579da31e5f9b15f3dd67bc9a82d6335eb44133df0","src/usage/lifetimes.rs":"f3dcb3fab5370c07ddb19fa04079f8da1f035d671930d987ab3980f77ae7f3cc","src/usage/mod.rs":"e49adadfa8ffed27299d5bbf3c33e68e2c8c7411f89aef655f77e158be9dd642","src/usage/options.rs":"0491c995aad0d55783b24cce8a4e40f0f4435988c54ce2ded34763ac9b199fcf","src/usage/type_params.rs":"e009419b102ad56878706d411b44cb89f5a497e8d0abbb6769bcd2d4af53c90b","src/util/flag.rs":"b2ac32e1a140d2fd9e02d84c73e5db3807b52419841fb293d3144b8e8a847a44","src/util/ident_string.rs":"5e91c4e7f97fd02b114b56b9b77527fc0a00970954ed12dfb9c75adfeab59c82","src/util/ignored.rs":"099c015023b9be0870fb1c4c44ad00f87789ea13da25e2ca952132443e497214","src/util/mod.rs":"2412be5a804685b2570a7e4e42e595566dab7b52a595fd74ecb50453687aae5f","src/util/over_ride.rs":"b917e68750c898cba6159db98362bf1226ca856c8a0919ad9d3920ed82b76f54","src/util/parse_attribute.rs":"202b9c05b818caa3d54c05d9dc34a52c7f46c87996a65865c1623084b4fb8eb7","src/util/parse_expr.rs":"71d7eb900ec5460934ff2f1770e85acb68c7a2c317b1e2f9776b4f4d7258f9fa","src/util/path_list.rs":"939d0035b09ef7b361e654271f0eafde93be8208f6fb9a1caef9a3ee9e7e337d","src/util/path_to_string.rs":"c093354f91ab45e0be3c50d2d4356408f415c910f1569fb9275c5087110736f6","src/util/shape.rs":"dda17aa8a063b5023ae1f055bec2859f984ec32633f6cc55938a442252f07204","src/util/spanned_value.rs":"3a7efefb4085a52d8483ad29b8535633342c8c029354da9a41124ff9c44823ea","src/util/with_original.rs":"56ea20c03d07ebe1a8bc0ed220258f6cee5a3cf7192c0e07601fafda99404062"},"package":"95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"} \ No newline at end of file diff --git a/vendor/darling_core/Cargo.toml b/vendor/darling_core/Cargo.toml new file mode 100644 index 00000000..292a0377 --- /dev/null +++ b/vendor/darling_core/Cargo.toml @@ -0,0 +1,50 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.56" +name = "darling_core" +version = "0.20.10" +authors = ["Ted Driggs "] +description = """ +Helper crate for proc-macro library for reading attributes into structs when +implementing custom derives. Use https://crates.io/crates/darling in your code. +""" +license = "MIT" +repository = "https://github.com/TedDriggs/darling" + +[dependencies.fnv] +version = "1.0.7" + +[dependencies.ident_case] +version = "1.0.1" + +[dependencies.proc-macro2] +version = "1.0.37" + +[dependencies.quote] +version = "1.0.18" + +[dependencies.strsim] +version = "0.11.1" +optional = true + +[dependencies.syn] +version = "2.0.15" +features = [ + "full", + "extra-traits", +] + +[features] +diagnostics = [] +suggestions = ["strsim"] diff --git a/vendor/darling_core/LICENSE b/vendor/darling_core/LICENSE new file mode 100644 index 00000000..0b48eadc --- /dev/null +++ b/vendor/darling_core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ted Driggs + +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/vendor/darling_core/src/ast/data.rs b/vendor/darling_core/src/ast/data.rs new file mode 100644 index 00000000..03036d80 --- /dev/null +++ b/vendor/darling_core/src/ast/data.rs @@ -0,0 +1,517 @@ +use std::{slice, vec}; + +use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned, ToTokens}; +use syn::ext::IdentExt; +use syn::parse::Parser; +use syn::spanned::Spanned; +use syn::Token; + +use crate::usage::{ + self, IdentRefSet, IdentSet, LifetimeRefSet, LifetimeSet, UsesLifetimes, UsesTypeParams, +}; +use crate::{Error, FromField, FromVariant, Result}; + +/// A struct or enum body. +/// +/// `V` is the type which receives any encountered variants, and `F` receives struct fields. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Data { + Enum(Vec), + Struct(Fields), +} + +impl Data { + /// Creates an empty body of the same shape as the passed-in body. + /// + /// # Panics + /// This function will panic if passed `syn::Data::Union`. + pub fn empty_from(src: &syn::Data) -> Self { + match *src { + syn::Data::Enum(_) => Data::Enum(vec![]), + syn::Data::Struct(ref vd) => Data::Struct(Fields::empty_from(&vd.fields)), + syn::Data::Union(_) => panic!("Unions are not supported"), + } + } + + /// Creates an empty body of the same shape as the passed-in body. + /// + /// `darling` does not support unions; calling this function with a union body will return an error. + pub fn try_empty_from(src: &syn::Data) -> Result { + match *src { + syn::Data::Enum(_) => Ok(Data::Enum(vec![])), + syn::Data::Struct(ref vd) => Ok(Data::Struct(Fields::empty_from(&vd.fields))), + // This deliberately doesn't set a span on the error message, as the error is most useful if + // applied to the call site of the offending macro. Given that the message is very generic, + // putting it on the union keyword ends up being confusing. + syn::Data::Union(_) => Err(Error::custom("Unions are not supported")), + } + } + + /// Creates a new `Data<&'a V, &'a F>` instance from `Data`. + pub fn as_ref(&self) -> Data<&V, &F> { + match *self { + Data::Enum(ref variants) => Data::Enum(variants.iter().collect()), + Data::Struct(ref data) => Data::Struct(data.as_ref()), + } + } + + /// Applies a function `V -> U` on enum variants, if this is an enum. + pub fn map_enum_variants(self, map: T) -> Data + where + T: FnMut(V) -> U, + { + match self { + Data::Enum(v) => Data::Enum(v.into_iter().map(map).collect()), + Data::Struct(f) => Data::Struct(f), + } + } + + /// Applies a function `F -> U` on struct fields, if this is a struct. + pub fn map_struct_fields(self, map: T) -> Data + where + T: FnMut(F) -> U, + { + match self { + Data::Enum(v) => Data::Enum(v), + Data::Struct(f) => Data::Struct(f.map(map)), + } + } + + /// Applies a function to the `Fields` if this is a struct. + pub fn map_struct(self, mut map: T) -> Data + where + T: FnMut(Fields) -> Fields, + { + match self { + Data::Enum(v) => Data::Enum(v), + Data::Struct(f) => Data::Struct(map(f)), + } + } + + /// Consumes the `Data`, returning `Fields` if it was a struct. + pub fn take_struct(self) -> Option> { + match self { + Data::Enum(_) => None, + Data::Struct(f) => Some(f), + } + } + + /// Consumes the `Data`, returning `Vec` if it was an enum. + pub fn take_enum(self) -> Option> { + match self { + Data::Enum(v) => Some(v), + Data::Struct(_) => None, + } + } + + /// Returns `true` if this instance is `Data::Enum`. + pub fn is_enum(&self) -> bool { + match *self { + Data::Enum(_) => true, + Data::Struct(_) => false, + } + } + + /// Returns `true` if this instance is `Data::Struct`. + pub fn is_struct(&self) -> bool { + !self.is_enum() + } +} + +impl Data { + /// Attempt to convert from a `syn::Data` instance. + pub fn try_from(body: &syn::Data) -> Result { + match *body { + syn::Data::Enum(ref data) => { + let mut errors = Error::accumulator(); + let items = data + .variants + .iter() + .filter_map(|v| errors.handle(FromVariant::from_variant(v))) + .collect(); + + errors.finish_with(Data::Enum(items)) + } + syn::Data::Struct(ref data) => Ok(Data::Struct(Fields::try_from(&data.fields)?)), + // This deliberately doesn't set a span on the error message, as the error is most useful if + // applied to the call site of the offending macro. Given that the message is very generic, + // putting it on the union keyword ends up being confusing. + syn::Data::Union(_) => Err(Error::custom("Unions are not supported")), + } + } +} + +impl UsesTypeParams for Data { + fn uses_type_params<'a>( + &self, + options: &usage::Options, + type_set: &'a IdentSet, + ) -> IdentRefSet<'a> { + match *self { + Data::Struct(ref v) => v.uses_type_params(options, type_set), + Data::Enum(ref v) => v.uses_type_params(options, type_set), + } + } +} + +impl UsesLifetimes for Data { + fn uses_lifetimes<'a>( + &self, + options: &usage::Options, + lifetimes: &'a LifetimeSet, + ) -> LifetimeRefSet<'a> { + match *self { + Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes), + Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes), + } + } +} + +/// Equivalent to `syn::Fields`, but replaces the AST element with a generic. +#[derive(Debug, Clone)] +pub struct Fields { + pub style: Style, + pub fields: Vec, + span: Option, + __nonexhaustive: (), +} + +impl Fields { + /// Creates a new [`Fields`] struct. + pub fn new(style: Style, fields: Vec) -> Self { + Self { + style, + fields, + span: None, + __nonexhaustive: (), + } + } + + /// Adds a [`Span`] to [`Fields`]. + pub fn with_span(mut self, span: Span) -> Self { + if self.span.is_none() { + self.span = Some(span); + } + self + } + + pub fn empty_from(vd: &syn::Fields) -> Self { + Self::new(vd.into(), Vec::new()) + } + + /// Splits the `Fields` into its style and fields for further processing. + /// Returns an empty `Vec` for `Unit` data. + pub fn split(self) -> (Style, Vec) { + (self.style, self.fields) + } + + /// Returns true if this variant's data makes it a newtype. + pub fn is_newtype(&self) -> bool { + self.style == Style::Tuple && self.len() == 1 + } + + pub fn is_unit(&self) -> bool { + self.style.is_unit() + } + + pub fn is_tuple(&self) -> bool { + self.style.is_tuple() + } + + pub fn is_struct(&self) -> bool { + self.style.is_struct() + } + + pub fn as_ref(&self) -> Fields<&T> { + Fields { + style: self.style, + fields: self.fields.iter().collect(), + span: self.span, + __nonexhaustive: (), + } + } + + pub fn map(self, map: F) -> Fields + where + F: FnMut(T) -> U, + { + Fields { + style: self.style, + fields: self.fields.into_iter().map(map).collect(), + span: self.span, + __nonexhaustive: (), + } + } + + pub fn iter(&self) -> slice::Iter<'_, T> { + self.fields.iter() + } + + /// Returns the number of fields in the structure. + pub fn len(&self) -> usize { + self.fields.len() + } + + /// Returns `true` if the `Fields` contains no fields. + pub fn is_empty(&self) -> bool { + self.fields.is_empty() + } +} + +impl Fields { + pub fn try_from(fields: &syn::Fields) -> Result { + let mut errors = Error::accumulator(); + let items = { + match &fields { + syn::Fields::Named(fields) => fields + .named + .iter() + .filter_map(|field| { + errors.handle(FromField::from_field(field).map_err(|err| { + // There should always be an ident here, since this is a collection + // of named fields, but `syn` doesn't prevent someone from manually + // constructing an invalid collection so a guard is still warranted. + if let Some(ident) = &field.ident { + err.at(ident) + } else { + err + } + })) + }) + .collect(), + syn::Fields::Unnamed(fields) => fields + .unnamed + .iter() + .filter_map(|field| errors.handle(FromField::from_field(field))) + .collect(), + syn::Fields::Unit => vec![], + } + }; + + errors.finish()?; + + Ok(Self::new(fields.into(), items).with_span(fields.span())) + } +} + +impl ToTokens for Fields { + fn to_tokens(&self, tokens: &mut TokenStream) { + let fields = &self.fields; + // An unknown Span should be `Span::call_site()`; + // https://docs.rs/syn/1.0.12/syn/spanned/trait.Spanned.html#tymethod.span + let span = self.span.unwrap_or_else(Span::call_site); + + match self.style { + Style::Struct => { + let trailing_comma = { + if fields.is_empty() { + quote!() + } else { + quote!(,) + } + }; + + tokens.extend(quote_spanned![span => { #(#fields),* #trailing_comma }]); + } + Style::Tuple => { + tokens.extend(quote_spanned![span => ( #(#fields),* )]); + } + Style::Unit => {} + } + } +} + +impl PartialEq for Fields { + fn eq(&self, other: &Self) -> bool { + self.style == other.style && self.fields == other.fields + } +} + +impl Eq for Fields {} + +impl IntoIterator for Fields { + type Item = T; + type IntoIter = vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.fields.into_iter() + } +} + +impl From