summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikhil Benesch <nikhil.benesch@gmail.com>2020-12-10 20:46:58 -0500
committerJustus Winter <justus@sequoia-pgp.org>2021-10-05 11:46:38 +0200
commit341fdd29a9863e793c560e2a7207989c4f61d772 (patch)
tree38ffda8be4d3ebce675e6561a3a619882934495e
parentaa21e2404d9502eeea84ff39da03a85c971ea2d3 (diff)
openpgp: Add a RustCrypto backend.
- This adds a cryptographic backend based on the RustCrypto crates. The backend is marked as experimental, as the RustCrypto crates' authors state that they have not been audited and may not perform computations in constant time. Nevertheless, it may be useful in certain environments, e.g. WebAssembly. - The backend implements RSA, EdDSA and ECDH over Curve25519, IDEA, 3DES, CAST5, Blowfish, AES, Twofish, EAX, MD5, SHA1, RipeMD160, and the SHA2 family. - Notably missing are DSA, ElGamal, and ECDSA and ECDH over the NIST curves. - See #333.
-rw-r--r--.gitlab-ci.yml16
-rw-r--r--Cargo.lock238
-rw-r--r--openpgp/Cargo.toml34
-rw-r--r--openpgp/NEWS2
-rw-r--r--openpgp/README.md7
-rw-r--r--openpgp/build.rs6
-rw-r--r--openpgp/src/crypto/aead.rs8
-rw-r--r--openpgp/src/crypto/backend.rs5
-rw-r--r--openpgp/src/crypto/backend/rust.rs64
-rw-r--r--openpgp/src/crypto/backend/rust/aead.rs134
-rw-r--r--openpgp/src/crypto/backend/rust/asymmetric.rs473
-rw-r--r--openpgp/src/crypto/backend/rust/ecdh.rs99
-rw-r--r--openpgp/src/crypto/backend/rust/hash.rs80
-rw-r--r--openpgp/src/crypto/backend/rust/symmetric.rs199
14 files changed, 1358 insertions, 7 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 76218ecc..c30c5476 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -72,6 +72,22 @@ bullseye:
RUSTFLAGS: -D warnings -A unused-parens
after_script: []
+bullseye-crypto-rust:
+ tags:
+ - linux
+ stage: build
+ image: registry.gitlab.com/sequoia-pgp/build-docker-image/bullseye-prebuild:latest
+ dependencies:
+ - codespell
+ script:
+ - cargo run --manifest-path openpgp/Cargo.toml --no-default-features --features crypto-rust,compression,allow-experimental-crypto,allow-variable-time-crypto --example supported-algorithms
+ - cargo test --release --manifest-path openpgp/Cargo.toml --no-default-features --features crypto-rust,compression,allow-experimental-crypto,allow-variable-time-crypto
+ variables:
+ CARGO_TARGET_DIR: /target
+ CARGO_HOME: /cargo
+ RUSTFLAGS: -D warnings -A unused-parens
+ after_script: []
+
bullseye:arm64:
tags:
- docker-arm64
diff --git a/Cargo.lock b/Cargo.lock
index 50b3468c..efcea173 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -25,6 +25,37 @@ dependencies = [
]
[[package]]
+name = "aes"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
+dependencies = [
+ "aes-soft",
+ "aesni",
+ "cipher",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
+dependencies = [
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
+name = "aesni"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
+dependencies = [
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -189,7 +220,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
- "block-padding",
+ "block-padding 0.1.5",
"byte-tools",
"byteorder",
"generic-array 0.12.4",
@@ -205,6 +236,16 @@ dependencies = [
]
[[package]]
+name = "block-modes"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0"
+dependencies = [
+ "block-padding 0.2.1",
+ "cipher",
+]
+
+[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -214,6 +255,23 @@ dependencies = [
]
[[package]]
+name = "block-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
+[[package]]
+name = "blowfish"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32fa6a061124e37baba002e496d203e23ba3d7b73750be82dbfbc92913048a5b"
+dependencies = [
+ "byteorder",
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "bstr"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -331,6 +389,17 @@ dependencies = [
]
[[package]]
+name = "cast5"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1285caf81ea1f1ece6b24414c521e625ad0ec94d880625c20f2e65d8d3f78823"
+dependencies = [
+ "byteorder",
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "cc"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -449,6 +518,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]]
+name = "cpufeatures"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "cpuid-bool"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -625,6 +703,17 @@ dependencies = [
]
[[package]]
+name = "des"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b24e7c748888aa2fa8bce21d8c64a52efc810663285315ac7476f7197a982fae"
+dependencies = [
+ "byteorder",
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "diff"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1150,6 +1239,16 @@ dependencies = [
]
[[package]]
+name = "idea"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcdd4b114cf2265123bbdc5d32a39f96a343fbdf141267d2b5232b7e14caacb3"
+dependencies = [
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "idna"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1271,9 +1370,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.92"
+version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714"
+checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
[[package]]
name = "libm"
@@ -1308,6 +1407,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]]
+name = "md-5"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1470,6 +1580,17 @@ dependencies = [
]
[[package]]
+name = "num-bigint"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
+dependencies = [
+ "autocfg 1.0.1",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
name = "num-bigint-dig"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1482,7 +1603,10 @@ dependencies = [
"num-integer",
"num-iter",
"num-traits",
+ "rand 0.7.3",
+ "serde",
"smallvec",
+ "zeroize",
]
[[package]]
@@ -1595,6 +1719,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
+name = "pem"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
+dependencies = [
+ "base64",
+ "once_cell",
+ "regex",
+]
+
+[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1917,6 +2052,17 @@ dependencies = [
]
[[package]]
+name = "ripemd160"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "rpassword"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1927,6 +2073,28 @@ dependencies = [
]
[[package]]
+name = "rsa"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3648b669b10afeab18972c105e284a7b953a669b0be3514c27f9b17acab2f9cd"
+dependencies = [
+ "byteorder",
+ "digest 0.9.0",
+ "lazy_static",
+ "num-bigint-dig",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "pem",
+ "rand 0.7.3",
+ "sha2 0.9.3",
+ "simple_asn1",
+ "subtle",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
name = "rusqlite"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2141,22 +2309,33 @@ dependencies = [
name = "sequoia-openpgp"
version = "1.3.0"
dependencies = [
+ "aes",
"anyhow",
"backtrace",
"base64",
+ "block-modes",
+ "block-padding 0.2.1",
+ "blowfish",
"buffered-reader",
"bzip2",
+ "cast5",
"chrono",
+ "cipher",
"criterion",
+ "des",
+ "digest 0.9.0",
"dyn-clone",
"eax",
"ed25519-dalek",
"flate2",
+ "generic-array 0.14.4",
+ "idea",
"idna",
"lalrpop",
"lalrpop-util",
"lazy_static",
"libc",
+ "md-5",
"memsec",
"nettle",
"num-bigint-dig",
@@ -2164,12 +2343,19 @@ dependencies = [
"rand 0.7.3",
"regex",
"regex-syntax",
+ "ripemd160",
"rpassword",
+ "rsa",
+ "sha-1",
"sha1collisiondetection",
+ "sha2 0.9.3",
"thiserror",
+ "twofish",
+ "typenum",
"unicode-normalization",
"win-crypto-ng",
"winapi 0.3.9",
+ "x25519-dalek",
]
[[package]]
@@ -2262,6 +2448,19 @@ dependencies = [
]
[[package]]
+name = "sha-1"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if 1.0.0",
+ "cpufeatures",
+ "digest 0.9.0",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "sha1collisiondetection"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2319,6 +2518,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68"
[[package]]
+name = "simple_asn1"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b"
+dependencies = [
+ "chrono",
+ "num-bigint",
+ "num-traits",
+]
+
+[[package]]
name = "siphasher"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2613,6 +2823,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
+name = "twofish"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0028f5982f23ecc9a1bc3008ead4c664f843ed5d78acd3d213b99ff50c441bc2"
+dependencies = [
+ "byteorder",
+ "cipher",
+ "opaque-debug 0.3.0",
+]
+
+[[package]]
name = "typenum"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2842,6 +3063,17 @@ dependencies = [
]
[[package]]
+name = "x25519-dalek"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f"
+dependencies = [
+ "curve25519-dalek",
+ "rand_core 0.5.1",
+ "zeroize",
+]
+
+[[package]]
name = "zbase32"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml
index 1d1fa3de..cd285ebe 100644
--- a/openpgp/Cargo.toml
+++ b/openpgp/Cargo.toml
@@ -45,12 +45,33 @@ thiserror = "1.0.2"
backtrace = "0.3.3"
unicode-normalization = "0.1.9"
+# RustCrypto crates.
+aes = { version = "0.6.0", optional = true }
+block-modes = { version = "0.7.0", optional = true }
+block-padding = { version = "0.2.1", optional = true }
+blowfish = { version = "0.7.0", optional = true }
+cast5 = { version = "0.9.0", optional = true }
+cipher = { version = "0.2.5", optional = true, features = ["std"] }
+des = { version = "0.6.0", optional = true }
+digest = { version = "0.9.0", optional = true }
+eax = { version = "0.3.0", optional = true }
+ed25519-dalek = { version = "1", default-features = false, features = ["rand", "u64_backend"], optional = true }
+generic-array = { version = "0.14.4", optional = true }
+idea = { version = "0.3.0", optional = true }
+md-5 = { version = "0.9.1", optional = true }
+num-bigint-dig = { version = "0.6", default-features = false, optional = true }
+rand = { version = "0.7.3", optional = true }
+ripemd160 = { version = "0.9.1", optional = true }
+rsa = { version = "0.3.0", optional = true }
+sha-1 = { version = "0.9.2", optional = true }
+sha2 = { version = "0.9.2", optional = true }
+twofish = { version = "0.5.0", optional = true }
+typenum = { version = "1.12.0", optional = true }
+x25519-dalek = { version = "1.1.0", optional = true }
+
[target.'cfg(windows)'.dependencies]
win-crypto-ng = { version = "0.4", features = ["rand", "block-cipher"], optional = true }
-num-bigint-dig = { version = "0.6", default-features = false, optional = true }
-ed25519-dalek = { version = "1", default-features = false, features = ["rand", "u64_backend"], optional = true }
winapi = { version = "0.3.8", default-features = false, features = ["bcrypt"], optional = true }
-eax = "0.3"
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
chrono = { version = "0.4.10", default-features = false, features = ["std"] }
@@ -68,7 +89,12 @@ criterion = { version = "0.3.4", features = ["html_reports"] }
default = ["compression", "crypto-nettle"]
# TODO(#333): Allow for/implement more backends
crypto-nettle = ["nettle"]
-crypto-cng = ["winapi", "win-crypto-ng", "ed25519-dalek", "num-bigint-dig"]
+crypto-rust = [
+ "aes", "block-modes", "block-padding", "blowfish", "cast5", "cipher", "des",
+ "digest", "eax", "ed25519-dalek", "generic-array", "idea", "md-5", "num-bigint-dig", "rand",
+ "ripemd160", "rsa", "sha-1", "sha2", "twofish", "typenum", "x25519-dalek"
+]
+crypto-cng = ["eax", "winapi", "win-crypto-ng", "ed25519-dalek", "num-bigint-dig"]
# Experimental and variable-time cryptographic backends opt-ins
allow-experimental-crypto = []
diff --git a/openpgp/NEWS b/openpgp/NEWS
index d17c9c08..739f53ec 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -3,6 +3,8 @@
#+STARTUP: content hidestars
* Changes in 1.4.0
+** New cryptographic backends
+ - We added a backend based on the RustCrypto crates.
** New functionality
- CipherSuite::is_supported
- MPI::value_padded
diff --git a/openpgp/README.md b/openpgp/README.md
index 3e0c81c2..c4bfa9e8 100644
--- a/openpgp/README.md
+++ b/openpgp/README.md
@@ -81,6 +81,13 @@ at compile time. Currently, these libraries are available:
include the `crypto-cng` feature to enable it. Currently, the CNG
backend requires at least Windows 10.
+ - The RustCrypto crates. To select this backend, use
+ `default-features = false`, and explicitly include the
+ `crypto-rust` feature to enable it. As of this writing, the
+ RustCrypto crates are not recommended for general use as they
+ cannot offer the same security guarantees as more mature
+ cryptographic libraries.
+
### Experimental and variable-time cryptographic backends
Some cryptographic backends are not yet considered mature enough for
diff --git a/openpgp/build.rs b/openpgp/build.rs
index 210483e5..aabf157d 100644
--- a/openpgp/build.rs
+++ b/openpgp/build.rs
@@ -62,6 +62,12 @@ fn crypto_backends_sanity_check() {
production_ready: true,
constant_time: true,
}),
+ (cfg!(feature = "crypto-rust"),
+ Backend {
+ name: "RustCrypto",
+ production_ready: false,
+ constant_time: false,
+ }),
].into_iter().filter_map(|(selected, backend)| {
if selected { Some(backend) } else { None }
}).collect::<Vec<_>>();
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index 3d55b0ab..95c172c1 100644
--- a/openpgp/src/crypto/aead.rs
+++ b/openpgp/src/crypto/aead.rs
@@ -815,6 +815,14 @@ mod tests {
SymmetricAlgorithm::Camellia256]
.iter()
.filter(|algo| algo.is_supported()) {
+
+ if cfg!(feature = "crypto-rust")
+ && sym_algo == &SymmetricAlgorithm::Twofish {
+ eprintln!("XXX: Skipping Twofish until Twofish \
+ implements Clone");
+ continue;
+ }
+
for aead in [
AEADAlgorithm::EAX,
AEADAlgorithm::OCB,
diff --git a/openpgp/src/crypto/backend.rs b/openpgp/src/crypto/backend.rs
index 11727d74..c0fd883f 100644
--- a/openpgp/src/crypto/backend.rs
+++ b/openpgp/src/crypto/backend.rs
@@ -8,6 +8,11 @@ mod nettle;
#[cfg(feature = "crypto-nettle")]
pub use self::nettle::*;
+#[cfg(feature = "crypto-rust")]
+mod rust;
+#[cfg(feature = "crypto-rust")]
+pub use self::rust::*;
+
#[cfg(feature = "crypto-cng")]
mod cng;
#[cfg(feature = "crypto-cng")]
diff --git a/openpgp/src/crypto/backend/rust.rs b/openpgp/src/crypto/backend/rust.rs
new file mode 100644
index 00000000..a661c14e
--- /dev/null
+++ b/openpgp/src/crypto/backend/rust.rs
@@ -0,0 +1,64 @@
+//! Implementation of Sequoia crypto API using pure Rust cryptographic
+//! libraries.
+
+use crate::types::*;
+
+pub mod aead;
+pub mod asymmetric;
+pub mod ecdh;
+pub mod hash;
+pub mod symmetric;
+
+/// Fills the given buffer with random data.
+///
+/// Fills the given buffer with random data produced by a
+/// cryptographically secure pseudorandom number generator (CSPRNG).
+/// The output may be used as session keys or to derive long-term
+/// cryptographic keys from.
+pub fn random<B: AsMut<[u8]>>(mut buf: B) {
+ use rand::rngs::OsRng;
+ use rand::RngCore;
+
+ OsRng.fill_bytes(buf.as_mut())
+}
+
+impl PublicKeyAlgorithm {
+ pub(crate) fn is_supported_by_backend(&self) -> bool {
+ use PublicKeyAlgorithm::*;
+ #[allow(deprecated)]
+ match &self {
+ RSAEncryptSign | RSAEncrypt | RSASign | ECDH | EdDSA
+ => true,
+ DSA | ECDSA
+ => false,
+ ElGamalEncrypt | ElGamalEncryptSign | Private(_) | Unknown(_)
+ => false,
+ }
+ }
+}
+
+impl Curve {
+ pub(crate) fn is_supported_by_backend(&self) -> bool {
+ use self::Curve::*;
+ match &self {
+ NistP256 | NistP384 | NistP521
+ => false,
+ Ed25519 | Cv25519
+ => true,
+ BrainpoolP256 | BrainpoolP512 | Unknown(_)
+ => false,
+ }
+ }
+}
+
+impl AEADAlgorithm {
+ pub(crate) fn is_supported_by_backend(&self) -> bool {
+ use self::AEADAlgorithm::*;
+ match &self {
+ EAX
+ => true,
+ OCB | Private(_) | Unknown(_)
+ => false,
+ }
+ }
+}
diff --git a/openpgp/src/crypto/backend/rust/aead.rs b/openpgp/src/crypto/backend/rust/aead.rs
new file mode 100644
index 00000000..ab2ca208
--- /dev/null
+++ b/openpgp/src/crypto/backend/rust/aead.rs
@@ -0,0 +1,134 @@
+//! Implementation of AEAD using pure Rust cryptographic libraries.
+
+use std::cmp;
+
+use cipher::{BlockCipher, NewBlockCipher};
+use cipher::block::Block;
+use cipher::consts::U16;
+use eax::online::{Eax, Encrypt, Decrypt};
+use generic_array::{ArrayLength, GenericArray};
+
+use crate::{Error, Result};
+use crate::crypto::aead::{Aead, CipherOp};
+use crate::seal;
+use crate::types::{AEADAlgorithm, SymmetricAlgorithm};
+
+trait GenericArrayExt {
+ const LEN: usize;
+}
+
+impl<T, N: ArrayLength<T>> GenericArrayExt for GenericArray<T, N> {
+ const LEN: usize = N::USIZE;
+}
+
+impl<Cipher> Aead for Eax<Cipher, Encrypt>
+where
+ Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone,
+ Cipher::ParBlocks: ArrayLength<Block<Cipher>>,
+{
+ fn update(&mut self, ad: &[u8]) {
+ self.update_assoc(ad)
+ }
+
+ fn digest_size(&self) -> usize {
+ eax::Tag::LEN
+ }
+
+ fn digest(&mut self, digest: &mut [u8]) {
+ let tag = self.tag_clone();
+ digest[..tag.len()].copy_from_slice(&tag[..]);
+ }
+
+ fn encrypt(&mut self, dst: &mut [u8], src: &[u8]) {
+ let len = cmp::min(dst.len(), src.len());
+ dst[..len].copy_from_slice(&src[..len]);
+ Self::encrypt(self, &mut dst[..len])
+ }
+
+ fn decrypt(&mut self, _dst: &mut [u8], _src: &[u8]) {
+ panic!("AEAD decryption called in the encryption context")
+ }
+}
+
+impl<Cipher> Aead for Eax<Cipher, Decrypt>
+where
+ Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone,
+ Cipher::ParBlocks: ArrayLength<Block<Cipher>>,
+{
+ fn update(&mut self, ad: &[u8]) {
+ self.update_assoc(ad)
+ }
+
+ fn digest_size(&self) -> usize {
+ eax::Tag::LEN
+ }
+
+ fn digest(&mut self, digest: &mut [u8]) {
+ let tag = self.tag_clone();
+ digest[..tag.len()].copy_from_slice(&tag[..]);
+ }
+
+ fn encrypt(&mut self, _dst: &mut [u8], _src: &[u8]) {
+ panic!("AEAD encryption called in the decryption context")
+ }
+
+ fn decrypt(&mut self, dst: &mut [u8], src: &[u8]) {
+ let len = core::cmp::min(dst.len(), src.len());
+ dst[..len].copy_from_slice(&src[..len]);
+ self.decrypt_unauthenticated_hazmat(&mut dst[..len])
+ }
+}
+
+impl<Cipher, Op> seal::Sealed for Eax<Cipher, Op>
+where
+ Cipher: BlockCipher<BlockSize = U16> + NewBlockCipher + Clone,
+ Cipher::ParBlocks: ArrayLength<Block<Cipher>>,
+ Op: eax::online::CipherOp,
+{}
+
+impl AEADAlgorithm {
+ pub(crate) fn context(
+ &self,
+ sym_algo: SymmetricAlgorithm,
+ key: &[u8],
+ nonce: &[u8],
+ op: CipherOp,
+ ) -> Result<Box<dyn Aead>> {
+ match self {
+ AEADAlgorithm::EAX => match sym_algo {
+ SymmetricAlgorithm::AES128 => match op {
+ CipherOp::Encrypt => Ok(Box::new(
+ Eax::<aes::Aes128, Encrypt>::with_key_and_nonce(key.into(), nonce.into()))),
+ CipherOp::Decrypt => Ok(Box::new(
+ Eax::<aes::Aes128, Decrypt>::with_key_and_nonce(key.into(), nonce.into()))),
+ }
+ SymmetricAlgorithm::AES192 => match op {
+ CipherOp::Encrypt => Ok(Box::new(
+ Eax::<aes::Aes192, Encrypt>::with_key_and_nonce(key.into(), nonce.into()))),
+ CipherOp::Decrypt => Ok(Box::new(
+ Eax::<aes::Aes192, Decrypt>::with_key_and_nonce(key.into(), nonce.into()))),
+ }
+ SymmetricAlgorithm::AES256 => match op {
+ CipherOp::Encrypt => Ok(Box::new(
+ Eax::<aes::Aes256, Encrypt>::with_key_and_nonce(key.into(), nonce.into()))),
+ CipherOp::Decrypt => Ok(Box::new(
+ Eax::<aes::Aes256, Decrypt>::with_key_and_nonce(key.into(), nonce.into()))),
+ }
+ | SymmetricAlgorithm::IDEA
+ | SymmetricAlgo