nym_client_core/client/key_manager/
mod.rs

1// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::client::key_manager::persistence::KeyStore;
5use nym_crypto::{
6    asymmetric::{ed25519, x25519},
7    hkdf::{DerivationMaterial, InvalidLength},
8};
9use nym_gateway_requests::shared_key::SharedSymmetricKey;
10use nym_sphinx::acknowledgements::AckKey;
11use rand::{CryptoRng, RngCore};
12use std::sync::Arc;
13use zeroize::ZeroizeOnDrop;
14
15pub mod persistence;
16mod test;
17
18// Note: to support key rotation in the future, all keys will require adding an extra smart pointer,
19// most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think
20// AtomicCell includes a Mutex implicitly if the underlying type does not work atomically.
21// And I guess there will need to be some mechanism for a grace period when you can still
22// use the old key after new one was issued.
23
24// Remember that Arc<T> has Deref implementation for T
25#[derive(Clone)]
26pub struct ClientKeys {
27    /// identity key associated with the client instance.
28    identity_keypair: Arc<ed25519::KeyPair>,
29
30    /// encryption key associated with the client instance.
31    encryption_keypair: Arc<x25519::KeyPair>,
32
33    /// key used for producing and processing acknowledgement packets.
34    ack_key: Arc<AckKey>,
35}
36
37impl ClientKeys {
38    /// Creates new instance of a [`ClientKeys`]
39    pub fn generate_new<R>(rng: &mut R) -> Self
40    where
41        R: RngCore + CryptoRng,
42    {
43        ClientKeys {
44            identity_keypair: Arc::new(ed25519::KeyPair::new(rng)),
45            encryption_keypair: Arc::new(x25519::KeyPair::new(rng)),
46            ack_key: Arc::new(AckKey::new(rng)),
47        }
48    }
49
50    pub fn from_master_key<R>(
51        rng: &mut R,
52        derivation_material: &DerivationMaterial,
53    ) -> Result<Self, InvalidLength>
54    where
55        R: RngCore + CryptoRng,
56    {
57        let secret = derivation_material.derive_secret()?;
58        Ok(ClientKeys {
59            identity_keypair: Arc::new(ed25519::KeyPair::from_secret(
60                secret,
61                derivation_material.index(),
62            )),
63            encryption_keypair: Arc::new(x25519::KeyPair::new(rng)),
64            ack_key: Arc::new(AckKey::new(rng)),
65        })
66    }
67
68    pub fn from_keys(
69        id_keypair: ed25519::KeyPair,
70        enc_keypair: x25519::KeyPair,
71        ack_key: AckKey,
72    ) -> Self {
73        Self {
74            identity_keypair: Arc::new(id_keypair),
75            encryption_keypair: Arc::new(enc_keypair),
76            ack_key: Arc::new(ack_key),
77        }
78    }
79
80    pub async fn load_keys<S: KeyStore>(store: &S) -> Result<Self, S::StorageError> {
81        store.load_keys().await
82    }
83
84    pub async fn persist_keys<S: KeyStore>(&self, store: &S) -> Result<(), S::StorageError> {
85        store.store_keys(self).await
86    }
87
88    /// Gets an atomically reference counted pointer to [`ed25519::KeyPair`].
89    pub fn identity_keypair(&self) -> Arc<ed25519::KeyPair> {
90        Arc::clone(&self.identity_keypair)
91    }
92
93    /// Gets an atomically reference counted pointer to [`x25519::KeyPair`].
94    pub fn encryption_keypair(&self) -> Arc<x25519::KeyPair> {
95        Arc::clone(&self.encryption_keypair)
96    }
97    /// Gets an atomically reference counted pointer to [`AckKey`].
98    pub fn ack_key(&self) -> Arc<AckKey> {
99        Arc::clone(&self.ack_key)
100    }
101}
102
103fn _assert_keys_zeroize_on_drop() {
104    fn _assert_zeroize_on_drop<T: ZeroizeOnDrop>() {}
105
106    _assert_zeroize_on_drop::<ed25519::KeyPair>();
107    _assert_zeroize_on_drop::<x25519::KeyPair>();
108    _assert_zeroize_on_drop::<AckKey>();
109    _assert_zeroize_on_drop::<SharedSymmetricKey>();
110}