bitwarden_access_token_crypto/
key.rs1use std::fmt;
4
5use bitwarden_crypto::{
6 BitwardenLegacyKeyBytes, EncString, KeyDecryptable, KeySlotIds, KeyStoreContext,
7 SymmetricCryptoKey, derive_shareable_key,
8};
9use bitwarden_encoding::B64;
10use serde::Deserialize;
11use zeroize::Zeroizing;
12
13use crate::{AccessTokenError, AccessTokenSeed, purpose::KeyPurpose};
14
15pub(crate) const DERIVE_NAME: &str = "accesstoken";
17
18pub struct AccessTokenKey(SymmetricCryptoKey);
21
22impl fmt::Debug for AccessTokenKey {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 f.debug_tuple("AccessTokenKey")
25 .field(&"[REDACTED]")
26 .finish()
27 }
28}
29
30impl AccessTokenKey {
31 pub fn derive(seed: &AccessTokenSeed, purpose: KeyPurpose) -> Self {
33 Self(SymmetricCryptoKey::Aes256CbcHmacKey(derive_shareable_key(
34 Zeroizing::new(*seed.as_bytes()),
35 DERIVE_NAME,
36 Some(purpose.as_str()),
37 )))
38 }
39
40 pub fn open_payload<Ids: KeySlotIds>(
43 &self,
44 ctx: &mut KeyStoreContext<Ids>,
45 encrypted_payload: &str,
46 organization_key: Ids::Symmetric,
47 ) -> Result<(), AccessTokenError> {
48 let encrypted_payload: EncString = encrypted_payload
49 .parse()
50 .map_err(|_| AccessTokenError::InvalidPayload)?;
51
52 let decrypted: Vec<u8> = encrypted_payload
53 .decrypt_with_key(&self.0)
54 .map_err(|_| AccessTokenError::InvalidPayload)?;
55
56 #[derive(Deserialize)]
57 struct Payload {
58 #[serde(rename = "encryptionKey")]
59 encryption_key: B64,
60 }
61
62 let payload: Payload =
63 serde_json::from_slice(&decrypted).map_err(|_| AccessTokenError::InvalidPayload)?;
64
65 let key_bytes = BitwardenLegacyKeyBytes::from(&payload.encryption_key);
66 let key = SymmetricCryptoKey::try_from(&key_bytes)
67 .map_err(|_| AccessTokenError::InvalidOrgKey)?;
68
69 let local = ctx.add_local_symmetric_key(key);
70 ctx.persist_symmetric_key(local, organization_key)?;
71 Ok(())
72 }
73}
74
75#[cfg(test)]
76impl AccessTokenKey {
77 pub(crate) fn to_base64_for_tests(&self) -> String {
78 self.0.to_base64().to_string()
79 }
80}