From 578632ccf9ae4ec60fca46ae43fbc8d2fe845a6b Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Thu, 28 Nov 2024 11:22:19 +0100 Subject: [PATCH] [PM-10405] Add bitwarden-ssh crate with keygeneration support (#35) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎟ī¸ Tracking https://bitwarden.atlassian.net/browse/PM-10405 ## 📔 Objective Adds a new bitwarden-ssh crate to the sdk. This should later include both import-parsing and key generation. This PR also exposes this for the web clients (not mobile yet). ## ⏰ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## đŸĻŽ Reviewer guidelines - 👍 (`:+1:`) or similar for great changes - 📝 (`:memo:`) or ℹī¸ (`:information_source:`) for notes or general info - ❓ (`:question:`) for questions - 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - 🎨 (`:art:`) for suggestions / improvements - ❌ (`:x:`) or ⚠ī¸ (`:warning:`) for more significant problems or concerns needing attention - 🌱 (`:seedling:`) or â™ģī¸ (`:recycle:`) for future improvements or indications of technical debt - ⛏ (`:pick:`) for minor or nitpick changes --- Cargo.lock | 271 ++++++++++++++++++++++ Cargo.toml | 1 + crates/bitwarden-ssh/Cargo.toml | 39 ++++ crates/bitwarden-ssh/README.md | 6 + crates/bitwarden-ssh/src/error.rs | 11 + crates/bitwarden-ssh/src/lib.rs | 100 ++++++++ crates/bitwarden-ssh/tests/ed25519_key | 7 + crates/bitwarden-ssh/tests/rsa3072_key | 38 +++ crates/bitwarden-ssh/tests/rsa4096_key | 49 ++++ crates/bitwarden-wasm-internal/Cargo.toml | 1 + crates/bitwarden-wasm-internal/src/lib.rs | 1 + crates/bitwarden-wasm-internal/src/ssh.rs | 8 + 12 files changed, 532 insertions(+) create mode 100644 crates/bitwarden-ssh/Cargo.toml create mode 100644 crates/bitwarden-ssh/README.md create mode 100644 crates/bitwarden-ssh/src/error.rs create mode 100644 crates/bitwarden-ssh/src/lib.rs create mode 100644 crates/bitwarden-ssh/tests/ed25519_key create mode 100644 crates/bitwarden-ssh/tests/rsa3072_key create mode 100644 crates/bitwarden-ssh/tests/rsa4096_key create mode 100644 crates/bitwarden-wasm-internal/src/ssh.rs diff --git a/Cargo.lock b/Cargo.lock index f41be3aa..836a15eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + [[package]] name = "aes" version = "0.8.4" @@ -29,6 +39,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -273,6 +297,17 @@ dependencies = [ "serde", ] +[[package]] +name = "bcrypt-pbkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2" +dependencies = [ + "blowfish", + "pbkdf2", + "sha2", +] + [[package]] name = "bincode" version = "1.3.3" @@ -539,6 +574,22 @@ dependencies = [ "validator", ] +[[package]] +name = "bitwarden-ssh" +version = "1.0.0" +dependencies = [ + "bitwarden-error", + "bitwarden-vault", + "js-sys", + "rand", + "rand_chacha", + "serde", + "ssh-key", + "thiserror", + "tsify-next", + "wasm-bindgen", +] + [[package]] name = "bitwarden-uniffi" version = "0.1.0" @@ -598,6 +649,7 @@ dependencies = [ "bitwarden-core", "bitwarden-crypto", "bitwarden-error", + "bitwarden-ssh", "bitwarden-vault", "console_error_panic_hook", "console_log", @@ -635,6 +687,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -739,6 +801,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "chrono" version = "0.4.38" @@ -1097,6 +1170,41 @@ dependencies = [ "memchr", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "darling" version = "0.20.10" @@ -1253,6 +1361,27 @@ dependencies = [ "spki", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2", + "subtle", +] + [[package]] name = "either" version = "1.13.0" @@ -1358,6 +1487,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fnv" version = "1.0.7" @@ -1513,6 +1648,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.28.1" @@ -2176,6 +2321,12 @@ version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2211,6 +2362,32 @@ dependencies = [ "sha2", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core", + "sha2", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2406,6 +2583,29 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2695,6 +2895,7 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core", + "sha2", "signature", "spki", "subtle", @@ -2713,6 +2914,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.37" @@ -3210,6 +3420,57 @@ dependencies = [ "der", ] +[[package]] +name = "ssh-cipher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" +dependencies = [ + "aes", + "aes-gcm", + "cbc", + "chacha20", + "cipher", + "ctr", + "poly1305", + "ssh-encoding", + "subtle", +] + +[[package]] +name = "ssh-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" +dependencies = [ + "base64ct", + "pem-rfc7468", + "sha2", +] + +[[package]] +name = "ssh-key" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" +dependencies = [ + "bcrypt-pbkdf", + "ed25519-dalek", + "num-bigint-dig", + "p256", + "p384", + "p521", + "rand_core", + "rsa", + "sec1", + "sha2", + "signature", + "ssh-cipher", + "ssh-encoding", + "subtle", + "zeroize", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -3801,6 +4062,16 @@ dependencies = [ "weedle2", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index aa14ca88..4c6182ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ 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-ssh = { path = "crates/bitwarden-ssh", version = "=1.0.0" } bitwarden-vault = { path = "crates/bitwarden-vault", version = "=1.0.0" } bitwarden-error = { path = "crates/bitwarden-error", version = "=1.0.0" } bitwarden-error-macro = { path = "crates/bitwarden-error-macro", version = "=1.0.0" } diff --git a/crates/bitwarden-ssh/Cargo.toml b/crates/bitwarden-ssh/Cargo.toml new file mode 100644 index 00000000..2511821a --- /dev/null +++ b/crates/bitwarden-ssh/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "bitwarden-ssh" +description = """ +Internal crate for the bitwarden crate. Do not use. +""" + +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +homepage.workspace = true +repository.workspace = true +license-file.workspace = true +keywords.workspace = true + +[features] +wasm = [ "bitwarden-error/wasm", "dep:js-sys", "dep:tsify-next", "dep:wasm-bindgen"] # WASM support + +[dependencies] +bitwarden-error = { workspace = true } +bitwarden-vault = { workspace = true } +rand = "0.8.5" +serde.workspace = true +ssh-key = { version = "0.6.7", features = [ + "ed25519", + "encryption", + "rsa", + "getrandom", +] } +thiserror = { workspace = true } +wasm-bindgen = { workspace = true, optional = true } +js-sys = { workspace = true, optional = true } +tsify-next = { workspace = true, optional = true } + +[dev-dependencies] +rand_chacha = "0.3.1" + +[lints] +workspace = true diff --git a/crates/bitwarden-ssh/README.md b/crates/bitwarden-ssh/README.md new file mode 100644 index 00000000..0dd46306 --- /dev/null +++ b/crates/bitwarden-ssh/README.md @@ -0,0 +1,6 @@ +# Bitwarden SSH + +This is an internal crate for the Bitwarden SDK do not depend on this directly and use the +[`bitwarden`](https://crates.io/crates/bitwarden) crate instead. + +This crate does not follow semantic versioning and the public interface may change at any time. diff --git a/crates/bitwarden-ssh/src/error.rs b/crates/bitwarden-ssh/src/error.rs new file mode 100644 index 00000000..f4c0409a --- /dev/null +++ b/crates/bitwarden-ssh/src/error.rs @@ -0,0 +1,11 @@ +use bitwarden_error::prelude::*; +use thiserror::Error; + +#[bitwarden_error(flat)] +#[derive(Error, Debug)] +pub enum KeyGenerationError { + #[error("Failed to generate key: {0}")] + KeyGenerationError(ssh_key::Error), + #[error("Failed to convert key: {0}")] + KeyConversionError(ssh_key::Error), +} diff --git a/crates/bitwarden-ssh/src/lib.rs b/crates/bitwarden-ssh/src/lib.rs new file mode 100644 index 00000000..7736ee33 --- /dev/null +++ b/crates/bitwarden-ssh/src/lib.rs @@ -0,0 +1,100 @@ +use error::KeyGenerationError; +use ssh_key::{rand_core::CryptoRngCore, Algorithm, HashAlg, LineEnding}; + +pub mod error; + +use serde::{Deserialize, Serialize}; +#[cfg(feature = "wasm")] +use tsify_next::Tsify; + +#[derive(Serialize, Deserialize)] +#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] +pub enum KeyAlgorithm { + Ed25519, + Rsa3072, + Rsa4096, +} + +pub fn generate_sshkey( + key_algorithm: KeyAlgorithm, +) -> Result { + let rng = rand::thread_rng(); + generate_sshkey_internal(key_algorithm, rng) +} + +fn generate_sshkey_internal( + key_algorithm: KeyAlgorithm, + mut rng: impl CryptoRngCore, +) -> Result { + let key = match key_algorithm { + KeyAlgorithm::Ed25519 => ssh_key::PrivateKey::random(&mut rng, Algorithm::Ed25519), + KeyAlgorithm::Rsa3072 | KeyAlgorithm::Rsa4096 => { + let bits = match key_algorithm { + KeyAlgorithm::Rsa3072 => 3072, + KeyAlgorithm::Rsa4096 => 4096, + _ => unreachable!(), + }; + + let rsa_keypair = ssh_key::private::RsaKeypair::random(&mut rng, bits) + .map_err(KeyGenerationError::KeyGenerationError)?; + + let private_key = + ssh_key::PrivateKey::new(ssh_key::private::KeypairData::from(rsa_keypair), "") + .map_err(KeyGenerationError::KeyGenerationError)?; + Ok(private_key) + } + } + .map_err(KeyGenerationError::KeyGenerationError)?; + + let private_key_openssh = key + .to_openssh(LineEnding::LF) + .map_err(KeyGenerationError::KeyConversionError)?; + Ok(GenerateSshKeyResult { + private_key: private_key_openssh.to_string(), + public_key: key.public_key().to_string(), + key_fingerprint: key.fingerprint(HashAlg::Sha256).to_string(), + }) +} + +#[derive(Serialize, Deserialize)] +#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] +pub struct GenerateSshKeyResult { + pub private_key: String, + pub public_key: String, + pub key_fingerprint: String, +} + +#[cfg(test)] +mod tests { + use rand::SeedableRng; + + use super::KeyAlgorithm; + use crate::generate_sshkey_internal; + + #[test] + fn generate_ssh_key_ed25519() { + let rng = rand_chacha::ChaCha12Rng::from_seed([0u8; 32]); + let key_algorithm = KeyAlgorithm::Ed25519; + let result = generate_sshkey_internal(key_algorithm, rng); + let target = include_str!("../tests/ed25519_key").replace("\r\n", "\n"); + assert_eq!(result.unwrap().private_key, target); + } + + #[test] + fn generate_ssh_key_rsa3072() { + let rng = rand_chacha::ChaCha12Rng::from_seed([0u8; 32]); + let key_algorithm = KeyAlgorithm::Rsa3072; + let result = generate_sshkey_internal(key_algorithm, rng); + let target = include_str!("../tests/rsa3072_key").replace("\r\n", "\n"); + assert_eq!(result.unwrap().private_key, target); + } + + #[test] + fn generate_ssh_key_rsa4096() { + let rng = rand_chacha::ChaCha12Rng::from_seed([0u8; 32]); + let key_algorithm = KeyAlgorithm::Rsa4096; + let result = generate_sshkey_internal(key_algorithm, rng); + let target = include_str!("../tests/rsa4096_key").replace("\r\n", "\n"); + assert_eq!(result.unwrap().private_key, target); + } +} diff --git a/crates/bitwarden-ssh/tests/ed25519_key b/crates/bitwarden-ssh/tests/ed25519_key new file mode 100644 index 00000000..3bbf5ea6 --- /dev/null +++ b/crates/bitwarden-ssh/tests/ed25519_key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCWETEIh/JX+ZaK0Xlg5xZ9QIfjiKD2Qs57PjhRY45trwAAAIhqmvSbapr0 +mwAAAAtzc2gtZWQyNTUxOQAAACCWETEIh/JX+ZaK0Xlg5xZ9QIfjiKD2Qs57PjhRY45trw +AAAEAHVflTgR/OEl8mg9UEKcO7SeB0FH4AiaUurhVfBWT4eZYRMQiH8lf5lorReWDnFn1A +h+OIoPZCzns+OFFjjm2vAAAAAAECAwQF +-----END OPENSSH PRIVATE KEY----- diff --git a/crates/bitwarden-ssh/tests/rsa3072_key b/crates/bitwarden-ssh/tests/rsa3072_key new file mode 100644 index 00000000..3baf6e51 --- /dev/null +++ b/crates/bitwarden-ssh/tests/rsa3072_key @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +92BGVXBMaMQH6FAAAAAAEC +-----END OPENSSH PRIVATE KEY----- diff --git a/crates/bitwarden-ssh/tests/rsa4096_key b/crates/bitwarden-ssh/tests/rsa4096_key new file mode 100644 index 00000000..3edf7065 --- /dev/null +++ b/crates/bitwarden-ssh/tests/rsa4096_key @@ -0,0 +1,49 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +lPX5us1SaJEAAAAAAQID +-----END OPENSSH PRIVATE KEY----- diff --git a/crates/bitwarden-wasm-internal/Cargo.toml b/crates/bitwarden-wasm-internal/Cargo.toml index 41639d10..9852effb 100644 --- a/crates/bitwarden-wasm-internal/Cargo.toml +++ b/crates/bitwarden-wasm-internal/Cargo.toml @@ -19,6 +19,7 @@ bitwarden-core = { workspace = true, features = ["wasm", "internal"] } bitwarden-crypto = { workspace = true, features = ["wasm"] } bitwarden-error = { version = "1.0.0", path = "../bitwarden-error" } bitwarden-vault = { workspace = true, features = ["wasm"] } +bitwarden-ssh = { workspace = true, features = ["wasm"] } console_error_panic_hook = "0.1.7" console_log = { version = "1.0.0", features = ["color"] } js-sys = "0.3.68" diff --git a/crates/bitwarden-wasm-internal/src/lib.rs b/crates/bitwarden-wasm-internal/src/lib.rs index 6f3516a9..fc61d4c2 100644 --- a/crates/bitwarden-wasm-internal/src/lib.rs +++ b/crates/bitwarden-wasm-internal/src/lib.rs @@ -1,6 +1,7 @@ mod client; mod crypto; mod custom_types; +mod ssh; mod vault; pub use client::BitwardenClient; diff --git a/crates/bitwarden-wasm-internal/src/ssh.rs b/crates/bitwarden-wasm-internal/src/ssh.rs new file mode 100644 index 00000000..e3ac77bf --- /dev/null +++ b/crates/bitwarden-wasm-internal/src/ssh.rs @@ -0,0 +1,8 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn generate_ssh_key( + key_algorithm: bitwarden_ssh::KeyAlgorithm, +) -> Result { + bitwarden_ssh::generate_sshkey(key_algorithm) +}