diff --git a/.github/workflows/crypto_box.yml b/.github/workflows/crypto_box.yml index 948fb11..11d59c1 100644 --- a/.github/workflows/crypto_box.yml +++ b/.github/workflows/crypto_box.yml @@ -23,7 +23,7 @@ jobs: strategy: matrix: rust: - - 1.56.0 # MSRV + - 1.60.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -44,7 +44,7 @@ jobs: strategy: matrix: rust: - - 1.56.0 # MSRV + - 1.60.0 # MSRV - stable steps: - uses: actions/checkout@v3 diff --git a/Cargo.lock b/Cargo.lock index 1de620b..96cf3f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,7 +211,7 @@ dependencies = [ [[package]] name = "crypto_box" -version = "0.8.2" +version = "0.9.0-pre" dependencies = [ "aead", "bincode", @@ -219,11 +219,11 @@ dependencies = [ "chacha20", "chacha20poly1305", "crypto_secretbox", + "curve25519-dalek 4.0.0-rc.1", "rand", "rmp-serde", "salsa20", "serdect", - "x25519-dalek", "zeroize", ] @@ -276,6 +276,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +dependencies = [ + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms", + "subtle", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -315,6 +329,12 @@ dependencies = [ "void", ] +[[package]] +name = "fiat-crypto" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" + [[package]] name = "generic-array" version = "0.14.6" @@ -402,6 +422,12 @@ version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + [[package]] name = "libsodium-sys" version = "0.2.7" @@ -475,6 +501,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm", +] + [[package]] name = "paste" version = "1.0.9" @@ -487,6 +523,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "poly1305" version = "0.8.0" @@ -931,7 +973,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 3.2.0", "rand_core 0.5.1", "zeroize", ] diff --git a/crypto_box/Cargo.toml b/crypto_box/Cargo.toml index c21368b..dfa93ca 100644 --- a/crypto_box/Cargo.toml +++ b/crypto_box/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crypto_box" -version = "0.8.2" +version = "0.9.0-pre" description = """ Pure Rust implementation of NaCl's crypto_box public-key authenticated encryption primitive which combines the X25519 Elliptic Curve Diffie-Hellman @@ -15,15 +15,15 @@ repository = "https://github.com/RustCrypto/nacl-compat/tree/master/crypto_box" categories = ["cryptography", "no-std"] keywords = ["nacl", "libsodium", "public-key", "x25519", "xsalsa20poly1305"] edition = "2021" -rust-version = "1.56" +rust-version = "1.60" [dependencies] aead = { version = "0.5.1", default-features = false } chacha20 = "0.9" chacha20poly1305 = { version = "0.10.1", default-features = false, features = ["rand_core"] } crypto_secretbox = { version = "0", default-features = false, path = "../crypto_secretbox" } +curve25519-dalek = { version = "4.0.0-rc.1", default-features = false, features = ["zeroize"] } salsa20 = "0.10" -x25519-dalek = { version = "1", default-features = false } zeroize = { version = "1", default-features = false } # optional dependencies @@ -36,7 +36,7 @@ rand = "0.8" rmp-serde = "1" [features] -default = ["alloc", "getrandom", "u64_backend"] +default = ["alloc", "getrandom"] std = ["aead/std"] serde = ["serdect"] alloc = ["aead/alloc"] @@ -44,8 +44,6 @@ getrandom = ["aead/getrandom", "rand_core"] heapless = ["aead/heapless"] rand_core = ["aead/rand_core"] seal = ["alloc", "blake2"] -u32_backend = ["x25519-dalek/u32_backend"] -u64_backend = ["x25519-dalek/u64_backend"] [package.metadata.docs.rs] features = ["serde", "seal"] diff --git a/crypto_box/README.md b/crypto_box/README.md index 2187bef..a5aabbb 100644 --- a/crypto_box/README.md +++ b/crypto_box/README.md @@ -68,7 +68,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/crypto_box/badge.svg [docs-link]: https://docs.rs/crypto_box/ [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 +[rustc-image]: https://img.shields.io/badge/rustc-1.60+-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/nacl-compat/actions/workflows/crypto_box.yml/badge.svg diff --git a/crypto_box/src/lib.rs b/crypto_box/src/lib.rs index eaf72b5..a6d54cd 100644 --- a/crypto_box/src/lib.rs +++ b/crypto_box/src/lib.rs @@ -176,9 +176,9 @@ use chacha20::hchacha; use chacha20poly1305::XChaCha20Poly1305; use core::fmt::{self, Debug}; use crypto_secretbox::XSalsa20Poly1305; +use curve25519_dalek::{MontgomeryPoint, Scalar}; use rand_core::{CryptoRng, RngCore}; use salsa20::hsalsa; -use x25519_dalek::{x25519, X25519_BASEPOINT_BYTES}; use zeroize::{Zeroize, Zeroizing}; #[cfg(feature = "seal")] @@ -206,7 +206,7 @@ pub const SEALBYTES: usize = KEY_SIZE + TAG_SIZE; /// A `crypto_box` secret key. #[derive(Clone)] -pub struct SecretKey([u8; KEY_SIZE]); +pub struct SecretKey(Scalar); impl SecretKey { /// Generate a random [`SecretKey`]. @@ -216,35 +216,34 @@ impl SecretKey { { let mut bytes = [0u8; KEY_SIZE]; csprng.fill_bytes(&mut bytes); - SecretKey(bytes) + bytes.into() } /// Get the [`PublicKey`] which corresponds to this [`SecretKey`] pub fn public_key(&self) -> PublicKey { - PublicKey(x25519(self.0, X25519_BASEPOINT_BYTES)) + PublicKey(MontgomeryPoint::mul_base(&self.0).to_bytes()) } - #[deprecated(note = "use `as_bytes` instead")] - #[allow(missing_docs)] + /// Serialize [`SecretKey`] to bytes. + /// + /// # ⚠️Warning + /// + /// The serialized bytes are secret key material. Please treat them with + /// the care they deserve! pub fn to_bytes(&self) -> [u8; KEY_SIZE] { - self.0 - } - - /// Get a slice of the [`SecretKey`] bytes - pub fn as_bytes(&self) -> &[u8; KEY_SIZE] { - &self.0 + self.0.to_bytes() } } impl From<[u8; KEY_SIZE]> for SecretKey { fn from(bytes: [u8; KEY_SIZE]) -> SecretKey { - SecretKey(bytes) + SecretKey(Scalar::from_bits_clamped(bytes)) } } impl Debug for SecretKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("SecretKey(...)") + f.debug_struct("SecretKey").finish_non_exhaustive() } } @@ -261,20 +260,22 @@ impl Drop for SecretKey { pub struct PublicKey([u8; KEY_SIZE]); impl PublicKey { - /// Get a slice of the [`PublicKey`] bytes - pub fn as_bytes(&self) -> &[u8; KEY_SIZE] { - &self.0 - } - /// Create a public key from a slice. The bytes of the slice will be copied. /// /// This function will fail and return `None` if the length of the byte /// slice isn't exactly [`KEY_SIZE`]. pub fn from_slice(slice: &[u8]) -> Option { - match slice.try_into() { - Ok(array) => Some(Self(array)), - Err(_) => None, - } + slice.try_into().map(PublicKey).ok() + } + + /// Borrow the public key as bytes. + pub fn as_bytes(&self) -> &[u8; KEY_SIZE] { + &self.0 + } + + /// Serialize this public key as bytes. + pub fn to_bytes(&self) -> [u8; KEY_SIZE] { + self.0 } } @@ -388,11 +389,11 @@ impl SalsaBox { /// Create a new [`SalsaBox`], performing X25519 Diffie-Hellman to derive /// a shared secret from the provided public and secret keys. pub fn new(public_key: &PublicKey, secret_key: &SecretKey) -> Self { - let shared_secret = Zeroizing::new(x25519(secret_key.0, public_key.0)); + let shared_secret = Zeroizing::new(secret_key.0 * MontgomeryPoint(public_key.0)); // Use HSalsa20 to create a uniformly random key from the shared secret let mut key = hsalsa::( - GenericArray::from_slice(&*shared_secret), + GenericArray::from_slice(&shared_secret.0), &GenericArray::default(), ); @@ -422,11 +423,11 @@ impl ChaChaBox { /// Create a new [`ChaChaBox`], performing X25519 Diffie-Hellman to derive /// a shared secret from the provided public and secret keys. pub fn new(public_key: &PublicKey, secret_key: &SecretKey) -> Self { - let shared_secret = Zeroizing::new(x25519(secret_key.0, public_key.0)); + let shared_secret = Zeroizing::new(secret_key.0 * MontgomeryPoint(public_key.0)); // Use HChaCha20 to create a uniformly random key from the shared secret let mut key = hchacha::( - GenericArray::from_slice(&*shared_secret), + GenericArray::from_slice(&shared_secret.0), &GenericArray::default(), ); diff --git a/crypto_box/tests/lib.rs b/crypto_box/tests/lib.rs index 1450794..2b25487 100644 --- a/crypto_box/tests/lib.rs +++ b/crypto_box/tests/lib.rs @@ -56,7 +56,7 @@ fn generate_secret_key() { #[test] fn secret_and_public_keys() { let secret_key = SecretKey::from(ALICE_SECRET_KEY); - assert_eq!(secret_key.as_bytes(), &ALICE_SECRET_KEY); + assert_eq!(secret_key.to_bytes(), ALICE_SECRET_KEY); // Ensure `Debug` impl on `SecretKey` is covered in tests dbg!(&secret_key);