paseto_core/paserk/
pw_wrap.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::fmt;
4use core::marker::PhantomData;
5
6use crate::PasetoError;
7use crate::key::{HasKey, Key, SealingKey};
8use crate::version::Version;
9
10/// This PASETO implementation allows encrypting keys using a password
11pub trait PwWrapVersion: Version {
12    type Params: Default;
13
14    /// Wrap the key using a password
15    fn pw_wrap_key(
16        header: &'static str,
17        pass: &[u8],
18        params: &Self::Params,
19        key_data: Vec<u8>,
20    ) -> Result<Vec<u8>, PasetoError>;
21
22    /// Extract the params from the
23    fn get_params(key_data: &[u8]) -> Result<Self::Params, PasetoError>;
24
25    /// Unwrap the key using a password
26    fn pw_unwrap_key<'key>(
27        header: &'static str,
28        pass: &[u8],
29        key_data: &'key mut [u8],
30    ) -> Result<&'key [u8], PasetoError>;
31}
32
33/// An password encrypted [`Key`].
34///
35/// * Encrypted using [`Key::password_wrap`]
36/// * Decrypted using [`PasswordWrappedKey::unwrap`]
37pub struct PasswordWrappedKey<V: PwWrapVersion, K: SealingKey> {
38    key_data: Box<[u8]>,
39    _version: PhantomData<(V, K)>,
40}
41
42impl<V: PwWrapVersion + HasKey<K>, K: SealingKey> Key<V, K> {
43    /// Encrypt the key using the password.
44    pub fn password_wrap(self, pass: &[u8]) -> Result<PasswordWrappedKey<V, K>, PasetoError> {
45        self.password_wrap_with_params(pass, &V::Params::default())
46    }
47
48    /// Encrypt the key using the password, configured with the specified parameters.
49    pub fn password_wrap_with_params(
50        self,
51        pass: &[u8],
52        params: &V::Params,
53    ) -> Result<PasswordWrappedKey<V, K>, PasetoError> {
54        V::pw_wrap_key(
55            K::PW_WRAP_HEADER,
56            pass,
57            params,
58            V::encode(&self.0).into_vec(),
59        )
60        .map(|key_data| PasswordWrappedKey {
61            key_data: key_data.into_boxed_slice(),
62            _version: PhantomData,
63        })
64    }
65}
66
67impl<V: PwWrapVersion, K: SealingKey> PasswordWrappedKey<V, K> {
68    /// Extract the parameters the key was encrypted with.
69    pub fn params(&self) -> Result<V::Params, PasetoError> {
70        V::get_params(&self.key_data)
71    }
72}
73
74impl<V: PwWrapVersion + HasKey<K>, K: SealingKey> PasswordWrappedKey<V, K> {
75    /// Decrypt the key using the password.
76    pub fn unwrap(mut self, pass: &[u8]) -> Result<Key<V, K>, PasetoError> {
77        V::pw_unwrap_key(K::PW_WRAP_HEADER, pass, &mut self.key_data)
78            .and_then(V::decode)
79            .map(Key)
80    }
81}
82
83impl<V: PwWrapVersion, K: SealingKey> fmt::Display for PasswordWrappedKey<V, K> {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        f.write_str(V::PASERK_HEADER)?;
86        f.write_str(K::PW_WRAP_HEADER)?;
87        crate::base64::write_to_fmt(&self.key_data, f)
88    }
89}
90
91impl<V: PwWrapVersion, K: SealingKey> core::str::FromStr for PasswordWrappedKey<V, K> {
92    type Err = PasetoError;
93
94    fn from_str(s: &str) -> Result<Self, Self::Err> {
95        let s = s
96            .strip_prefix(V::PASERK_HEADER)
97            .ok_or(PasetoError::InvalidKey)?;
98        let s = s
99            .strip_prefix(K::PW_WRAP_HEADER)
100            .ok_or(PasetoError::InvalidKey)?;
101
102        Ok(PasswordWrappedKey {
103            key_data: crate::base64::decode_vec(s)?.into_boxed_slice(),
104            _version: PhantomData,
105        })
106    }
107}
108
109serde_str!(
110    impl<V, K> PasswordWrappedKey<V, K>
111    where
112        V: PwWrapVersion,
113        K: SealingKey,
114    {
115        fn expecting() {
116            format_args!(
117                "a {}{} PASERK password wrapped key",
118                V::PASERK_HEADER,
119                K::PW_WRAP_HEADER
120            )
121        }
122    }
123);