summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2024-10-15 11:58:00 +0200
committerLinus Färnstrand <linus@mullvad.net>2024-10-15 11:58:00 +0200
commitd89d32947ade649eac07ab55c29d41b3aaa0ff2a (patch)
tree8ff3f4da38fd0489d5cf6a4b153ce47b753ee2db
parenta21b70239ce7501add3c9d4e1c7730b84ef42dd1 (diff)
parent6e64e75eb982b2a8e59800334ed95e95fcb91573 (diff)
downloadmullvadvpn-d89d32947ade649eac07ab55c29d41b3aaa0ff2a.tar.xz
mullvadvpn-d89d32947ade649eac07ab55c29d41b3aaa0ff2a.zip
Merge branch 'upgrade-kyber-ml-kem-for-quantum-resistance-des-1267'
-rw-r--r--.github/workflows/cargo-audit.yml4
-rw-r--r--.github/workflows/rust-unused-dependencies.yml2
-rw-r--r--CHANGELOG.md3
-rw-r--r--Cargo.lock44
-rw-r--r--android/CHANGELOG.md2
-rw-r--r--deny.toml2
-rw-r--r--ios/CHANGELOG.md3
-rw-r--r--osv-scanner.toml10
-rw-r--r--talpid-tunnel-config-client/Cargo.toml3
-rw-r--r--talpid-tunnel-config-client/examples/tuncfg-server.rs51
-rw-r--r--talpid-tunnel-config-client/proto/ephemeralpeer.proto8
-rw-r--r--talpid-tunnel-config-client/src/kyber.rs31
-rw-r--r--talpid-tunnel-config-client/src/lib.rs23
-rw-r--r--talpid-tunnel-config-client/src/ml_kem.rs65
-rw-r--r--talpid-wireguard/src/config.rs6
15 files changed, 163 insertions, 94 deletions
diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml
index e3f44a3b96..a9f8c039c7 100644
--- a/.github/workflows/cargo-audit.yml
+++ b/.github/workflows/cargo-audit.yml
@@ -28,8 +28,6 @@ jobs:
denyWarnings: true
# Ignored audit issues. This list should be kept short, and effort should be
# put into removing items from the list.
- # RUSTSEC-2023-0079 - KyberSlash in `pqc_kyber`.
- ignore: RUSTSEC-2023-0079
- uses: actions-rust-lang/audit@v1.1.11
name: Audit testrunner Rust Dependencies
@@ -38,5 +36,3 @@ jobs:
denyWarnings: true
# Ignored audit issues. This list should be kept short, and effort should be
# put into removing items from the list.
- # RUSTSEC-2023-0079 - KyberSlash in `pqc_kyber`.
- ignore: RUSTSEC-2023-0079
diff --git a/.github/workflows/rust-unused-dependencies.yml b/.github/workflows/rust-unused-dependencies.yml
index cfdd75e751..3c243b98d0 100644
--- a/.github/workflows/rust-unused-dependencies.yml
+++ b/.github/workflows/rust-unused-dependencies.yml
@@ -10,7 +10,7 @@ on:
workflow_dispatch:
env:
# Pinning nightly just to avoid random breakage. It's fine to bump this at any time
- RUST_NIGHTLY_TOOLCHAIN: nightly-2024-06-06
+ RUST_NIGHTLY_TOOLCHAIN: nightly-2024-10-02
permissions: {}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 795f61da7d..4a08634efd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,9 @@ Line wrap the file at 100 chars. Th
- Add experimental support for Windows ARM64.
### Changed
+- Replace the draft key encapsulation mechanism Kyber (round 3) with the standardized
+ ML-KEM (FIPS 203) dito in the handshake for Quantum-resistant tunnels.
+
#### Windows
- Enable quantum-resistant tunnels by default (when set to `auto`).
diff --git a/Cargo.lock b/Cargo.lock
index 2f378ada80..3a3bd52289 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1537,6 +1537,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
+name = "hybrid-array"
+version = "0.2.0-rc.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5a41e5b0754cae5aaf7915f1df1147ba8d316fc6e019cfcc00fbaba96d5e030"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
name = "hyper"
version = "0.14.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2026,6 +2035,16 @@ dependencies = [
]
[[package]]
+name = "kem"
+version = "0.3.0-pre.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b8645470337db67b01a7f966decf7d0bafedbae74147d33e641c67a91df239f"
+dependencies = [
+ "rand_core 0.6.4",
+ "zeroize",
+]
+
+[[package]]
name = "kqueue"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2294,6 +2313,19 @@ dependencies = [
]
[[package]]
+name = "ml-kem"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97befee0c869cb56f3118f49d0f9bb68c9e3f380dec23c1100aedc4ec3ba239a"
+dependencies = [
+ "hybrid-array",
+ "kem",
+ "rand_core 0.6.4",
+ "sha3",
+ "zeroize",
+]
+
+[[package]]
name = "mnl"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3189,16 +3221,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
-name = "pqc_kyber"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b79004a05337e54e8ffc0ec7470e40fa26eca6fe182968ec2b803247f2283c"
-dependencies = [
- "rand_core 0.6.4",
- "zeroize",
-]
-
-[[package]]
name = "prettyplease"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4286,8 +4308,8 @@ dependencies = [
"hyper-util",
"libc",
"log",
+ "ml-kem",
"oslog",
- "pqc_kyber",
"prost 0.13.3",
"rand 0.8.5",
"talpid-types",
diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md
index a51a1deacf..39bc7a5124 100644
--- a/android/CHANGELOG.md
+++ b/android/CHANGELOG.md
@@ -34,6 +34,8 @@ Line wrap the file at 100 chars. Th
### Changed
- Update colors in the app to be more in line with material design.
+- Replace the draft key encapsulation mechanism Kyber (round 3) with the standardized
+ ML-KEM (FIPS 203) dito in the handshake for Quantum-resistant tunnels.
### Fixed
- Fix VPN service being recreated multiple times when toggling certain options.
diff --git a/deny.toml b/deny.toml
index 00a1076b78..c310d84330 100644
--- a/deny.toml
+++ b/deny.toml
@@ -26,8 +26,6 @@ yanked = "deny"
ignore = [
# Ignored audit issues. This list should be kept short, and effort should be
# put into removing items from the list.
- # RUSTSEC-2023-0079 - KyberSlash in `pqc_kyber`.
- "RUSTSEC-2023-0079",
]
diff --git a/ios/CHANGELOG.md b/ios/CHANGELOG.md
index 0e9eef9860..68b62affef 100644
--- a/ios/CHANGELOG.md
+++ b/ios/CHANGELOG.md
@@ -22,6 +22,9 @@ Line wrap the file at 100 chars. Th
* **Security**: in case of vulnerabilities.
## Unreleased
+### Changed
+- Replace the draft key encapsulation mechanism Kyber (round 3) with the standardized
+ ML-KEM (FIPS 203) dito in the handshake for Quantum-resistant tunnels.
## [2024.8 - 2024-10-14]
### Added
diff --git a/osv-scanner.toml b/osv-scanner.toml
index 0349695942..1837415f42 100644
--- a/osv-scanner.toml
+++ b/osv-scanner.toml
@@ -40,13 +40,3 @@
# `renderer-helper` currently depend on this version of libbaz, preventing us from upgrading to a fixed version.
# """
# ```
-
-# KyberSlash timing attack against Kyber PQ KEM
-[[IgnoredVulns]]
-id = "RUSTSEC-2023-0079"
-ignoreUntil = 2024-12-05 # Ignored for six months at a time. This class of timing based attacks are not exploitable in our protocol design
-reason = """
-KyberSlash is not exploitable in our usage of it:
-https://mullvad.net/en/blog/mullvads-usage-of-kyber-is-not-affected-by-kyberslash
-And no patched version is available.
-"""
diff --git a/talpid-tunnel-config-client/Cargo.toml b/talpid-tunnel-config-client/Cargo.toml
index 54966873ce..5cf6e4b522 100644
--- a/talpid-tunnel-config-client/Cargo.toml
+++ b/talpid-tunnel-config-client/Cargo.toml
@@ -24,7 +24,8 @@ classic-mceliece-rust = { version = "2.0.0", features = [
"mceliece460896f",
"zeroize",
] }
-pqc_kyber = { version = "0.4.0", features = ["std", "kyber1024", "zeroize"] }
+
+ml-kem = { version = "0.2.1", features = ["zeroize"] }
zeroize = "1.5.7"
[target.'cfg(unix)'.dependencies]
diff --git a/talpid-tunnel-config-client/examples/tuncfg-server.rs b/talpid-tunnel-config-client/examples/tuncfg-server.rs
index 306a425ff4..4ba996431c 100644
--- a/talpid-tunnel-config-client/examples/tuncfg-server.rs
+++ b/talpid-tunnel-config-client/examples/tuncfg-server.rs
@@ -5,11 +5,11 @@
mod proto {
tonic::include_proto!("ephemeralpeer");
}
-use classic_mceliece_rust::{PublicKey, CRYPTO_PUBLICKEYBYTES};
use proto::{
ephemeral_peer_server::{EphemeralPeer, EphemeralPeerServer},
EphemeralPeerRequestV1, EphemeralPeerResponseV1, PostQuantumResponseV1,
};
+use rand::{CryptoRng, RngCore};
use talpid_types::net::wireguard::PresharedKey;
use tonic::{transport::Server, Request, Response, Status};
@@ -44,20 +44,9 @@ impl EphemeralPeer for EphemeralPeerImpl {
println!("\tKEM algorithm: {}", kem_pubkey.algorithm_name);
let (ciphertext, shared_secret) = match kem_pubkey.algorithm_name.as_str() {
"Classic-McEliece-460896f-round3" => {
- let key_data: [u8; CRYPTO_PUBLICKEYBYTES] =
- kem_pubkey.key_data.as_slice().try_into().unwrap();
- let public_key = PublicKey::from(&key_data);
- let (ciphertext, shared_secret) =
- classic_mceliece_rust::encapsulate_boxed(&public_key, &mut rng);
- (ciphertext.as_array().to_vec(), *shared_secret.as_array())
- }
- // Kyber round3
- "Kyber1024" => {
- let public_key = kem_pubkey.key_data.as_slice();
- let (ciphertext, shared_secret) =
- pqc_kyber::encapsulate(public_key, &mut rng).unwrap();
- (ciphertext.to_vec(), shared_secret)
+ encapsulate_classic_mceliece(kem_pubkey.key_data.as_slice(), &mut rng)
}
+ "ML-KEM-1024" => encapsulate_ml_kem(kem_pubkey.key_data.as_slice(), &mut rng),
name => panic!("Unsupported KEM algorithm: {name}"),
};
@@ -82,6 +71,40 @@ impl EphemeralPeer for EphemeralPeerImpl {
}
}
+/// Generate a random shared secret and encapsulate it with the given
+/// public key/encapsulation key. Returns the ciphertext to return
+/// to the owner of the public key, along with the shared secret.
+fn encapsulate_classic_mceliece<R: RngCore + CryptoRng>(
+ public_key: &[u8],
+ rng: &mut R,
+) -> (Vec<u8>, [u8; 32]) {
+ use classic_mceliece_rust::{PublicKey, CRYPTO_PUBLICKEYBYTES};
+
+ let public_key_array = <[u8; CRYPTO_PUBLICKEYBYTES]>::try_from(public_key).unwrap();
+ let public_key = PublicKey::from(&public_key_array);
+ let (ciphertext, shared_secret) = classic_mceliece_rust::encapsulate_boxed(&public_key, rng);
+ (ciphertext.as_array().to_vec(), *shared_secret.as_array())
+}
+
+/// Generate a random shared secret and encapsulate it with the given
+/// public key/encapsulation key. Returns the ciphertext to return
+/// to the owner of the public key, along with the shared secret.
+fn encapsulate_ml_kem<R: RngCore + CryptoRng>(
+ public_key: &[u8],
+ rng: &mut R,
+) -> (Vec<u8>, [u8; 32]) {
+ use ml_kem::{kem::Encapsulate, Encoded, EncodedSizeUser, KemCore, MlKem1024};
+
+ type EncapsulationKey = <MlKem1024 as KemCore>::EncapsulationKey;
+
+ let encapsulation_key_array = <Encoded<EncapsulationKey>>::try_from(public_key).unwrap();
+ let encapsulation_key = EncapsulationKey::from_bytes(&encapsulation_key_array);
+
+ let (ciphertext, shared_secret) = encapsulation_key.encapsulate(rng).unwrap();
+
+ (ciphertext.to_vec(), shared_secret.into())
+}
+
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "127.0.0.1:1337".parse()?;
diff --git a/talpid-tunnel-config-client/proto/ephemeralpeer.proto b/talpid-tunnel-config-client/proto/ephemeralpeer.proto
index d247e8bcb3..7c78425b34 100644
--- a/talpid-tunnel-config-client/proto/ephemeralpeer.proto
+++ b/talpid-tunnel-config-client/proto/ephemeralpeer.proto
@@ -43,10 +43,12 @@ message EphemeralPeerRequestV1 {
DaitaRequestV1 daita = 4;
}
-// The v1 request supports exactly two algorithms.
-// The algorithms can appear soletary or in mixed order:
+// The v1 request supports these three algorithms.
+// The algorithms can appear soletary or mixed. Kyber1024 and ML-KEM-1024 cannot be used in the
+// same request as they are just different versions of the same kem.
// - "Classic-McEliece-460896f", but explicitly identified as "Classic-McEliece-460896f-round3"
// - "Kyber1024", this is round3 of the Kyber KEM
+// - "ML-KEM-1024". This is the standardized version of ML-KEM (FIPS 203) at the highest strength
message PostQuantumRequestV1 { repeated KemPubkeyV1 kem_pubkeys = 1; }
message KemPubkeyV1 {
@@ -70,8 +72,6 @@ message EphemeralPeerResponseV1 {
// Since the PSK provided to WireGuard is directly fed into a HKDF, it is not important that
// the entropy in the PSK is uniformly distributed. The actual keys used for encrypting the
// data channel will have uniformly distributed entropy anyway, thanks to the HKDF.
- // But even if that was not true, since both CME and Kyber run SHAKE256 as the last step
- // of their internal key derivation, the output they produce are uniformly distributed.
//
// If we later want to support another type of KEM that produce longer or shorter output,
// we can hash that secret into a 32 byte hash before proceeding to the XOR step.
diff --git a/talpid-tunnel-config-client/src/kyber.rs b/talpid-tunnel-config-client/src/kyber.rs
deleted file mode 100644
index 706f056041..0000000000
--- a/talpid-tunnel-config-client/src/kyber.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-//! This module implements the Kyber round3 KEM as specified in:
-//! https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf
-
-use pqc_kyber::KYBER_CIPHERTEXTBYTES;
-pub use pqc_kyber::{keypair, KyberError, SecretKey};
-
-/// Use the strongest variant of Kyber. It is fast and the keys are small, so there is no practical
-/// benefit of going with anything lower.
-pub const ALGORITHM_NAME: &str = "Kyber1024";
-
-// Always inline in order to try to avoid potential copies of `shared_secret` to multiple places on
-// the stack.
-#[inline(always)]
-pub fn decapsulate(
- secret_key: SecretKey,
- ciphertext_slice: &[u8],
-) -> Result<[u8; 32], super::Error> {
- // The `pqc_kyber` library takes a byte slice. But we convert it into an array
- // in order to catch the length mismatch error and report it better than `pqc_kyber` would.
- let ciphertext_array =
- <[u8; KYBER_CIPHERTEXTBYTES]>::try_from(ciphertext_slice).map_err(|_| {
- super::Error::InvalidCiphertextLength {
- algorithm: ALGORITHM_NAME,
- actual: ciphertext_slice.len(),
- expected: KYBER_CIPHERTEXTBYTES,
- }
- })?;
- let shared_secret = pqc_kyber::decapsulate(ciphertext_array.as_slice(), secret_key.as_slice())
- .map_err(super::Error::FailedDecapsulateKyber)?;
- Ok(shared_secret)
-}
diff --git a/talpid-tunnel-config-client/src/lib.rs b/talpid-tunnel-config-client/src/lib.rs
index 9820a71a73..ab47c13be7 100644
--- a/talpid-tunnel-config-client/src/lib.rs
+++ b/talpid-tunnel-config-client/src/lib.rs
@@ -13,7 +13,7 @@ use tower::service_fn;
use zeroize::Zeroize;
mod classic_mceliece;
-mod kyber;
+mod ml_kem;
#[cfg(not(target_os = "ios"))]
mod socket;
@@ -35,7 +35,6 @@ pub enum Error {
InvalidCiphertextCount {
actual: usize,
},
- FailedDecapsulateKyber(kyber::KyberError),
#[cfg(target_os = "ios")]
TcpConnectionExpired,
#[cfg(target_os = "ios")]
@@ -60,7 +59,6 @@ impl std::fmt::Display for Error {
InvalidCiphertextCount { actual } => {
write!(f, "Expected 2 ciphertext in the response, got {actual}")
}
- FailedDecapsulateKyber(_) => "Failed to decapsulate Kyber1024 ciphertext".fmt(f),
#[cfg(target_os = "ios")]
TcpConnectionExpired => "TCP connection is already shut down".fmt(f),
#[cfg(target_os = "ios")]
@@ -73,7 +71,6 @@ impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::GrpcConnectError(error) => Some(error),
- Self::FailedDecapsulateKyber(error) => Some(error),
_ => None,
}
}
@@ -110,7 +107,7 @@ pub async fn request_ephemeral_peer_with(
.await
.map_err(Error::GrpcError)?;
- let psk = if let Some((cme_kem_secret, kyber_secret)) = kem_secrets {
+ let psk = if let Some((cme_kem_secret, ml_kem_secret)) = kem_secrets {
let ciphertexts = response
.into_inner()
.post_quantum
@@ -118,7 +115,7 @@ pub async fn request_ephemeral_peer_with(
.ciphertexts;
// Unpack the ciphertexts into one per KEM without needing to access them by index.
- let [cme_ciphertext, kyber_ciphertext] = <&[Vec<u8>; 2]>::try_from(ciphertexts.as_slice())
+ let [cme_ciphertext, ml_kem_ciphertext] = <&[Vec<u8>; 2]>::try_from(ciphertexts.as_slice())
.map_err(|_| Error::InvalidCiphertextCount {
actual: ciphertexts.len(),
})?;
@@ -137,9 +134,9 @@ pub async fn request_ephemeral_peer_with(
// accidentally removed.
shared_secret.zeroize();
}
- // Decapsulate Kyber and mix into PSK
+ // Decapsulate ML-KEM and mix into PSK
{
- let mut shared_secret = kyber::decapsulate(kyber_secret, kyber_ciphertext)?;
+ let mut shared_secret = ml_kem_secret.decapsulate(ml_kem_ciphertext)?;
xor_assign(&mut psk_data, &shared_secret);
// The shared secret is sadly stored in an array on the stack. So we can't get any
@@ -182,11 +179,11 @@ async fn post_quantum_secrets(
enable_post_quantum: bool,
) -> (
Option<PostQuantumRequestV1>,
- Option<(classic_mceliece_rust::SecretKey<'static>, [u8; 3168])>,
+ Option<(classic_mceliece_rust::SecretKey<'static>, ml_kem::Keypair)>,
) {
if enable_post_quantum {
let (cme_kem_pubkey, cme_kem_secret) = classic_mceliece::generate_keys().await;
- let kyber_keypair = kyber::keypair(&mut rand::thread_rng());
+ let ml_kem_keypair = ml_kem::keypair();
(
Some(proto::PostQuantumRequestV1 {
@@ -196,12 +193,12 @@ async fn post_quantum_secrets(
key_data: cme_kem_pubkey.as_array().to_vec(),
},
proto::KemPubkeyV1 {
- algorithm_name: kyber::ALGORITHM_NAME.to_owned(),
- key_data: kyber_keypair.public.to_vec(),
+ algorithm_name: ml_kem::ALGORITHM_NAME.to_owned(),
+ key_data: ml_kem_keypair.encapsulation_key(),
},
],
}),
- Some((cme_kem_secret, kyber_keypair.secret)),
+ Some((cme_kem_secret, ml_kem_keypair)),
)
} else {
(None, None)
diff --git a/talpid-tunnel-config-client/src/ml_kem.rs b/talpid-tunnel-config-client/src/ml_kem.rs
new file mode 100644
index 0000000000..5cf101107c
--- /dev/null
+++ b/talpid-tunnel-config-client/src/ml_kem.rs
@@ -0,0 +1,65 @@
+use ml_kem::array::typenum::marker_traits::Unsigned;
+use ml_kem::kem::Decapsulate;
+use ml_kem::{Ciphertext, EncodedSizeUser, KemCore, MlKem1024, MlKem1024Params};
+
+/// Use the strongest variant of ML-KEM. It is fast and the keys are small, so there is no practical
+/// benefit of going with anything lower. The servers also only supports the strongest variant.
+pub const ALGORITHM_NAME: &str = "ML-KEM-1024";
+
+/// The number of bytes in an ML-KEM 1024 ciphertext.
+const CIPHERTEXT_LEN: usize = <MlKem1024 as KemCore>::CiphertextSize::USIZE;
+
+pub struct Keypair {
+ encapsulation_key: ml_kem::kem::EncapsulationKey<MlKem1024Params>,
+ decapsulation_key: ml_kem::kem::DecapsulationKey<MlKem1024Params>,
+}
+
+impl Keypair {
+ /// Returns the encapsulation key. This is sometimes called the public key.
+ ///
+ /// This is the key to send to the peer you want to negotiate a shared secret with.
+ pub fn encapsulation_key(&self) -> Vec<u8> {
+ self.encapsulation_key.as_bytes().as_slice().to_vec()
+ }
+
+ /// Decapsulates a shared secret that was encapsulated to our encapsulation key.
+ ///
+ // Always inline in order to try to avoid potential copies of `shared_secret` to multiple places
+ // on the stack. This is almost pointless as with optimization all bets are off regarding where
+ // the shared secrets will end up in memory. In the future we can try to do better, by
+ // cleaning the stack. But this is not trivial. Please see:
+ // https://github.com/RustCrypto/KEMs/issues/70
+ #[inline(always)]
+ pub fn decapsulate(&self, ciphertext_slice: &[u8]) -> Result<[u8; 32], super::Error> {
+ // Convert the ciphertext byte slice into the appropriate Array<u8, ...> type.
+ // This involves validating the length of the ciphertext.
+ let ciphertext_array =
+ <Ciphertext<MlKem1024>>::try_from(ciphertext_slice).map_err(|_| {
+ super::Error::InvalidCiphertextLength {
+ algorithm: ALGORITHM_NAME,
+ actual: ciphertext_slice.len(),
+ expected: CIPHERTEXT_LEN,
+ }
+ })?;
+
+ // Decapsulate the shared secret. This is an infallible operation but
+ // must due to the signature of the trait it is implemented via return a
+ // Result that we must unwrap... For now. Please see:
+ // https://github.com/RustCrypto/KEMs/pull/59
+ let shared_secret = self
+ .decapsulation_key
+ .decapsulate(&ciphertext_array)
+ .unwrap();
+ Ok(shared_secret.0)
+ }
+}
+
+/// Generates and returns an ML-KEM keypair.
+pub fn keypair() -> Keypair {
+ let (decapsulation_key, encapsulation_key) =
+ ml_kem::MlKem1024::generate(&mut rand::thread_rng());
+ Keypair {
+ encapsulation_key,
+ decapsulation_key,
+ }
+}
diff --git a/talpid-wireguard/src/config.rs b/talpid-wireguard/src/config.rs
index c599d34483..5326427d13 100644
--- a/talpid-wireguard/src/config.rs
+++ b/talpid-wireguard/src/config.rs
@@ -124,7 +124,7 @@ impl Config {
// the order of insertion matters, public key entry denotes a new peer entry
let mut wg_conf = WgConfigBuffer::new();
wg_conf
- .add("private_key", self.tunnel.private_key.to_bytes().as_ref())
+ .add::<&[u8]>("private_key", self.tunnel.private_key.to_bytes().as_ref())
.add("listen_port", "0");
#[cfg(target_os = "linux")]
@@ -136,11 +136,11 @@ impl Config {
for peer in self.peers() {
wg_conf
- .add("public_key", peer.public_key.as_bytes().as_ref())
+ .add::<&[u8]>("public_key", peer.public_key.as_bytes().as_ref())
.add("endpoint", peer.endpoint.to_string().as_str())
.add("replace_allowed_ips", "true");
if let Some(ref psk) = peer.psk {
- wg_conf.add("preshared_key", psk.as_bytes().as_ref());
+ wg_conf.add::<&[u8]>("preshared_key", psk.as_bytes().as_ref());
}
for addr in &peer.allowed_ips {
wg_conf.add("allowed_ip", addr.to_string().as_str());