1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
use crate::error::CryptError;
use pqcrypto_kyber::kyber1024;
use pqcrypto_kyber::kyber1024::*;
use pqcrypto_traits::kem::{PublicKey, SecretKey, SharedSecret, Ciphertext};
use crate::KeyControl::*;
use std::{
    path::{PathBuf},
};

/// Represents a cryptographic key, including its type and raw content.
#[derive(PartialEq, Debug, Clone)]
pub struct Key {
    /// The type of the key, as defined in `KeyTypes`.
    key_type: KeyTypes,
    /// The raw content of the key.
    content: Vec<u8>
}

/// Represents a cryptographic key with its type and content.
/// It provides functionalities to manipulate and store keys in various formats.
impl Key {
    /// Constructs a new `Key` with specified type and content, optimizing storage based on the key type.
    ///
    /// # Parameters
    /// - `key_type`: The type of the key (public, secret, ciphertext, shared secret).
    /// - `content`: The raw content of the key.
    ///
    /// # Returns
    /// A new instance of `Key`.
    pub fn new(key_type: KeyTypes, content: Vec<u8>) -> Self {
        let content = Self::optimize(&key_type, content);
        Key {
            key_type,
            content,
        }
    }

    /// Optimizes the storage of the key based on its type.
    ///
    /// # Parameters
    /// - `key_type`: The type of the key being optimized.
    /// - `content`: The raw key content.
    ///
    /// # Returns
    /// Optimized key content as a byte vector.
    fn optimize(key_type: &KeyTypes, content: Vec<u8>) -> Vec<u8> {
        let key: Vec<u8> = match key_type {
            KeyTypes::PublicKey => {
                let key: kyber1024::PublicKey = PublicKey::from_bytes(&content).unwrap();
                key.as_bytes().to_vec()
            },
            KeyTypes::SecretKey => {
                let key: kyber1024::SecretKey = SecretKey::from_bytes(&content).unwrap();
                key.as_bytes().to_vec()
            },
            KeyTypes::Ciphertext => {
                let key: kyber1024::Ciphertext = Ciphertext::from_bytes(&content).unwrap();
                key.as_bytes().to_vec()
            },
            KeyTypes::SharedSecret => {
                let key: kyber1024::SharedSecret = SharedSecret::from_bytes(&content).unwrap();
                key.as_bytes().to_vec()
            },
            _ => {
                content
            }
        };
        key
    }


    /// Factory methods for creating specific types of keys by building new Self elements.
    pub fn new_public_key(key: Vec<u8>) -> Self {
        Key {
            key_type: KeyTypes::PublicKey,
            content: key,
        }
    }
    pub fn new_secret_key(key: Vec<u8>) -> Self {
        Key {
            key_type: KeyTypes::SecretKey,
            content: key,
        }
    }
    pub fn new_ciphertext(key: Vec<u8>) -> Self {
        Key {
            key_type: KeyTypes::Ciphertext,
            content: key,
        }
    }
    pub fn new_shared_secret(key: Vec<u8>) -> Self {
        Key {
            key_type: KeyTypes::SharedSecret,
            content: key,
        }
    }

    /// Accessors for the key's properties.
    pub fn get(&self) -> Result<&Key, CryptError> {
        Ok(&self)
    }
    pub fn key_type(&self) -> Result<&KeyTypes, CryptError> {
        Ok(&self.key_type)
    }
    pub fn content(&self) -> Result<&[u8], CryptError> {
        Ok(&self.content)
    }

    /// Safely stores the key to a specified path.
    ///
    /// # Parameters
    /// - `base_path`: The base directory path where the key will be saved.
    ///
    /// # Returns
    /// An `Ok(())` on success or a `CryptError` on failure.
    pub fn save(&self, base_path: PathBuf) -> Result<(), CryptError> {
        let file_name = match self.key_type {
            KeyTypes::PublicKey => "public_key.pub",
            KeyTypes::SecretKey => "secret_key.sec",
            KeyTypes::Ciphertext => "ciphertext.ct",
            KeyTypes::SharedSecret => return Err(CryptError::UnsupportedOperation),
            _ => return Err(CryptError::InvalidKeyType),
        };

        let path = base_path.join(file_name);
        let file_metadata = FileMetadata::from(path, self.file_type_from_key_type(), FileState::Encrypted);
        
        file_metadata.save(&self.content)
    }

    fn file_type_from_key_type(&self) -> FileTypes {
        match self.key_type {
            KeyTypes::PublicKey => FileTypes::PublicKey,
            KeyTypes::SecretKey => FileTypes::SecretKey,
            KeyTypes::Ciphertext => FileTypes::Ciphertext,
            _ => FileTypes::Other,
        }
    }

    /// Encapsulates the key, generating a ciphertext and shared secret.
    ///
    /// # Returns
    /// A tuple containing the ciphertext and shared secret as `Key` instances, or a `CryptError`.
    pub fn encap(&self) -> Result<(Key,Key), CryptError> {
        match self.key_type {
            KeyTypes::PublicKey => {
                let pk = PublicKey::from_bytes(self.content()?).unwrap();
                let (ss, ct) = encapsulate(&pk);
                let ciphertext = Key::new_ciphertext(ct.as_bytes().to_vec());
                let shared_secret = Key::new_shared_secret(ss.as_bytes().to_vec());
                //Ok((ct.as_bytes().to_vec(), ss.as_bytes().to_vec()));
                Ok((ciphertext, shared_secret))
            }
            _ => Err(CryptError::EncapsulationError)
        }
    }

    /// Decapsulates the ciphertext using the secret key, retrieving the shared secret.
    ///
    /// # Parameters
    /// - `ciphertext`: The ciphertext `Key` to be decapsulated.
    ///
    /// # Returns
    /// The shared secret as a `Key`, or a `CryptError`.
    pub fn decap(&self, ciphertext: Key) -> Result<Key, CryptError> {
        match self.key_type {
            KeyTypes::SecretKey => {
                let ct = Ciphertext::from_bytes(ciphertext.content()?).unwrap();
                let sk = SecretKey::from_bytes(self.content()?).unwrap();
                let ss2 = decapsulate(&ct, &sk);
                let shared_secret = Key::new_shared_secret(ss2.as_bytes().to_vec());
                Ok(shared_secret)
            }
            _ => Err(CryptError::DecapsulationError)
        }
    }
}