Skip to main content

seher/crypto/
linux.rs

1use crate::crypto::{CryptoError, Result};
2use aes::cipher::{BlockDecryptMut, KeyIvInit};
3
4type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
5
6const SALT: &[u8] = b"saltysalt";
7const IV: &[u8] = b"                "; // 16 spaces
8const KEY_LENGTH: usize = 16;
9const ITERATIONS: u32 = 1;
10
11pub fn decrypt(encrypted_value: &[u8]) -> Result<String> {
12    if encrypted_value.len() < 3 {
13        return Ok(String::new());
14    }
15
16    let version = &encrypted_value[..3];
17    match version {
18        b"v10" | b"v11" => {
19            let encrypted = &encrypted_value[3..];
20            let key = get_encryption_key()?;
21            decrypt_aes_cbc(&key, encrypted)
22        }
23        _ => String::from_utf8(encrypted_value.to_vec())
24            .map_err(|e| CryptoError::DecryptionFailed(e.to_string())),
25    }
26}
27
28fn get_encryption_key() -> Result<Vec<u8>> {
29    match get_key_from_secret_service() {
30        Ok(key) => Ok(key),
31        Err(_) => {
32            // Fallback to default password "peanuts"
33            let mut key = vec![0u8; KEY_LENGTH];
34            pbkdf2::pbkdf2_hmac::<sha1::Sha1>(b"peanuts", SALT, ITERATIONS, &mut key);
35            Ok(key)
36        }
37    }
38}
39
40fn get_key_from_secret_service() -> Result<Vec<u8>> {
41    use secret_service::blocking::SecretService;
42
43    let service = SecretService::connect(secret_service::EncryptionType::Dh)
44        .map_err(|e| CryptoError::SecretServiceError(format!("Failed to connect: {}", e)))?;
45
46    let collection = service
47        .get_default_collection()
48        .map_err(|e| CryptoError::SecretServiceError(format!("Failed to get collection: {}", e)))?;
49
50    let items = collection
51        .search_items(std::collections::HashMap::from([("application", "chrome")]))
52        .map_err(|e| CryptoError::SecretServiceError(format!("Failed to search items: {}", e)))?;
53
54    if let Some(item) = items.first() {
55        let password = item
56            .get_secret()
57            .map_err(|e| CryptoError::SecretServiceError(format!("Failed to get secret: {}", e)))?;
58
59        let mut key = vec![0u8; KEY_LENGTH];
60        pbkdf2::pbkdf2_hmac::<sha1::Sha1>(&password, SALT, ITERATIONS, &mut key);
61        return Ok(key);
62    }
63
64    Err(CryptoError::SecretServiceError(
65        "Chrome password not found".to_string(),
66    ))
67}
68
69fn decrypt_aes_cbc(key: &[u8], encrypted: &[u8]) -> Result<String> {
70    let cipher = Aes128CbcDec::new(key.into(), IV.into());
71
72    let mut buffer = encrypted.to_vec();
73    let decrypted = cipher
74        .decrypt_padded_mut::<aes::cipher::block_padding::Pkcs7>(&mut buffer)
75        .map_err(|e| {
76            CryptoError::DecryptionFailed(format!("AES-CBC decryption failed: {:?}", e))
77        })?;
78
79    String::from_utf8(decrypted.to_vec())
80        .map_err(|e| CryptoError::DecryptionFailed(format!("UTF-8 conversion failed: {}", e)))
81}