diff --git a/.github/workflows/evercrypt-rs.yml b/.github/workflows/evercrypt-rs.yml index 3da1109..aae745a 100644 --- a/.github/workflows/evercrypt-rs.yml +++ b/.github/workflows/evercrypt-rs.yml @@ -55,3 +55,32 @@ jobs: run: | cd evercrypt-rs cargo bench --verbose --features rust-crypto-aes + fuzz: + strategy: + fail-fast: false + matrix: + os: + - macos-latest + - ubuntu-latest + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + default: true + - uses: actions-rs/install@v0.1 + with: + crate: cargo-fuzz + version: latest + - name: Fuzz AEAD + run: | + cd evercrypt-rs + cargo fuzz run aead -- -runs=1000000 + - name: Fuzz ECDH + run: | + cd evercrypt-rs + cargo fuzz run ecdh -- -runs=1000000 diff --git a/Cargo.toml b/Cargo.toml index 1e73c13..8310146 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ "evercrypt-rs", - "evercrypt-sys" + "evercrypt-sys", ] [patch.crates-io] diff --git a/evercrypt-rs/Cargo.toml b/evercrypt-rs/Cargo.toml index 23221c7..7e82dc0 100644 --- a/evercrypt-rs/Cargo.toml +++ b/evercrypt-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evercrypt" -version = "0.0.4" +version = "0.0.5" authors = ["Franziskus Kiefer "] edition = "2018" license = "MPL-2.0" @@ -22,7 +22,7 @@ random = ["rand", "rand_core"] serialization = ["serde", "serde_json"] [dependencies] -evercrypt-sys = { version = "0.0.4" } +evercrypt-sys = { version = "0.0.5" } aes-gcm = { version = "0.8", optional = true } rand = { version = "0.7", optional = true } rand_core = { version = "0.5", optional = true } diff --git a/evercrypt-rs/fuzz/.gitignore b/evercrypt-rs/fuzz/.gitignore new file mode 100644 index 0000000..572e03b --- /dev/null +++ b/evercrypt-rs/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts diff --git a/evercrypt-rs/fuzz/Cargo.toml b/evercrypt-rs/fuzz/Cargo.toml new file mode 100644 index 0000000..daa6504 --- /dev/null +++ b/evercrypt-rs/fuzz/Cargo.toml @@ -0,0 +1,35 @@ + +[package] +name = "evercrypt-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2018" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.3" + +[dependencies.evercrypt] +path = ".." + +[patch.crates-io] +evercrypt-sys = { path = "../../evercrypt-sys" } + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "ecdh" +path = "fuzz_targets/ecdh.rs" +test = false +doc = false + +[[bin]] +name = "aead" +path = "fuzz_targets/aead.rs" +test = false +doc = false diff --git a/evercrypt-rs/fuzz/fuzz_targets/aead.rs b/evercrypt-rs/fuzz/fuzz_targets/aead.rs new file mode 100644 index 0000000..0ea86e5 --- /dev/null +++ b/evercrypt-rs/fuzz/fuzz_targets/aead.rs @@ -0,0 +1,30 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +use evercrypt::prelude::*; + +fuzz_target!(|data: &[u8]| { + let modes = [ + AeadMode::Aes128Gcm, + AeadMode::Aes256Gcm, + AeadMode::Chacha20Poly1305, + ]; + for &mode in modes.iter() { + let nonce = aead_nonce_gen(mode); + let enc_result = aead_encrypt(mode, data, data, &nonce, &[]); + let (c, t) = if let Ok((c, t)) = enc_result { + (c, t) + } else { + if data.len() != 16 { + return; + } + let mut tag = [0u8; 16]; + tag.clone_from_slice(data); + (data.to_vec(), tag) + }; + let dec_result = aead_decrypt(mode, data, &c, &t, &nonce, &[]); + if let Ok(ptxt) = dec_result { + assert_eq!(ptxt, data); + } + } +}); diff --git a/evercrypt-rs/fuzz/fuzz_targets/ecdh.rs b/evercrypt-rs/fuzz/fuzz_targets/ecdh.rs new file mode 100644 index 0000000..96d291c --- /dev/null +++ b/evercrypt-rs/fuzz/fuzz_targets/ecdh.rs @@ -0,0 +1,9 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +use evercrypt::prelude::*; + +fuzz_target!(|data: &[u8]| { + let _ = ecdh_derive(EcdhMode::X25519, data, data); + let _ = ecdh_derive_base(EcdhMode::X25519, data); +}); diff --git a/evercrypt-rs/src/aead.rs b/evercrypt-rs/src/aead.rs index 735dedf..1fa51bb 100644 --- a/evercrypt-rs/src/aead.rs +++ b/evercrypt-rs/src/aead.rs @@ -124,6 +124,7 @@ pub enum Error { UnsupportedConfig = 4, Encrypting = 5, Decrypting = 6, + InvalidKeySize = 7, } /// The Aead struct allows to re-use a key without having to initialize it @@ -191,6 +192,11 @@ impl Aead { /// If the algorithm is not supported or the state generation fails, this /// function returns an `Error`. pub fn new(alg: Mode, k: &[u8]) -> Result { + // Check key lengths. Evercrypt is not doing this. + if k.len() != key_size(&alg) { + return Err(Error::InvalidKeySize); + } + unsafe { // Make sure this happened. EverCrypt_AutoConfig2_init(); @@ -388,6 +394,18 @@ impl Aead { } } +impl Drop for Aead { + fn drop(&mut self) { + if let Some(c_state) = self.c_state { + unsafe { EverCrypt_AEAD_free(c_state) } + } + // This will probably be optimised out. But it's only best effort for + // now. + let zero_key: Vec = (0u8..self.key.len() as u8).collect(); + let _ = std::mem::replace(&mut self.key, zero_key); + } +} + // Single-shot APIs /// Single-shot API for AEAD encryption. diff --git a/evercrypt-rs/src/ecdh.rs b/evercrypt-rs/src/ecdh.rs index d8a508e..a231733 100644 --- a/evercrypt-rs/src/ecdh.rs +++ b/evercrypt-rs/src/ecdh.rs @@ -48,6 +48,7 @@ use crate::x25519; #[derive(Debug, PartialEq)] pub enum Error { InvalidPoint, + InvalidScalar, UnkownAlgorithm, } @@ -64,6 +65,12 @@ pub enum Mode { pub fn derive(mode: Mode, p: &[u8], s: &[u8]) -> Result, Error> { match mode { Mode::X25519 => { + if p.len() != 32 { + return Err(Error::InvalidPoint); + } + if s.len() != 32 { + return Err(Error::InvalidScalar); + } let mut point = [0u8; 32]; point.clone_from_slice(p); let mut scalar = [0u8; 32]; @@ -85,6 +92,9 @@ pub fn derive(mode: Mode, p: &[u8], s: &[u8]) -> Result, Error> { pub fn derive_base(mode: Mode, s: &[u8]) -> Result, Error> { match mode { Mode::X25519 => { + if s.len() != 32 { + return Err(Error::InvalidScalar); + } let mut scalar = [0u8; 32]; scalar.clone_from_slice(s); diff --git a/evercrypt-rs/src/p256.rs b/evercrypt-rs/src/p256.rs index d0a3d4b..88fd2a5 100644 --- a/evercrypt-rs/src/p256.rs +++ b/evercrypt-rs/src/p256.rs @@ -19,10 +19,14 @@ pub fn validate_pk(pk: &[u8]) -> Result<[u8; 64], Error> { // Parse the public key. let mut public = [0u8; 64]; - let uncompressed_point = unsafe { - Hacl_P256_decompression_not_compressed_form(pk.as_ptr() as _, public.as_mut_ptr()) + let uncompressed_point = if pk.len() < 65 { + false + } else { + unsafe { + Hacl_P256_decompression_not_compressed_form(pk.as_ptr() as _, public.as_mut_ptr()) + } }; - let compressed_point = if !uncompressed_point { + let compressed_point = if !uncompressed_point && pk.len() >= 33 { unsafe { Hacl_P256_decompression_compressed_form(pk.as_ptr() as _, public.as_mut_ptr()) } } else { false diff --git a/evercrypt-sys/Cargo.toml b/evercrypt-sys/Cargo.toml index 979d0c1..ca90759 100644 --- a/evercrypt-sys/Cargo.toml +++ b/evercrypt-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "evercrypt-sys" -version = "0.0.4" +version = "0.0.5" authors = ["Franziskus Kiefer "] edition = "2018" build = "build.rs" diff --git a/evercrypt-sys/build.rs b/evercrypt-sys/build.rs index c8f1676..ee298f0 100644 --- a/evercrypt-sys/build.rs +++ b/evercrypt-sys/build.rs @@ -300,14 +300,15 @@ fn main() { let hacl_src_path_str = hacl_src_path.to_str().unwrap(); // Build hacl/evercrypt - if rebuild(home_dir, &out_path) { + // Always rebuild on windows for now. TODO: fix rebuild check on Windows. + if build_config.windows || rebuild(home_dir, &out_path) { // Only rebuild if the hacl revision changed. copy_hacl_to_out(&out_path, &hacl_src_path); build_hacl(&hacl_src_path, &build_config); } // Generate new bindings if not on Windows. - if !cfg.windows { + if !build_config.windows { create_bindings(&hacl_dir, hacl_src_path_str, home_dir); } diff --git a/evercrypt-sys/hacl-build.bat b/evercrypt-sys/hacl-build.bat index 436cae7..c681df3 100644 --- a/evercrypt-sys/hacl-build.bat +++ b/evercrypt-sys/hacl-build.bat @@ -1,6 +1,6 @@ echo off call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -host_arch=amd64 -arch=amd64 -call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -test +@REM call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\VsDevCmd.bat" -test cd %~dp0 cl *.c /I ../kremlin/include /I . /I ../kremlin/kremlib/dist/minimal /c || goto :error for /F %%i in ('dir /b *-x86_64-msvc.asm') do ( diff --git a/evercrypt-sys/hacl-star b/evercrypt-sys/hacl-star index 1e5134d..d88c750 160000 --- a/evercrypt-sys/hacl-star +++ b/evercrypt-sys/hacl-star @@ -1 +1 @@ -Subproject commit 1e5134dd915692fff37ba2d34cf7231e11aa2ad7 +Subproject commit d88c75005f7871f89f7d6713fbaf6ee167e61773