fitgirl_decrypt/
types.rs

1use serde::{ser::SerializeTuple as _, Deserialize, Serialize, Serializer};
2
3/// CipherInfo is directly from the JSON returned from privatebin.
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct CipherInfo {
6    /// additional data about a paste
7    pub adata: AData,
8    /// cipher text, in base64
9    pub ct: String,
10}
11
12/// Additional data about a paste.
13#[derive(Debug, Clone, Deserialize)]
14pub struct AData {
15    /// everything related to decrypt cipher text
16    pub cipher: Cipher,
17    /// post formatter, can be "plaintext" or "markdown"
18    pub formatter: String,
19    /// accepts comments
20    pub open_discussion: u8,
21    /// will burn after one access
22    pub burn_after_reading: u8,
23}
24
25impl AsRef<CipherInfo> for CipherInfo {
26    fn as_ref(&self) -> &CipherInfo {
27        &self
28    }
29}
30
31/// [`Cipher`] contains AES-GCM related fields,
32/// which is an array in original JSON.
33///
34/// [`serde`] could deserialize this from an 8 length list.
35#[derive(Deserialize, Debug, Clone)]
36pub struct Cipher {
37    /// IV (nonce), in base64
38    pub cipher_iv: String,
39    /// pbkdf2 salt, in base64
40    pub kdf_salt: String,
41    /// pbkdf2 iterations
42    pub kdf_iterations: u32,
43    /// pbkdf2 generated key size, always 256 (bits)
44    pub kdf_keysize: u32,
45    /// tag size in GCM, always 128 (bits)
46    pub cipher_tag_size: u32,
47    /// encryption algorithm, always `"aes"`
48    pub cipher_algo: String,
49    /// aes encryption mode, always `"gcm"`
50    pub cipher_mode: String,
51    /// compression type of encrypted data. either "zlib" or "none"
52    pub compression_type: CompressionType,
53}
54
55/// Compression type
56#[derive(Default, Deserialize, Debug, Serialize, Clone)]
57#[serde(rename_all = "lowercase")]
58pub enum CompressionType {
59    /// no compression
60    None,
61    /// zlib (flate) compression
62    #[default]
63    Zlib,
64}
65
66impl Serialize for AData {
67    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68    where
69        S: Serializer,
70    {
71        let mut s = serializer.serialize_tuple(4)?;
72        s.serialize_element(&self.cipher)?;
73        s.serialize_element(&self.formatter)?;
74        s.serialize_element(&self.open_discussion)?;
75        s.serialize_element(&self.burn_after_reading)?;
76        s.end()
77    }
78}
79
80impl Serialize for Cipher {
81    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: Serializer,
84    {
85        let mut s = serializer.serialize_tuple(8)?;
86        s.serialize_element(&self.cipher_iv)?;
87        s.serialize_element(&self.kdf_salt)?;
88        s.serialize_element(&self.kdf_iterations)?;
89        s.serialize_element(&self.kdf_keysize)?;
90        s.serialize_element(&self.cipher_tag_size)?;
91        s.serialize_element(&self.cipher_algo)?;
92        s.serialize_element(&self.cipher_mode)?;
93        s.serialize_element(&self.compression_type)?;
94        s.end()
95    }
96}
97
98/// `Attachment` is from the decrypted paste JSON.
99#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
100pub struct Attachment {
101    /// data URI startswith `data:application/x-bittorrent;base64,`
102    pub attachment: String,
103    /// suggested filename of the attachment
104    pub attachment_name: String,
105}