fitgirl_decrypt/
crypto.rs

1use std::num::NonZero;
2
3use aes_gcm::aead::Aead;
4use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce};
5use base64::prelude::BASE64_STANDARD;
6use base64::Engine as _;
7
8use crate::{types::CompressionType, Error};
9use crate::{Attachment, Cipher, CipherInfo};
10
11/// Decrypt paste using given master_key
12pub fn decrypt_with_key(
13    master_key: impl AsRef<[u8]>,
14    cipher: impl AsRef<CipherInfo>,
15) -> crate::Result<Attachment> {
16    let CipherInfo { adata, ct } = cipher.as_ref();
17
18    let Cipher {
19        cipher_iv,
20        kdf_salt,
21        kdf_iterations,
22        compression_type,
23        ..
24    } = &adata.cipher;
25
26    let ct = BASE64_STANDARD.decode(ct)?;
27    let cipher_iv = BASE64_STANDARD.decode(cipher_iv)?;
28    let kdf_salt = BASE64_STANDARD.decode(kdf_salt)?;
29    let iterations = NonZero::new(*kdf_iterations).ok_or(Error::ZeroIterations)?;
30    let algorithm = ring::pbkdf2::PBKDF2_HMAC_SHA256;
31
32    let mut derived_key = [0u8; 32];
33    ring::pbkdf2::derive(
34        algorithm,
35        iterations,
36        &kdf_salt,
37        master_key.as_ref(),
38        &mut derived_key,
39    );
40
41    let adata_json = serde_json::to_string(&adata)?;
42
43    let data = decrypt_aes_256_gcm(&ct, &derived_key, cipher_iv, &adata_json, compression_type)?;
44    Ok(serde_json::from_slice(&data)?)
45}
46
47fn decrypt_aes_256_gcm(
48    ct: &[u8],
49    derived_key: &[u8; 32],
50    iv: Vec<u8>,
51    adata_json: &str,
52    compression_type: &CompressionType,
53) -> crate::Result<Vec<u8>> {
54    type Cipher = aes_gcm::AesGcm<aes_gcm::aes::Aes256, typenum::U16>;
55
56    let cipher = Cipher::new(Key::<Aes256Gcm>::from_slice(derived_key));
57    let payload = aes_gcm::aead::Payload {
58        msg: ct,
59        aad: adata_json.as_bytes(),
60    };
61    let data = cipher
62        .decrypt(Nonce::from_slice(&iv), payload)
63        .map_err(|_| Error::AesGcm)?;
64
65    let decompressed = match compression_type {
66        CompressionType::None => data,
67        CompressionType::Zlib => {
68            miniz_oxide::inflate::decompress_to_vec(&data).map_err(|_| Error::DecompressError)?
69        }
70    };
71
72    Ok(decompressed)
73}