diff --git a/Cargo.toml b/Cargo.toml index 490af8a..78d00e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ name = "dryoc" readme = "README.md" repository = "https://github.com/brndnmtthws/dryoc" rust-version = "1.56" -version = "0.4.4" +version = "0.5.0" [dependencies] base64 = { version = "0.21", optional = true } @@ -24,7 +24,7 @@ salsa20 = { version = "0.10", features = ["zeroize"] } serde = { version = "1.0", optional = true, features = ["derive"] } sha2 = "0.10" subtle = "2.4" -zeroize = { version = "1.5", features = ["zeroize_derive"] } +zeroize = { version = "1.6", features = ["zeroize_derive"] } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = [ diff --git a/src/blake2b/blake2b_simd.rs b/src/blake2b/blake2b_simd.rs index b7ee6ef..c38312b 100644 --- a/src/blake2b/blake2b_simd.rs +++ b/src/blake2b/blake2b_simd.rs @@ -1,7 +1,7 @@ use std::simd::Which::{First, Second}; use std::simd::{simd_swizzle, Simd}; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::error::Error; use crate::utils::load_u64_le; @@ -47,8 +47,7 @@ impl Default for Params { } } -#[derive(Zeroize, Debug, Default)] -#[zeroize(drop)] +#[derive(Zeroize, ZeroizeOnDrop, Debug, Default)] pub struct State { t: [u64; 2], f: [u64; 2], diff --git a/src/blake2b/blake2b_soft.rs b/src/blake2b/blake2b_soft.rs index de9929d..2377640 100644 --- a/src/blake2b/blake2b_soft.rs +++ b/src/blake2b/blake2b_soft.rs @@ -1,4 +1,4 @@ -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::error::Error; use crate::utils::{load_u64_le, rotr64}; @@ -44,8 +44,7 @@ impl Default for Params { } } -#[derive(Zeroize, Debug, Default)] -#[zeroize(drop)] +#[derive(Zeroize, ZeroizeOnDrop, Debug, Default)] pub struct State { h: [u64; 8], t: [u64; 2], diff --git a/src/classic/crypto_auth.rs b/src/classic/crypto_auth.rs index f991617..d57e6d1 100644 --- a/src/classic/crypto_auth.rs +++ b/src/classic/crypto_auth.rs @@ -6,7 +6,6 @@ //! # Classic API single-part example //! //! ``` -//! use base64::encode; //! use dryoc::classic::crypto_auth::{crypto_auth, crypto_auth_keygen, crypto_auth_verify, Mac}; //! //! let key = crypto_auth_keygen(); @@ -24,7 +23,6 @@ //! # Classic API multi-part example //! //! ``` -//! use base64::encode; //! use dryoc::classic::crypto_auth::{ //! crypto_auth_final, crypto_auth_init, crypto_auth_keygen, crypto_auth_update, //! crypto_auth_verify, Mac, diff --git a/src/classic/crypto_core.rs b/src/classic/crypto_core.rs index 13e7050..af574c5 100644 --- a/src/classic/crypto_core.rs +++ b/src/classic/crypto_core.rs @@ -219,7 +219,8 @@ mod tests { #[test] fn test_crypto_scalarmult_base() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; for _ in 0..20 { use sodiumoxide::crypto::scalarmult::curve25519::{scalarmult_base, Scalar}; @@ -232,13 +233,17 @@ mod tests { let ge = scalarmult_base(&Scalar::from_slice(&sk).unwrap()); - assert_eq!(encode(ge.as_ref()), encode(public_key)); + assert_eq!( + general_purpose::STANDARD.encode(ge.as_ref()), + general_purpose::STANDARD.encode(public_key) + ); } } #[test] fn test_crypto_scalarmult() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; for _ in 0..20 { use sodiumoxide::crypto::scalarmult::curve25519::{scalarmult, GroupElement, Scalar}; @@ -254,13 +259,17 @@ mod tests { ) .expect("scalarmult failed"); - assert_eq!(encode(ge.as_ref()), encode(shared_secret)); + assert_eq!( + general_purpose::STANDARD.encode(ge.as_ref()), + general_purpose::STANDARD.encode(shared_secret) + ); } } #[test] fn test_crypto_core_hchacha20() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libsodium_sys::crypto_core_hchacha20 as so_crypto_core_hchacha20; use crate::rng::copy_randombytes; @@ -284,13 +293,17 @@ mod tests { ); assert_eq!(ret, 0); } - assert_eq!(encode(&out), encode(&so_out)); + assert_eq!( + general_purpose::STANDARD.encode(&out), + general_purpose::STANDARD.encode(&so_out) + ); } } #[test] fn test_crypto_core_hsalsa20() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libsodium_sys::crypto_core_hsalsa20 as so_crypto_core_hsalsa20; use crate::rng::copy_randombytes; @@ -314,7 +327,10 @@ mod tests { ); assert_eq!(ret, 0); } - assert_eq!(encode(&out), encode(&so_out)); + assert_eq!( + general_purpose::STANDARD.encode(&out), + general_purpose::STANDARD.encode(&so_out) + ); } } } diff --git a/src/classic/crypto_generichash.rs b/src/classic/crypto_generichash.rs index b81ce1a..6ff338a 100644 --- a/src/classic/crypto_generichash.rs +++ b/src/classic/crypto_generichash.rs @@ -8,7 +8,8 @@ //! # Classic API example, one-time interface //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::classic::crypto_generichash::*; //! use dryoc::constants::CRYPTO_GENERICHASH_BYTES; //! @@ -18,7 +19,7 @@ //! crypto_generichash(&mut output, b"a string of bytes", None).ok(); //! //! assert_eq!( -//! encode(output), +//! general_purpose::STANDARD.encode(output), //! "GdztjR9nU/rLh8VJt8e74+/seKTUnHgBexhGSpxLau0=" //! ); //! ``` @@ -26,7 +27,8 @@ //! # Classic API example, incremental interface //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::classic::crypto_generichash::*; //! use dryoc::constants::CRYPTO_GENERICHASH_BYTES; //! @@ -40,7 +42,7 @@ //! crypto_generichash_final(state, &mut output).expect("final failed"); //! //! assert_eq!( -//! encode(output), +//! general_purpose::STANDARD.encode(output), //! "GdztjR9nU/rLh8VJt8e74+/seKTUnHgBexhGSpxLau0=" //! ); //! ``` diff --git a/src/classic/crypto_kdf.rs b/src/classic/crypto_kdf.rs index b0cdb21..baec96e 100644 --- a/src/classic/crypto_kdf.rs +++ b/src/classic/crypto_kdf.rs @@ -7,7 +7,8 @@ //! # Classic API example //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::classic::crypto_kdf::*; //! //! // Generate a random main key @@ -19,7 +20,7 @@ //! for i in 0..20 { //! let mut key = Key::default(); //! crypto_kdf_derive_from_key(&mut key, i, context, &main_key).expect("kdf failed"); -//! println!("Subkey {}: {}", i, encode(&key)); +//! println!("Subkey {}: {}", i, general_purpose::STANDARD.encode(&key)); //! } //! ``` diff --git a/src/classic/crypto_onetimeauth.rs b/src/classic/crypto_onetimeauth.rs index 2972185..0983b10 100644 --- a/src/classic/crypto_onetimeauth.rs +++ b/src/classic/crypto_onetimeauth.rs @@ -6,7 +6,8 @@ //! # Classic API single-part example //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::classic::crypto_onetimeauth::{ //! crypto_onetimeauth, crypto_onetimeauth_keygen, crypto_onetimeauth_verify, Mac, //! }; @@ -26,7 +27,8 @@ //! # Classic API multi-part example //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::classic::crypto_onetimeauth::{ //! crypto_onetimeauth_final, crypto_onetimeauth_init, crypto_onetimeauth_keygen, //! crypto_onetimeauth_update, crypto_onetimeauth_verify, Mac, diff --git a/src/classic/crypto_pwhash.rs b/src/classic/crypto_pwhash.rs index 921f1bf..4e4ac0e 100644 --- a/src/classic/crypto_pwhash.rs +++ b/src/classic/crypto_pwhash.rs @@ -151,21 +151,16 @@ pub fn crypto_pwhash( #[cfg(any(feature = "base64", all(doc, not(doctest))))] #[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "base64")))] pub(crate) fn pwhash_to_string(t_cost: u32, m_cost: u32, salt: &[u8], hash: &[u8]) -> String { - #[cfg(feature = "base64")] - use base64::Engine; - - let base64_engine = base64::engine::general_purpose::GeneralPurpose::new( - &base64::alphabet::STANDARD, - base64::engine::general_purpose::NO_PAD, - ); + use base64::engine::general_purpose; + use base64::Engine as _; format!( "$argon2id$v={}$m={},t={},p=1${}${}", argon2::ARGON2_VERSION_NUMBER, m_cost, t_cost, - base64_engine.encode(salt), - base64_engine.encode(hash), + general_purpose::STANDARD_NO_PAD.encode(salt), + general_purpose::STANDARD_NO_PAD.encode(hash), ) } diff --git a/src/classic/crypto_secretbox.rs b/src/classic/crypto_secretbox.rs index 9ca699f..158d013 100644 --- a/src/classic/crypto_secretbox.rs +++ b/src/classic/crypto_secretbox.rs @@ -179,7 +179,8 @@ mod tests { #[test] fn test_crypto_secretbox_easy() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::secretbox; use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce}; @@ -197,7 +198,10 @@ mod tests { &SONonce::from_slice(&nonce).unwrap(), &SOKey::from_slice(&key).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let mut decrypted = vec![0u8; message.len()]; crypto_secretbox_open_easy(&mut decrypted, &ciphertext, &nonce, &key) @@ -217,7 +221,8 @@ mod tests { #[test] fn test_crypto_secretbox_easy_inplace() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::secretbox; use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce}; @@ -236,7 +241,10 @@ mod tests { &SONonce::from_slice(&nonce).unwrap(), &SOKey::from_slice(&key).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let mut decrypted = ciphertext.clone(); crypto_secretbox_open_easy_inplace(&mut decrypted, &nonce, &key) diff --git a/src/classic/crypto_secretstream_xchacha20poly1305.rs b/src/classic/crypto_secretstream_xchacha20poly1305.rs index b9885c4..02d57cd 100644 --- a/src/classic/crypto_secretstream_xchacha20poly1305.rs +++ b/src/classic/crypto_secretstream_xchacha20poly1305.rs @@ -87,7 +87,7 @@ //! ``` use subtle::ConstantTimeEq; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::classic::crypto_core::{crypto_core_hchacha20, HChaCha20Key}; use crate::constants::{ @@ -113,8 +113,7 @@ pub type Nonce = [u8; CRYPTO_STREAM_CHACHA20_IETF_NONCEBYTES]; pub type Header = [u8; CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES]; /// Stream state data -#[derive(PartialEq, Eq, Clone, Zeroize, Default)] -#[zeroize(drop)] +#[derive(PartialEq, Eq, Clone, Default, Zeroize, ZeroizeOnDrop)] pub struct State { k: Key, nonce: Nonce, @@ -480,7 +479,8 @@ mod tests { #[test] fn test_secretstream_basic_push() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libsodium_sys::{ crypto_secretstream_xchacha20poly1305_init_pull as so_crypto_secretstream_xchacha20poly1305_init_pull, crypto_secretstream_xchacha20poly1305_pull as so_crypto_secretstream_xchacha20poly1305_pull, @@ -535,9 +535,18 @@ mod tests { ); assert_eq!(ret, 0); so_output.resize(clen_p as usize, 0); - assert_eq!(encode(&so_output), encode(&output)); - assert_eq!(encode(&so_state.k), encode(&push_state.k)); - assert_eq!(encode(&so_state.nonce), encode(&push_state.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(&so_output), + general_purpose::STANDARD.encode(&output) + ); + assert_eq!( + general_purpose::STANDARD.encode(&so_state.k), + general_purpose::STANDARD.encode(&push_state.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(&so_state.nonce), + general_purpose::STANDARD.encode(&push_state.nonce) + ); let mut so_state = crypto_secretstream_xchacha20poly1305_state { k: [0u8; CRYPTO_STREAM_CHACHA20_IETF_KEYBYTES], @@ -552,8 +561,14 @@ mod tests { key.as_ptr(), ); assert_eq!(ret, 0); - assert_eq!(encode(&so_state.k), encode(&push_state_init.k)); - assert_eq!(encode(&so_state.nonce), encode(&push_state_init.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(&so_state.k), + general_purpose::STANDARD.encode(&push_state_init.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(&so_state.nonce), + general_purpose::STANDARD.encode(&push_state_init.nonce) + ); assert!(so_output.len() >= CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES); let ret = so_crypto_secretstream_xchacha20poly1305_pull( &mut so_state, @@ -568,13 +583,22 @@ mod tests { assert_eq!(ret, 0); so_output.resize(mlen_p as usize, 0); } - assert_eq!(encode(&message), encode(&so_output)); + assert_eq!( + general_purpose::STANDARD.encode(&message), + general_purpose::STANDARD.encode(&so_output) + ); let mut pull_state = State::default(); crypto_secretstream_xchacha20poly1305_init_pull(&mut pull_state, &push_header, &key); - assert_eq!(encode(pull_state.k), encode(push_state_init.k)); - assert_eq!(encode(pull_state.nonce), encode(push_state_init.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(pull_state.k), + general_purpose::STANDARD.encode(push_state_init.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(pull_state.nonce), + general_purpose::STANDARD.encode(push_state_init.nonce) + ); let mut pull_result_message = vec![0u8; output.len() - CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES]; @@ -589,12 +613,16 @@ mod tests { .expect("pull failed"); assert_eq!(Tag::MESSAGE, Tag::from_bits(tag).expect("tag")); - assert_eq!(encode(&pull_result_message), encode(&message)); + assert_eq!( + general_purpose::STANDARD.encode(&pull_result_message), + general_purpose::STANDARD.encode(&message) + ); } #[test] fn test_rekey() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libsodium_sys::{ crypto_secretstream_xchacha20poly1305_rekey as so_crypto_secretstream_xchacha20poly1305_rekey, crypto_secretstream_xchacha20poly1305_state, @@ -622,13 +650,20 @@ mod tests { unsafe { so_crypto_secretstream_xchacha20poly1305_rekey(&mut so_state); } - assert_eq!(encode(so_state.k), encode(push_state.k)); - assert_eq!(encode(so_state.nonce), encode(push_state.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(so_state.k), + general_purpose::STANDARD.encode(push_state.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(so_state.nonce), + general_purpose::STANDARD.encode(push_state.nonce) + ); } #[test] fn test_secretstream_lots_of_messages_push() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libc::{c_uchar, c_ulonglong}; use libsodium_sys::{ crypto_secretstream_xchacha20poly1305_init_pull as so_crypto_secretstream_xchacha20poly1305_init_pull, @@ -650,8 +685,14 @@ mod tests { let mut pull_state = State::default(); crypto_secretstream_xchacha20poly1305_init_pull(&mut pull_state, &push_header, &key); - assert_eq!(encode(pull_state.k), encode(push_state_init.k)); - assert_eq!(encode(pull_state.nonce), encode(push_state_init.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(pull_state.k), + general_purpose::STANDARD.encode(push_state_init.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(pull_state.nonce), + general_purpose::STANDARD.encode(push_state_init.nonce) + ); let mut so_state = crypto_secretstream_xchacha20poly1305_state { k: [0u8; CRYPTO_STREAM_CHACHA20_IETF_KEYBYTES], @@ -676,8 +717,14 @@ mod tests { ); assert_eq!(ret, 0); } - assert_eq!(encode(so_state.k), encode(push_state_init.k)); - assert_eq!(encode(so_state.nonce), encode(push_state_init.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(so_state.k), + general_purpose::STANDARD.encode(push_state_init.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(so_state.nonce), + general_purpose::STANDARD.encode(push_state_init.nonce) + ); for i in 0..100 { let message = format!("hello {}", i); @@ -711,7 +758,10 @@ mod tests { assert_eq!(ret, 0); so_output.resize(mlen_p as usize, 0); } - assert_eq!(encode(&message), encode(&so_output)); + assert_eq!( + general_purpose::STANDARD.encode(&message), + general_purpose::STANDARD.encode(&so_output) + ); let mut pull_result_message = vec![0u8; output.len() - CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES]; @@ -726,13 +776,17 @@ mod tests { .expect("pull failed"); assert_eq!(tag, Tag::from_bits(pull_result_tag).expect("tag")); - assert_eq!(encode(&pull_result_message), encode(&message)); + assert_eq!( + general_purpose::STANDARD.encode(&pull_result_message), + general_purpose::STANDARD.encode(&message) + ); } } #[test] fn test_secretstream_basic_pull() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libc::c_ulonglong; use libsodium_sys::{ crypto_secretstream_xchacha20poly1305_init_push as so_crypto_secretstream_xchacha20poly1305_init_push, @@ -794,13 +848,17 @@ mod tests { .expect("decrypt failed"); output.resize(mlen, 0); - assert_eq!(encode(&output), encode(message)); + assert_eq!( + general_purpose::STANDARD.encode(&output), + general_purpose::STANDARD.encode(message) + ); assert_eq!(tag, 0); } #[test] fn test_secretstream_lots_of_messages_pull() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use libc::c_ulonglong; use libsodium_sys::{ crypto_secretstream_xchacha20poly1305_init_push as so_crypto_secretstream_xchacha20poly1305_init_push, @@ -867,10 +925,19 @@ mod tests { ) .expect("decrypt failed"); - assert_eq!(encode(so_state.k), encode(pull_state.k)); - assert_eq!(encode(so_state.nonce), encode(pull_state.nonce)); + assert_eq!( + general_purpose::STANDARD.encode(so_state.k), + general_purpose::STANDARD.encode(pull_state.k) + ); + assert_eq!( + general_purpose::STANDARD.encode(so_state.nonce), + general_purpose::STANDARD.encode(pull_state.nonce) + ); - assert_eq!(encode(&output), encode(message)); + assert_eq!( + general_purpose::STANDARD.encode(&output), + general_purpose::STANDARD.encode(message) + ); assert_eq!(outtag, tag.bits()); } } diff --git a/src/classic/crypto_sign.rs b/src/classic/crypto_sign.rs index ef3638b..fe11f38 100644 --- a/src/classic/crypto_sign.rs +++ b/src/classic/crypto_sign.rs @@ -203,7 +203,8 @@ mod tests { #[test] fn test_crypto_sign() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::sign; for _ in 0..10 { @@ -217,7 +218,10 @@ mod tests { &sign::SecretKey::from_slice(&secret_key).expect("secret key failed"), ); - assert_eq!(encode(&signed_message), encode(&so_signed_message)); + assert_eq!( + general_purpose::STANDARD.encode(&signed_message), + general_purpose::STANDARD.encode(&so_signed_message) + ); let so_m = sign::verify( &signed_message, @@ -231,7 +235,8 @@ mod tests { #[test] fn test_crypto_sign_open() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::sign; for _ in 0..10 { @@ -245,7 +250,10 @@ mod tests { &sign::SecretKey::from_slice(&secret_key).expect("secret key failed"), ); - assert_eq!(encode(&signed_message), encode(&so_signed_message)); + assert_eq!( + general_purpose::STANDARD.encode(&signed_message), + general_purpose::STANDARD.encode(&so_signed_message) + ); let so_m = sign::verify( &signed_message, diff --git a/src/classic/crypto_sign_ed25519.rs b/src/classic/crypto_sign_ed25519.rs index 5d4f7da..a3ebc6b 100644 --- a/src/classic/crypto_sign_ed25519.rs +++ b/src/classic/crypto_sign_ed25519.rs @@ -329,7 +329,8 @@ pub(crate) fn crypto_sign_ed25519ph_final_verify( #[cfg(test)] mod tests { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use super::*; use crate::rng::copy_randombytes; @@ -347,8 +348,14 @@ mod tests { let (so_pk, so_sk) = sign::keypair_from_seed(&sign::Seed::from_slice(&seed).expect("seed failed")); - assert_eq!(encode(pk), encode(so_pk.0)); - assert_eq!(encode(sk), encode(so_sk.0)); + assert_eq!( + general_purpose::STANDARD.encode(pk), + general_purpose::STANDARD.encode(so_pk.0) + ); + assert_eq!( + general_purpose::STANDARD.encode(sk), + general_purpose::STANDARD.encode(so_sk.0) + ); } } @@ -380,8 +387,14 @@ mod tests { ); } - assert_eq!(encode(xpk), encode(so_xpk)); - assert_eq!(encode(xsk), encode(so_xsk)); + assert_eq!( + general_purpose::STANDARD.encode(xpk), + general_purpose::STANDARD.encode(so_xpk) + ); + assert_eq!( + general_purpose::STANDARD.encode(xsk), + general_purpose::STANDARD.encode(so_xsk) + ); } } } diff --git a/src/dryocbox.rs b/src/dryocbox.rs index 0b52108..60532ac 100644 --- a/src/dryocbox.rs +++ b/src/dryocbox.rs @@ -200,9 +200,9 @@ pub mod protected { /// /// Refer to [crate::dryocbox] for sample usage. pub struct DryocBox< - EphemeralPublicKey: ByteArray, - Mac: ByteArray, - Data: Bytes, + EphemeralPublicKey: ByteArray + Zeroize, + Mac: ByteArray + Zeroize, + Data: Bytes + Zeroize, > { ephemeral_pk: Option, tag: Mac, @@ -213,9 +213,9 @@ pub struct DryocBox< pub type VecBox = DryocBox>; impl< - EphemeralPublicKey: ByteArray, - Mac: NewByteArray, - Data: NewBytes + ResizableBytes, + EphemeralPublicKey: ByteArray + Zeroize, + Mac: NewByteArray + Zeroize, + Data: NewBytes + ResizableBytes + Zeroize, > DryocBox { /// Encrypts a message using `sender_secret_key` for `recipient_public_key`, @@ -255,9 +255,9 @@ impl< } impl< - EphemeralPublicKey: NewByteArray, - Mac: NewByteArray, - Data: NewBytes + ResizableBytes, + EphemeralPublicKey: NewByteArray + Zeroize, + Mac: NewByteArray + Zeroize, + Data: NewBytes + ResizableBytes + Zeroize, > DryocBox { /// Encrypts a message for `recipient_public_key`, using an ephemeral secret @@ -304,9 +304,9 @@ impl< impl< 'a, - EphemeralPublicKey: ByteArray + std::convert::TryFrom<&'a [u8]>, - Mac: ByteArray + std::convert::TryFrom<&'a [u8]>, - Data: Bytes + From<&'a [u8]>, + EphemeralPublicKey: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, + Mac: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, + Data: Bytes + From<&'a [u8]> + Zeroize, > DryocBox { /// Initializes a [`DryocBox`] from a slice. Expects the first @@ -356,9 +356,9 @@ impl< } impl< - EphemeralPublicKey: ByteArray, - Mac: ByteArray, - Data: Bytes, + EphemeralPublicKey: ByteArray + Zeroize, + Mac: ByteArray + Zeroize, + Data: Bytes + Zeroize, > DryocBox { /// Returns a new box with `tag`, `data` and (optional) `ephemeral_pk`, @@ -415,9 +415,9 @@ impl< /// Decrypts this sealed box using `recipient_secret_key`, and /// returning the decrypted message upon success. pub fn unseal< - RecipientPublicKey: ByteArray, - RecipientSecretKey: ByteArray, - Output: ResizableBytes + NewBytes, + RecipientPublicKey: ByteArray + Zeroize, + RecipientSecretKey: ByteArray + Zeroize, + Output: ResizableBytes + NewBytes + Zeroize, >( &self, recipient_keypair: &crate::keypair::KeyPair, @@ -515,8 +515,8 @@ impl DryocBox> { /// Decrypts this sealed box using `recipient_secret_key`, returning the /// decrypted message upon success. pub fn unseal_to_vec< - RecipientPublicKey: ByteArray, - RecipientSecretKey: ByteArray, + RecipientPublicKey: ByteArray + Zeroize, + RecipientSecretKey: ByteArray + Zeroize, >( &self, recipient_keypair: &crate::keypair::KeyPair, @@ -527,9 +527,9 @@ impl DryocBox> { impl< 'a, - EphemeralPublicKey: ByteArray, - Mac: ByteArray, - Data: Bytes + ResizableBytes + From<&'a [u8]>, + EphemeralPublicKey: ByteArray + Zeroize, + Mac: ByteArray + Zeroize, + Data: Bytes + ResizableBytes + From<&'a [u8]> + Zeroize, > DryocBox { /// Returns a new box with `data` and `tag`, with data copied from `input` @@ -559,9 +559,9 @@ impl< } impl< - EphemeralPublicKey: ByteArray, - Mac: ByteArray, - Data: Bytes, + EphemeralPublicKey: ByteArray + Zeroize, + Mac: ByteArray + Zeroize, + Data: Bytes + Zeroize, > PartialEq> for DryocBox { fn eq(&self, other: &Self) -> bool { @@ -599,7 +599,8 @@ mod tests { #[test] fn test_dryocbox_vecbox() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::box_; use sodiumoxide::crypto::box_::{Nonce as SONonce, PublicKey, SecretKey}; @@ -628,7 +629,10 @@ mod tests { &SecretKey::from_slice(&keypair_sender_copy.secret_key).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let keypair_sender = keypair_sender_copy.clone(); let keypair_recipient = keypair_recipient_copy.clone(); @@ -656,7 +660,8 @@ mod tests { #[test] fn test_decrypt_failure() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::box_; use sodiumoxide::crypto::box_::{ Nonce as SONonce, PublicKey as SOPublicKey, SecretKey as SOSecretKey, @@ -687,7 +692,10 @@ mod tests { &SOSecretKey::from_slice(&keypair_sender_copy.secret_key).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let invalid_key = KeyPair::gen(); let invalid_key_copy_1 = invalid_key.clone(); diff --git a/src/dryocsecretbox.rs b/src/dryocsecretbox.rs index ad6aaaa..4163e27 100644 --- a/src/dryocsecretbox.rs +++ b/src/dryocsecretbox.rs @@ -134,7 +134,10 @@ pub mod protected { /// Use with either [`VecBox`] or [`protected::LockedBox`] type aliases. /// /// Refer to [crate::dryocsecretbox] for sample usage. -pub struct DryocSecretBox, Data: Bytes> { +pub struct DryocSecretBox< + Mac: ByteArray + Zeroize, + Data: Bytes + Zeroize, +> { tag: Mac, data: Data, } @@ -142,8 +145,10 @@ pub struct DryocSecretBox, Data: Bytes /// [Vec]-based authenticated secret box. pub type VecBox = DryocSecretBox>; -impl, Data: NewBytes + ResizableBytes> - DryocSecretBox +impl< + Mac: NewByteArray + Zeroize, + Data: NewBytes + ResizableBytes + Zeroize, +> DryocSecretBox { /// Encrypts a message using `secret_key`, and returns a new /// [DryocSecretBox] with ciphertext and tag @@ -178,8 +183,8 @@ impl, Data: NewBytes + ResizableByt impl< 'a, - Mac: ByteArray + std::convert::TryFrom<&'a [u8]>, - Data: Bytes + From<&'a [u8]>, + Mac: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, + Data: Bytes + From<&'a [u8]> + Zeroize, > DryocSecretBox { /// Initializes a [`DryocSecretBox`] from a slice. Expects the first @@ -203,7 +208,9 @@ impl< } } -impl, Data: Bytes> DryocSecretBox { +impl + Zeroize, Data: Bytes + Zeroize> + DryocSecretBox +{ /// Returns a new box with `tag` and `data`, consuming both pub fn from_parts(tag: Mac, data: Data) -> Self { Self { tag, data } @@ -220,7 +227,9 @@ impl, Data: Bytes> DryocSecretBox, Data: Bytes> DryocSecretBox { +impl + Zeroize, Data: Bytes + Zeroize> + DryocSecretBox +{ /// Decrypts `ciphertext` using `secret_key`, returning a new /// [DryocSecretBox] with decrypted message pub fn decrypt< @@ -299,8 +308,8 @@ impl DryocSecretBox> { impl< 'a, - Mac: NewByteArray, - Data: NewBytes + ResizableBytes + From<&'a [u8]>, + Mac: NewByteArray + Zeroize, + Data: NewBytes + ResizableBytes + From<&'a [u8]> + Zeroize, > DryocSecretBox { /// Returns a box with `data` copied from slice `input`. @@ -312,8 +321,11 @@ impl< } } -impl<'a, Mac: ByteArray, Data: Bytes + ResizableBytes + From<&'a [u8]>> - DryocSecretBox +impl< + 'a, + Mac: ByteArray + Zeroize, + Data: Bytes + ResizableBytes + From<&'a [u8]> + Zeroize, +> DryocSecretBox { /// Returns a new box with `data` and `tag`, with data copied from `input` /// and `tag` consumed. @@ -325,8 +337,8 @@ impl<'a, Mac: ByteArray, Data: Bytes + ResizableBytes } } -impl, Data: Bytes> PartialEq> - for DryocSecretBox +impl + Zeroize, Data: Bytes + Zeroize> + PartialEq> for DryocSecretBox { fn eq(&self, other: &Self) -> bool { self.tag.as_slice().ct_eq(other.tag.as_slice()).unwrap_u8() == 1 @@ -346,7 +358,8 @@ mod tests { #[test] fn test_dryocbox() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::secretbox; use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce}; @@ -369,7 +382,10 @@ mod tests { &SONonce::from_slice(&nonce).unwrap(), &SOKey::from_slice(&secret_key).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let so_decrypted = secretbox::open( &ciphertext_copy, @@ -392,7 +408,8 @@ mod tests { #[test] fn test_dryocbox_vec() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::secretbox; use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce}; @@ -415,7 +432,10 @@ mod tests { &SONonce::from_slice(&nonce).unwrap(), &SOKey::from_slice(&secret_key).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let so_decrypted = secretbox::open( &ciphertext_copy, @@ -477,7 +497,8 @@ mod tests { #[test] fn test_dryocbox_locked() { for i in 0..20 { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; use sodiumoxide::crypto::secretbox; use sodiumoxide::crypto::secretbox::{Key as SOKey, Nonce as SONonce}; @@ -501,7 +522,10 @@ mod tests { &SONonce::from_slice(nonce.as_slice()).unwrap(), &SOKey::from_slice(secret_key.as_slice()).unwrap(), ); - assert_eq!(encode(&ciphertext), encode(&so_ciphertext)); + assert_eq!( + general_purpose::STANDARD.encode(&ciphertext), + general_purpose::STANDARD.encode(&so_ciphertext) + ); let so_decrypted = secretbox::open( &ciphertext_copy, diff --git a/src/generichash.rs b/src/generichash.rs index 4cf4a9e..8b5a31d 100644 --- a/src/generichash.rs +++ b/src/generichash.rs @@ -6,7 +6,8 @@ //! # Rustaceous API example, one-time interface //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::generichash::{GenericHash, Key}; //! //! // NOTE: The type for `key` param must be specified, the compiler cannot infer it when @@ -15,7 +16,7 @@ //! GenericHash::hash_with_defaults_to_vec::<_, Key>(b"hello", None).expect("hash failed"); //! //! assert_eq!( -//! encode(&hash), +//! general_purpose::STANDARD.encode(&hash), //! "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8=" //! ); //! ``` @@ -23,7 +24,8 @@ //! # Rustaceous API example, incremental interface //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::generichash::{GenericHash, Key}; //! //! // The compiler cannot infer the `Key` type, so we pass it below. @@ -32,7 +34,7 @@ //! let hash = hasher.finalize_to_vec().expect("finalize failed"); //! //! assert_eq!( -//! encode(&hash), +//! general_purpose::STANDARD.encode(&hash), //! "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8=" //! ); //! ``` @@ -62,7 +64,6 @@ pub mod protected { //! ## Example //! //! ``` - //! use base64::encode; //! use dryoc::generichash::protected::*; //! use dryoc::generichash::GenericHash; //! @@ -125,14 +126,15 @@ impl GenericHash = hasher.finalize().expect("finalize failed"); assert_eq!( - encode(&output), + general_purpose::STANDARD.encode(&output), "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8=" ); @@ -223,20 +226,21 @@ mod tests { let output = hasher.finalize_to_vec().expect("finalize failed"); assert_eq!( - encode(&output), + general_purpose::STANDARD.encode(&output), "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8=" ); } #[test] fn test_generichash_onetime() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; let output: Hash = GenericHash::hash(b"hello", Some(b"a very secret key")).expect("hash failed"); assert_eq!( - encode(&output), + general_purpose::STANDARD.encode(&output), "AECDe+XJsB6nOkbCsbS/OPXdzpcRm3AolW/Bg1LFY9A=" ); @@ -244,7 +248,7 @@ mod tests { GenericHash::hash_with_defaults::<_, Key, _>(b"hello", None).expect("hash failed"); assert_eq!( - encode(&output), + general_purpose::STANDARD.encode(&output), "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8=" ); @@ -252,19 +256,20 @@ mod tests { GenericHash::hash_with_defaults_to_vec::<_, Key>(b"hello", None).expect("hash failed"); assert_eq!( - encode(&output), + general_purpose::STANDARD.encode(&output), "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8=" ); } #[test] fn test_generichash_onetime_empty() { - use base64::encode; + use base64::engine::general_purpose; + use base64::Engine as _; let output = GenericHash::hash_with_defaults_to_vec::<_, Key>(&[], None).expect("hash failed"); assert_eq!( - encode(&output), + general_purpose::STANDARD.encode(&output), "DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=" ); } diff --git a/src/kdf.rs b/src/kdf.rs index fc28d53..3d7caa0 100644 --- a/src/kdf.rs +++ b/src/kdf.rs @@ -13,7 +13,8 @@ //! # Rustaceous API example //! //! ``` -//! use base64::encode; +//! use base64::engine::general_purpose; +//! use base64::Engine as _; //! use dryoc::kdf::*; //! //! // Randomly generate a main key and context, using the default stack-allocated @@ -22,7 +23,11 @@ //! let subkey_id = 0; //! //! let subkey = key.derive_subkey_to_vec(subkey_id).expect("derive failed"); -//! println!("Subkey {}: {}", subkey_id, encode(&subkey)); +//! println!( +//! "Subkey {}: {}", +//! subkey_id, +//! general_purpose::STANDARD.encode(&subkey) +//! ); //! ``` //! //! ## Additional resources @@ -51,7 +56,10 @@ pub type Context = StackByteArray; #[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))] /// Key derivation implementation based on Blake2b, compatible with libsodium's /// `crypto_kdf_*` functions. -pub struct Kdf, Context: ByteArray> { +pub struct Kdf< + Key: ByteArray + Zeroize, + Context: ByteArray + Zeroize, +> { main_key: Key, context: Context, } @@ -71,7 +79,8 @@ pub mod protected { //! ## Example //! //! ``` - //! use base64::encode; + //! use base64::engine::general_purpose; + //! use base64::Engine as _; //! use dryoc::kdf::protected::*; //! use dryoc::kdf::Kdf; //! @@ -80,7 +89,11 @@ pub mod protected { //! let subkey_id = 0; //! //! let subkey: Locked = key.derive_subkey(subkey_id).expect("derive failed"); - //! println!("Subkey {}: {}", subkey_id, encode(&subkey)); + //! println!( + //! "Subkey {}: {}", + //! subkey_id, + //! general_purpose::STANDARD.encode(&subkey) + //! ); //! ``` use super::*; pub use crate::protected::*; @@ -97,8 +110,10 @@ pub mod protected { pub type LockedKdf = Kdf, Locked>; } -impl, Context: NewByteArray> - Kdf +impl< + Key: NewByteArray + Zeroize, + Context: NewByteArray + Zeroize, +> Kdf { /// Randomly generates a new pair of main key and context. pub fn gen() -> Self { @@ -109,8 +124,10 @@ impl, Context: NewByteArray, Context: ByteArray> - Kdf +impl< + Key: ByteArray + Zeroize, + Context: ByteArray + Zeroize, +> Kdf { /// Derives a subkey for `subkey_id`, returning it. pub fn derive_subkey>( diff --git a/src/keypair.rs b/src/keypair.rs index 2b03d5a..cc1adde 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -8,7 +8,7 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use subtle::ConstantTimeEq; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::classic::crypto_box::crypto_box_seed_keypair_inplace; use crate::constants::{ @@ -27,14 +27,14 @@ pub type StackKeyPair = KeyPair; #[cfg_attr( feature = "serde", - derive(Zeroize, Serialize, Deserialize, Debug, Clone) + derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize, Debug, Clone) )] -#[cfg_attr(not(feature = "serde"), derive(Zeroize, Debug, Clone))] +#[cfg_attr(not(feature = "serde"), derive(Zeroize, ZeroizeOnDrop, Debug, Clone))] /// Public/private keypair for use with [`crate::dryocbox::DryocBox`], aka /// libsodium box pub struct KeyPair< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, > { /// Public key pub public_key: PublicKey, @@ -43,8 +43,8 @@ pub struct KeyPair< } impl< - PublicKey: NewByteArray, - SecretKey: NewByteArray, + PublicKey: NewByteArray + Zeroize, + SecretKey: NewByteArray + Zeroize, > KeyPair { /// Creates a new, empty keypair. @@ -112,8 +112,8 @@ impl KeyPair, StackByteArray + std::convert::TryFrom<&'a [u8]>, - SecretKey: ByteArray + std::convert::TryFrom<&'a [u8]>, + PublicKey: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, + SecretKey: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, > KeyPair { /// Constructs a new keypair from key slices, consuming them. Does not check @@ -129,13 +129,13 @@ impl< } impl< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, > KeyPair { /// Creates new client session keys using this keypair and /// `server_public_key`, assuming this keypair is for the client. - pub fn kx_new_client_session>( + pub fn kx_new_client_session + Zeroize>( &self, server_public_key: &PublicKey, ) -> Result, Error> { @@ -144,7 +144,7 @@ impl< /// Creates new server session keys using this keypair and /// `client_public_key`, assuming this keypair is for the server. - pub fn kx_new_server_session>( + pub fn kx_new_server_session + Zeroize>( &self, client_public_key: &PublicKey, ) -> Result, Error> { @@ -153,8 +153,8 @@ impl< } impl< - PublicKey: NewByteArray, - SecretKey: NewByteArray, + PublicKey: NewByteArray + Zeroize, + SecretKey: NewByteArray + Zeroize, > Default for KeyPair { fn default() -> Self { @@ -222,8 +222,8 @@ pub mod protected { } impl< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, > PartialEq> for KeyPair { fn eq(&self, other: &Self) -> bool { diff --git a/src/kx.rs b/src/kx.rs index 17a92db..30b2fdc 100644 --- a/src/kx.rs +++ b/src/kx.rs @@ -72,7 +72,7 @@ pub type KeyPair = crate::keypair::KeyPair; #[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))] /// Key derivation implemantation based on Curve25519, Diffie-Hellman, and /// Blake2b. Compatible with libsodium's `crypto_kx_*` functions. -pub struct Session> { +pub struct Session + Zeroize> { rx_key: SessionKey, tx_key: SessionKey, } @@ -144,12 +144,12 @@ pub mod protected { pub type LockedSession = Session>; } -impl> Session { +impl + Zeroize> Session { /// Computes client session keys, given `client_keypair` and /// `server_public_key`, returning a new session upon success. pub fn new_client< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, >( client_keypair: &crate::keypair::KeyPair, server_public_key: &PublicKey, @@ -171,8 +171,8 @@ impl> Session { /// Computes server session keys, given `server_keypair` and /// `client_public_key`, returning a new session upon success. pub fn new_server< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, >( server_keypair: &crate::keypair::KeyPair, client_public_key: &PublicKey, @@ -197,8 +197,8 @@ impl Session { /// the given `client_keypair` and `server_public_key`. Wraps /// [`Session::new_client`], provided for convenience. pub fn new_client_with_defaults< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, >( client_keypair: &crate::keypair::KeyPair, server_public_key: &PublicKey, @@ -210,8 +210,8 @@ impl Session { /// the given `server_keypair` and `client_public_key`. Wraps /// [`Session::new_server`], provided for convenience. pub fn new_server_with_defaults< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, >( server_keypair: &crate::keypair::KeyPair, client_public_key: &PublicKey, @@ -220,7 +220,7 @@ impl Session { } } -impl> Session { +impl + Zeroize> Session { /// Moves the rx_key and tx_key out of this instance, returning them as a /// tuple with `(rx_key, tx_key)`. pub fn into_parts(self) -> (SessionKey, SessionKey) { diff --git a/src/protected.rs b/src/protected.rs index 6429dfb..989ccc4 100644 --- a/src/protected.rs +++ b/src/protected.rs @@ -74,7 +74,7 @@ use std::marker::PhantomData; use std::ptr; use lazy_static::lazy_static; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::error; use crate::rng::copy_randombytes; @@ -800,16 +800,14 @@ unsafe impl Allocator for PageAlignedAllocator { /// [page-aligned allocator](PageAlignedAllocator). Required for working with /// protected memory regions. Wraps a [`Vec`] with custom [`Allocator`] /// implementation. -#[derive(Zeroize, Debug, PartialEq, Eq, Clone)] -#[zeroize(drop)] +#[derive(Zeroize, ZeroizeOnDrop, Debug, PartialEq, Eq, Clone)] pub struct HeapByteArray(Vec); /// A heap-allocated resizable byte array, using the /// [page-aligned allocator](PageAlignedAllocator). Required for working with /// protected memory regions. Wraps a [`Vec`] with custom [`Allocator`] /// implementation. -#[derive(Zeroize, Debug, PartialEq, Eq, Clone)] -#[zeroize(drop)] +#[derive(Zeroize, ZeroizeOnDrop, Debug, PartialEq, Eq, Clone)] pub struct HeapBytes(Vec); impl> NewLocked for A { @@ -1420,6 +1418,14 @@ impl Drop for Protected { fn drop(&mut self) { + self.zeroize() + } +} + +impl Zeroize + for Protected +{ + fn zeroize(&mut self) { match &mut self.i { Some(d) => { if !d.a.as_slice().is_empty() { diff --git a/src/pwhash.rs b/src/pwhash.rs index 06c2351..ba7c50e 100644 --- a/src/pwhash.rs +++ b/src/pwhash.rs @@ -209,7 +209,7 @@ impl Default for Config { #[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))] /// Password hash implementation based on Argon2, compatible with libsodium's /// `crypto_pwhash_*` functions. -pub struct PwHash { +pub struct PwHash { hash: Hash, salt: Salt, config: Config, @@ -261,7 +261,9 @@ pub mod protected { pub type LockedPwHash = PwHash, Locked>; } -impl PwHash { +impl + PwHash +{ /// Hashes `password` with a random salt and `config`, returning /// the hash, salt, and config upon success. pub fn hash(password: &Password, config: Config) -> Result { @@ -347,7 +349,7 @@ impl PwHash PwHash { +impl PwHash { /// Verifies that this hash, salt, and config is valid for `password`. pub fn verify(&self, password: &Password) -> Result<(), Error> { let computed = Self::hash_with_salt(password, self.salt.clone(), self.config.clone())?; @@ -391,7 +393,9 @@ impl PwHash { #[cfg(any(feature = "base64", all(doc, not(doctest))))] #[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "base64")))] -impl>, Salt: Bytes + From>> PwHash { +impl> + Zeroize, Salt: Bytes + From> + Zeroize> + PwHash +{ /// Creates a new password hash instance by parsing `hashed_password`. /// Compatible with libsodium's `crypto_pwhash_str*` functions, and supports /// variable-length encoding for the hash and salt. @@ -421,7 +425,7 @@ impl>, Salt: Bytes + From>> PwHash PwHash { +impl PwHash { /// Constructs a new instance from `hash`, `salt`, and `config`, consuming /// them. pub fn from_parts(hash: Hash, salt: Salt, config: Config) -> Self { @@ -435,12 +439,12 @@ impl PwHash { } } -impl PwHash { +impl PwHash { /// Derives a keypair from `password` and `salt`, using `config`. pub fn derive_keypair< - Password: Bytes, - PublicKey: NewByteArray, - SecretKey: NewByteArray, + Password: Bytes + Zeroize, + PublicKey: NewByteArray + Zeroize, + SecretKey: NewByteArray + Zeroize, >( password: &Password, salt: Salt, diff --git a/src/sign.rs b/src/sign.rs index 79f8f8e..84d091b 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -76,7 +76,7 @@ #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use subtle::ConstantTimeEq; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::classic::crypto_sign::{ crypto_sign_detached, crypto_sign_final_create, crypto_sign_final_verify, crypto_sign_init, @@ -101,13 +101,13 @@ pub type Message = Vec; #[cfg_attr( feature = "serde", - derive(Zeroize, Serialize, Deserialize, Debug, Clone) + derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize, Debug, Clone) )] -#[cfg_attr(not(feature = "serde"), derive(Zeroize, Debug, Clone))] +#[cfg_attr(not(feature = "serde"), derive(Zeroize, ZeroizeOnDrop, Debug, Clone))] /// An Ed25519 keypair for public-key signatures pub struct SigningKeyPair< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, > { /// Public key pub public_key: PublicKey, @@ -116,8 +116,8 @@ pub struct SigningKeyPair< } impl< - PublicKey: NewByteArray, - SecretKey: NewByteArray, + PublicKey: NewByteArray + Zeroize, + SecretKey: NewByteArray + Zeroize, > SigningKeyPair { /// Creates a new, empty signing keypair. @@ -182,8 +182,8 @@ impl impl< 'a, - PublicKey: ByteArray + std::convert::TryFrom<&'a [u8]>, - SecretKey: ByteArray + std::convert::TryFrom<&'a [u8]>, + PublicKey: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, + SecretKey: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, > SigningKeyPair { /// Constructs a new signing keypair from key slices, consuming them. Does @@ -304,20 +304,23 @@ pub mod protected { )] #[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))] /// A signed message, for use with [`SigningKeyPair`]. -pub struct SignedMessage, Message: Bytes> { +pub struct SignedMessage< + Signature: ByteArray + Zeroize, + Message: Bytes + Zeroize, +> { signature: Signature, message: Message, } impl< - PublicKey: ByteArray, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, > SigningKeyPair { /// Signs `message` using this keypair, consuming the message, and returning /// a new [`SignedMessage`]. The type of `message` should match that of the /// target signed message. - pub fn sign, Message: Bytes>( + pub fn sign + Zeroize, Message: Bytes + Zeroize>( &self, message: Message, ) -> Result, Error> { @@ -402,7 +405,9 @@ impl Default for IncrementalSigner { } } -impl, Message: Bytes> SignedMessage { +impl + Zeroize, Message: Bytes + Zeroize> + SignedMessage +{ /// Verifies that this signed message is valid for `public_key`. pub fn verify>( &self, @@ -418,8 +423,8 @@ impl, Message: Bytes> SignedMessage + std::convert::TryFrom<&'a [u8]>, - Message: Bytes + From<&'a [u8]>, + Signature: ByteArray + std::convert::TryFrom<&'a [u8]> + Zeroize, + Message: Bytes + From<&'a [u8]> + Zeroize, > SignedMessage { /// Initializes a [`SignedMessage`] from a slice. Expects the first @@ -443,7 +448,9 @@ impl< } } -impl, Message: Bytes> SignedMessage { +impl + Zeroize, Message: Bytes + Zeroize> + SignedMessage +{ /// Returns a new box with `tag`, `data` and (optional) `ephemeral_pk`, /// consuming each. pub fn from_parts(signature: Signature, message: Message) -> Self { @@ -475,8 +482,8 @@ impl, Message: Bytes> SignedMessage, - SecretKey: ByteArray, + PublicKey: ByteArray + Zeroize, + SecretKey: ByteArray + Zeroize, > PartialEq> for SigningKeyPair { fn eq(&self, other: &Self) -> bool { @@ -494,7 +501,7 @@ impl< } } -impl, Message: Bytes> +impl + Zeroize, Message: Bytes + Zeroize> PartialEq> for SignedMessage { fn eq(&self, other: &Self) -> bool { diff --git a/src/types.rs b/src/types.rs index 430043b..855c0e2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use lazy_static::__Deref; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; #[cfg(any(feature = "serde"))] pub use crate::bytes_serde::*; @@ -9,8 +9,7 @@ use crate::rng::copy_randombytes; /// A stack-allocated fixed-length byte array for working with data, with /// optional [Serde](https://serde.rs) features. -#[derive(Zeroize, Debug, PartialEq, Eq, Clone)] -#[zeroize(drop)] +#[derive(Zeroize, ZeroizeOnDrop, Debug, PartialEq, Eq, Clone)] pub struct StackByteArray([u8; LENGTH]); /// Fixed-length byte array.