Skip to content

Commit

Permalink
Add xwing, x25519 and ed25519
Browse files Browse the repository at this point in the history
  • Loading branch information
quexten committed Nov 11, 2024
1 parent 565ba4d commit a81d10b
Show file tree
Hide file tree
Showing 8 changed files with 273 additions and 6 deletions.
146 changes: 146 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ version = "1.0.0"
authors = ["Bitwarden Inc"]
edition = "2021"
# Note: Changing rust-version should be considered a breaking change
rust-version = "1.75"
rust-version = "1.81"
homepage = "https://bitwarden.com"
repository = "https://github.com/bitwarden/sdk-internal"
license-file = "LICENSE"
keywords = ["bitwarden"]

# Define dependencies that are expected to be consistent across all crates
[workspace.dependencies]
bitwarden = { path = "crates/bitwarden", version = "=1.0.0" }
bitwarden-api-api = { path = "crates/bitwarden-api-api", version = "=1.0.0" }
bitwarden-api-identity = { path = "crates/bitwarden-api-identity", version = "=1.0.0" }
bitwarden-cli = { path = "crates/bitwarden-cli", version = "=1.0.0" }
Expand All @@ -27,7 +26,6 @@ bitwarden-exporters = { path = "crates/bitwarden-exporters", version = "=1.0.0"
bitwarden-fido = { path = "crates/bitwarden-fido", version = "=1.0.0" }
bitwarden-generators = { path = "crates/bitwarden-generators", version = "=1.0.0" }
bitwarden-send = { path = "crates/bitwarden-send", version = "=1.0.0" }
bitwarden-sm = { path = "bitwarden_license/bitwarden-sm", version = "=1.0.0" }
bitwarden-vault = { path = "crates/bitwarden-vault", version = "=1.0.0" }

# External crates that are expected to maintain a consistent version across all crates
Expand Down Expand Up @@ -56,7 +54,6 @@ uniffi = "=0.28.1"
uuid = { version = ">=1.3.3, <2.0", features = ["serde", "v4"] }
validator = { version = "0.18.1", features = ["derive"] }
wasm-bindgen = { version = ">=0.2.91, <0.3", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.41"

[workspace.lints.clippy]
unused_async = "deny"
Expand Down
4 changes: 4 additions & 0 deletions crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ argon2 = { version = ">=0.5.0, <0.6", features = [
base64 = ">=0.22.1, <0.23"
cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] }
chacha20poly1305 = "0.10.1"
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] }
hkdf = ">=0.12.3, <0.13"
hmac = ">=0.12.1, <0.13"
ml-kem = "0.2.1"
num-bigint = ">=0.4, <0.5"
num-traits = ">=0.2.15, <0.3"
pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false }
Expand All @@ -49,6 +51,8 @@ tsify-next = { workspace = true, optional = true }
uniffi = { workspace = true, optional = true }
uuid = { workspace = true }
wasm-bindgen = { workspace = true, optional = true }
x-wing = "0.0.1-alpha"
x25519-dalek = { version = "2.0.1", features = ["reusable_secrets"] }
zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] }

[dev-dependencies]
Expand Down
31 changes: 31 additions & 0 deletions crates/bitwarden-crypto/src/ed25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use ed25519_dalek::{SigningKey, VerifyingKey};
use rand::rngs::OsRng;
use rsa::signature::SignerMut;

use crate::CryptoError;

pub fn generate_ed25519_keypair() -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
let secret = SigningKey::generate(&mut OsRng);
let public = VerifyingKey::from(&secret);
let secret_bytes: Vec<u8> = secret.to_bytes().to_vec();
let public_bytes = public.as_bytes().to_vec();
Ok((secret_bytes.to_vec(), public_bytes))
}

Check warning on line 13 in crates/bitwarden-crypto/src/ed25519.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/ed25519.rs#L7-L13

Added lines #L7 - L13 were not covered by tests

pub fn sign(data: Vec<u8>, secret: Vec<u8>) -> Result<Vec<u8>, CryptoError> {
let secret_fixed: [u8; 32] = secret.try_into().map_err(|_| CryptoError::InvalidKey)?;
let mut secret = SigningKey::from_bytes(&secret_fixed);
let data_fixed: &[u8] = data.as_slice();
let signature = secret.sign(data_fixed);
Ok(signature.to_bytes().to_vec())
}

Check warning on line 21 in crates/bitwarden-crypto/src/ed25519.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/ed25519.rs#L15-L21

Added lines #L15 - L21 were not covered by tests

pub fn verify(data: Vec<u8>, signature: Vec<u8>, public: Vec<u8>) -> Result<bool, CryptoError> {
let public_fixed: [u8; 32] = public.try_into().map_err(|_| CryptoError::InvalidKey)?;
let public = VerifyingKey::from_bytes(&public_fixed).map_err(|_| CryptoError::InvalidKey)?;
let data_fixed: &[u8] = data.as_slice();
let signature_fixed: [u8; 64] = signature.try_into().map_err(|_| CryptoError::InvalidKey)?;
let signature = ed25519_dalek::Signature::from_bytes(&signature_fixed);
let res = public.verify_strict(data_fixed, &signature).map_err(|_| CryptoError::InvalidKey);
Ok(res.is_ok())
}

Check warning on line 31 in crates/bitwarden-crypto/src/ed25519.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/ed25519.rs#L23-L31

Added lines #L23 - L31 were not covered by tests
3 changes: 3 additions & 0 deletions crates/bitwarden-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ pub use wordlist::EFF_LONG_WORD_LIST;
mod allocator;
pub use allocator::ZeroizingAllocator;
pub mod chacha20;
pub mod xwing;
pub mod x25519;
pub mod ed25519;

#[cfg(feature = "uniffi")]
uniffi::setup_scaffolding!();
Expand Down
20 changes: 20 additions & 0 deletions crates/bitwarden-crypto/src/x25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use x25519_dalek::{EphemeralSecret, PublicKey, StaticSecret};
use rand::rngs::OsRng;

use crate::CryptoError;

fn generate_x25519_keypair() -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
let secret = StaticSecret::new(OsRng);
let public = PublicKey::from(&secret);
let secret_bytes: Vec<u8> = secret.to_bytes().to_vec();
let public_bytes = public.as_bytes().to_vec();
Ok((secret_bytes.to_vec(), public_bytes))
}

Check warning on line 12 in crates/bitwarden-crypto/src/x25519.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/x25519.rs#L6-L12

Added lines #L6 - L12 were not covered by tests

fn derive_shared(pubkey: Vec<u8>) -> Result<Vec<u8>, CryptoError> {
let pubkey_fixed: [u8; 32] = pubkey.try_into().map_err(|_| CryptoError::InvalidKey)?;
let public = PublicKey::from(pubkey_fixed);
let secret = EphemeralSecret::new(OsRng);
let shared_secret = secret.diffie_hellman(&public);
Ok(shared_secret.as_bytes().to_vec())
}

Check warning on line 20 in crates/bitwarden-crypto/src/x25519.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/x25519.rs#L14-L20

Added lines #L14 - L20 were not covered by tests
30 changes: 30 additions & 0 deletions crates/bitwarden-crypto/src/xwing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::io::Read;

use ml_kem::kem::Encapsulate;
use ml_kem::kem::Decapsulate;
use crate::{CryptoError};

pub fn generate_keypair() -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
let mut rng = rand::thread_rng();
let (sk, pk) = x_wing::generate_key_pair(&mut rng);
let sk_bytes = sk.as_bytes();
let pk_bytes = pk.as_bytes();
Ok((sk_bytes.to_vec(), pk_bytes.to_vec()))
}

Check warning on line 13 in crates/bitwarden-crypto/src/xwing.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/xwing.rs#L7-L13

Added lines #L7 - L13 were not covered by tests

pub fn encapsulate(pk: &[u8]) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
let pk_fixed_slize: &[u8; 1216] = pk.try_into().map_err(|_| CryptoError::InvalidKey)?;
let mut rng = rand::thread_rng();
let pk = x_wing::EncapsulationKey::from(pk_fixed_slize);
let (ct, ss_sender) = pk.encapsulate(&mut rng).unwrap();
Ok((ct.as_bytes().to_vec(), ss_sender.to_vec()))
}

Check warning on line 21 in crates/bitwarden-crypto/src/xwing.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/xwing.rs#L15-L21

Added lines #L15 - L21 were not covered by tests

pub fn decapsulate(sk: &[u8], ct: &[u8]) -> Result<Vec<u8>, CryptoError> {
let sk_fixed_slize: [u8; 32] = sk.try_into().map_err(|_| CryptoError::InvalidKey)?;
let ct_fixed_slize: &[u8; 1120] = ct.try_into().map_err(|_| CryptoError::InvalidKey)?;
let sk = x_wing::DecapsulationKey::from(sk_fixed_slize);
let ct = x_wing::Ciphertext::from(ct_fixed_slize);
let ss_receiver = sk.decapsulate(&ct).unwrap();
Ok(ss_receiver.to_vec())
}

Check warning on line 30 in crates/bitwarden-crypto/src/xwing.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/xwing.rs#L23-L30

Added lines #L23 - L30 were not covered by tests
Loading

0 comments on commit a81d10b

Please sign in to comment.