]>
Commit | Line | Data |
---|---|---|
9a045790 DM |
1 | use std::io::Write; |
2 | use std::path::Path; | |
37e60ddc | 3 | |
86fb3877 WB |
4 | use anyhow::{bail, format_err, Context, Error}; |
5 | use serde::{Deserialize, Serialize}; | |
6 | ||
25877d05 | 7 | use proxmox_sys::fs::{file_get_contents, replace_file, CreateOptions}; |
6ef1b649 | 8 | use proxmox_lang::try_block; |
e18a6c9e | 9 | |
bbdda58b | 10 | use pbs_api_types::{Kdf, KeyInfo, Fingerprint}; |
86fb3877 | 11 | |
bbdda58b | 12 | use pbs_tools::crypt_config::CryptConfig; |
86fb3877 | 13 | |
8abe51b7 | 14 | /// Key derivation function configuration |
feb1645f | 15 | #[derive(Deserialize, Serialize, Clone, Debug)] |
826f309b DM |
16 | pub enum KeyDerivationConfig { |
17 | Scrypt { | |
18 | n: u64, | |
19 | r: u64, | |
20 | p: u64, | |
25877d05 | 21 | #[serde(with = "proxmox_serde::bytes_as_base64")] |
826f309b DM |
22 | salt: Vec<u8>, |
23 | }, | |
24 | PBKDF2 { | |
25 | iter: usize, | |
25877d05 | 26 | #[serde(with = "proxmox_serde::bytes_as_base64")] |
826f309b DM |
27 | salt: Vec<u8>, |
28 | }, | |
29 | } | |
30 | ||
31 | impl KeyDerivationConfig { | |
32 | ||
33 | /// Derive a key from provided passphrase | |
34 | pub fn derive_key(&self, passphrase: &[u8]) -> Result<[u8; 32], Error> { | |
35 | ||
36 | let mut key = [0u8; 32]; | |
37 | ||
38 | match self { | |
39 | KeyDerivationConfig::Scrypt { n, r, p, salt } => { | |
40 | // estimated scrypt memory usage is 128*r*n*p | |
41 | openssl::pkcs5::scrypt( | |
42 | passphrase, | |
9a37bd6c | 43 | salt, |
826f309b DM |
44 | *n, *r, *p, |
45 | 1025*1024*1024, | |
46 | &mut key, | |
47 | )?; | |
48 | ||
49 | Ok(key) | |
50 | } | |
51 | KeyDerivationConfig::PBKDF2 { iter, salt } => { | |
52 | ||
53 | openssl::pkcs5::pbkdf2_hmac( | |
54 | passphrase, | |
9a37bd6c | 55 | salt, |
826f309b DM |
56 | *iter, |
57 | openssl::hash::MessageDigest::sha256(), | |
58 | &mut key, | |
59 | )?; | |
60 | ||
61 | Ok(key) | |
62 | } | |
63 | } | |
64 | } | |
65 | } | |
66 | ||
8abe51b7 DM |
67 | /// Encryption Key Configuration |
68 | /// | |
69 | /// We use this struct to store secret keys. When used with a key | |
572e6594 | 70 | /// derivation function, the key data is encrypted (AES-GCM), and you |
8abe51b7 | 71 | /// need the password to restore the plain key. |
feb1645f | 72 | #[derive(Deserialize, Serialize, Clone, Debug)] |
826f309b | 73 | pub struct KeyConfig { |
181f097a | 74 | pub kdf: Option<KeyDerivationConfig>, |
25877d05 | 75 | #[serde(with = "proxmox_serde::epoch_as_rfc3339")] |
6a7be83e | 76 | pub created: i64, |
25877d05 | 77 | #[serde(with = "proxmox_serde::epoch_as_rfc3339")] |
6a7be83e | 78 | pub modified: i64, |
25877d05 | 79 | #[serde(with = "proxmox_serde::bytes_as_base64")] |
181f097a | 80 | pub data: Vec<u8>, |
37e60ddc FG |
81 | #[serde(skip_serializing_if = "Option::is_none")] |
82 | #[serde(default)] | |
83 | pub fingerprint: Option<Fingerprint>, | |
82a103c8 DM |
84 | /// Password hint |
85 | #[serde(skip_serializing_if = "Option::is_none")] | |
86 | pub hint: Option<String>, | |
87 | } | |
826f309b | 88 | |
69b8bc3b DM |
89 | impl From<&KeyConfig> for KeyInfo { |
90 | fn from(key_config: &KeyConfig) -> Self { | |
91 | Self { | |
92 | path: None, | |
93 | kdf: match key_config.kdf { | |
94 | Some(KeyDerivationConfig::PBKDF2 { .. }) => Kdf::PBKDF2, | |
95 | Some(KeyDerivationConfig::Scrypt { .. }) => Kdf::Scrypt, | |
96 | None => Kdf::None, | |
97 | }, | |
98 | created: key_config.created, | |
99 | modified: key_config.modified, | |
100 | fingerprint: key_config | |
101 | .fingerprint | |
102 | .as_ref() | |
ca6e66aa | 103 | .map(|fp| fp.signature()), |
69b8bc3b DM |
104 | hint: key_config.hint.clone(), |
105 | } | |
106 | } | |
107 | } | |
108 | ||
9a045790 | 109 | impl KeyConfig { |
181f097a | 110 | |
8abe51b7 | 111 | /// Creates a new key using random data, protected by passphrase. |
9a045790 DM |
112 | pub fn new(passphrase: &[u8], kdf: Kdf) -> Result<([u8;32], Self), Error> { |
113 | let mut key = [0u8; 32]; | |
25877d05 | 114 | proxmox_sys::linux::fill_with_random_data(&mut key)?; |
9a045790 DM |
115 | let key_config = Self::with_key(&key, passphrase, kdf)?; |
116 | Ok((key, key_config)) | |
117 | } | |
181f097a | 118 | |
8abe51b7 | 119 | /// Creates a new, unencrypted key. |
1c86893d DM |
120 | pub fn without_password(raw_key: [u8; 32]) -> Result<Self, Error> { |
121 | // always compute fingerprint | |
122 | let crypt_config = CryptConfig::new(raw_key.clone())?; | |
bbdda58b | 123 | let fingerprint = Some(Fingerprint::new(crypt_config.fingerprint())); |
1c86893d | 124 | |
6ef1b649 | 125 | let created = proxmox_time::epoch_i64(); |
1c86893d | 126 | Ok(Self { |
9a045790 DM |
127 | kdf: None, |
128 | created, | |
129 | modified: created, | |
130 | data: raw_key.to_vec(), | |
1c86893d | 131 | fingerprint, |
9a045790 | 132 | hint: None, |
1c86893d | 133 | }) |
9a045790 | 134 | } |
181f097a | 135 | |
8abe51b7 | 136 | /// Creates a new instance, protect raw_key with passphrase. |
9a045790 | 137 | pub fn with_key( |
1c86893d | 138 | raw_key: &[u8; 32], |
9a045790 DM |
139 | passphrase: &[u8], |
140 | kdf: Kdf, | |
141 | ) -> Result<Self, Error> { | |
181f097a | 142 | |
9a045790 DM |
143 | if raw_key.len() != 32 { |
144 | bail!("got strange key length ({} != 32)", raw_key.len()) | |
181f097a DM |
145 | } |
146 | ||
25877d05 | 147 | let salt = proxmox_sys::linux::random_data(32)?; |
9a045790 DM |
148 | |
149 | let kdf = match kdf { | |
150 | Kdf::Scrypt => KeyDerivationConfig::Scrypt { | |
151 | n: 65536, | |
152 | r: 8, | |
153 | p: 1, | |
154 | salt, | |
155 | }, | |
156 | Kdf::PBKDF2 => KeyDerivationConfig::PBKDF2 { | |
157 | iter: 65535, | |
158 | salt, | |
159 | }, | |
160 | Kdf::None => { | |
161 | bail!("No key derivation function specified"); | |
162 | } | |
163 | }; | |
181f097a | 164 | |
9a045790 | 165 | let derived_key = kdf.derive_key(passphrase)?; |
826f309b | 166 | |
9a045790 | 167 | let cipher = openssl::symm::Cipher::aes_256_gcm(); |
826f309b | 168 | |
25877d05 | 169 | let iv = proxmox_sys::linux::random_data(16)?; |
9a045790 | 170 | let mut tag = [0u8; 16]; |
826f309b | 171 | |
9a045790 DM |
172 | let encrypted_key = openssl::symm::encrypt_aead( |
173 | cipher, | |
174 | &derived_key, | |
175 | Some(&iv), | |
176 | b"", | |
1c86893d | 177 | raw_key, |
9a045790 DM |
178 | &mut tag, |
179 | )?; | |
180 | ||
181 | let mut enc_data = vec![]; | |
182 | enc_data.extend_from_slice(&iv); | |
183 | enc_data.extend_from_slice(&tag); | |
184 | enc_data.extend_from_slice(&encrypted_key); | |
185 | ||
6ef1b649 | 186 | let created = proxmox_time::epoch_i64(); |
9a045790 | 187 | |
1c86893d DM |
188 | // always compute fingerprint |
189 | let crypt_config = CryptConfig::new(raw_key.clone())?; | |
bbdda58b | 190 | let fingerprint = Some(Fingerprint::new(crypt_config.fingerprint())); |
1c86893d | 191 | |
9a045790 DM |
192 | Ok(Self { |
193 | kdf: Some(kdf), | |
194 | created, | |
195 | modified: created, | |
196 | data: enc_data, | |
1c86893d | 197 | fingerprint, |
9a045790 DM |
198 | hint: None, |
199 | }) | |
200 | } | |
82a103c8 | 201 | |
9a045790 DM |
202 | /// Loads a KeyConfig from path |
203 | pub fn load<P: AsRef<Path>>(path: P) -> Result<KeyConfig, Error> { | |
204 | let keydata = file_get_contents(path)?; | |
205 | let key_config: KeyConfig = serde_json::from_reader(&keydata[..])?; | |
206 | Ok(key_config) | |
207 | } | |
826f309b | 208 | |
8abe51b7 | 209 | /// Decrypt key to get raw key data. |
9a045790 DM |
210 | pub fn decrypt( |
211 | &self, | |
212 | passphrase: &dyn Fn() -> Result<Vec<u8>, Error>, | |
213 | ) -> Result<([u8;32], i64, Fingerprint), Error> { | |
826f309b | 214 | |
9a045790 | 215 | let raw_data = &self.data; |
826f309b | 216 | |
9a045790 | 217 | let key = if let Some(ref kdf) = self.kdf { |
826f309b | 218 | |
9a045790 DM |
219 | let passphrase = passphrase()?; |
220 | if passphrase.len() < 5 { | |
221 | bail!("Passphrase is too short!"); | |
222 | } | |
826f309b | 223 | |
9a045790 | 224 | let derived_key = kdf.derive_key(&passphrase)?; |
826f309b | 225 | |
9a045790 | 226 | if raw_data.len() < 32 { |
8428063d | 227 | bail!("Unable to decrypt key - short data"); |
9a045790 DM |
228 | } |
229 | let iv = &raw_data[0..16]; | |
230 | let tag = &raw_data[16..32]; | |
231 | let enc_data = &raw_data[32..]; | |
826f309b | 232 | |
9a045790 DM |
233 | let cipher = openssl::symm::Cipher::aes_256_gcm(); |
234 | ||
235 | openssl::symm::decrypt_aead( | |
236 | cipher, | |
237 | &derived_key, | |
9a37bd6c | 238 | Some(iv), |
9a045790 | 239 | b"", |
9a37bd6c FG |
240 | enc_data, |
241 | tag, | |
8428063d DM |
242 | ).map_err(|err| { |
243 | match self.hint { | |
244 | Some(ref hint) => { | |
245 | format_err!("Unable to decrypt key (password hint: {})", hint) | |
246 | } | |
247 | None => { | |
248 | format_err!("Unable to decrypt key (wrong password?) - {}", err) | |
249 | } | |
250 | } | |
251 | })? | |
9a045790 DM |
252 | |
253 | } else { | |
254 | raw_data.clone() | |
255 | }; | |
256 | ||
257 | let mut result = [0u8; 32]; | |
258 | result.copy_from_slice(&key); | |
259 | ||
260 | let crypt_config = CryptConfig::new(result.clone())?; | |
bbdda58b | 261 | let fingerprint = Fingerprint::new(crypt_config.fingerprint()); |
9a045790 DM |
262 | if let Some(ref stored_fingerprint) = self.fingerprint { |
263 | if &fingerprint != stored_fingerprint { | |
264 | bail!( | |
265 | "KeyConfig contains wrong fingerprint {}, contained key has fingerprint {}", | |
266 | stored_fingerprint, fingerprint | |
267 | ); | |
268 | } | |
e0af222e | 269 | } |
9a045790 DM |
270 | |
271 | Ok((result, self.created, fingerprint)) | |
272 | } | |
273 | ||
8abe51b7 | 274 | /// Store a KeyConfig to path |
9a045790 DM |
275 | pub fn store<P: AsRef<Path>>(&self, path: P, replace: bool) -> Result<(), Error> { |
276 | ||
277 | let path: &Path = path.as_ref(); | |
278 | ||
279 | let data = serde_json::to_string(self)?; | |
280 | ||
281 | try_block!({ | |
282 | if replace { | |
283 | let mode = nix::sys::stat::Mode::S_IRUSR | nix::sys::stat::Mode::S_IWUSR; | |
e0a19d33 | 284 | replace_file(path, data.as_bytes(), CreateOptions::new().perm(mode), true)?; |
9a045790 DM |
285 | } else { |
286 | use std::os::unix::fs::OpenOptionsExt; | |
287 | ||
288 | let mut file = std::fs::OpenOptions::new() | |
289 | .write(true) | |
290 | .mode(0o0600) | |
291 | .create_new(true) | |
292 | .open(&path)?; | |
293 | ||
294 | file.write_all(data.as_bytes())?; | |
295 | } | |
296 | ||
297 | Ok(()) | |
298 | }).map_err(|err: Error| format_err!("Unable to store key file {:?} - {}", path, err))?; | |
299 | ||
300 | Ok(()) | |
e0af222e | 301 | } |
9a045790 | 302 | } |
82a103c8 | 303 | |
8abe51b7 | 304 | /// Loads a KeyConfig from path and decrypt it. |
9a045790 DM |
305 | pub fn load_and_decrypt_key( |
306 | path: &std::path::Path, | |
307 | passphrase: &dyn Fn() -> Result<Vec<u8>, Error>, | |
308 | ) -> Result<([u8;32], i64, Fingerprint), Error> { | |
309 | decrypt_key(&file_get_contents(&path)?, passphrase) | |
310 | .with_context(|| format!("failed to load decryption key from {:?}", path)) | |
8ca37d6a | 311 | } |
37e60ddc | 312 | |
8abe51b7 | 313 | /// Decrypt a KeyConfig from raw keydata. |
8ca37d6a DM |
314 | pub fn decrypt_key( |
315 | mut keydata: &[u8], | |
316 | passphrase: &dyn Fn() -> Result<Vec<u8>, Error>, | |
317 | ) -> Result<([u8;32], i64, Fingerprint), Error> { | |
318 | let key_config: KeyConfig = serde_json::from_reader(&mut keydata)?; | |
9a045790 | 319 | key_config.decrypt(passphrase) |
826f309b | 320 | } |
8acfd15d | 321 | |
8abe51b7 | 322 | /// RSA encrypt a KeyConfig using a public key |
8acfd15d FG |
323 | pub fn rsa_encrypt_key_config( |
324 | rsa: openssl::rsa::Rsa<openssl::pkey::Public>, | |
325 | key: &KeyConfig, | |
326 | ) -> Result<Vec<u8>, Error> { | |
327 | let data = serde_json::to_string(key)?.as_bytes().to_vec(); | |
328 | ||
329 | let mut buffer = vec![0u8; rsa.size() as usize]; | |
330 | let len = rsa.public_encrypt(&data, &mut buffer, openssl::rsa::Padding::PKCS1)?; | |
331 | if len != buffer.len() { | |
332 | bail!("got unexpected length from rsa.public_encrypt()."); | |
333 | } | |
334 | Ok(buffer) | |
335 | } | |
7137630d | 336 | |
8abe51b7 | 337 | /// RSA deccrypt a KeyConfig using a private key |
7137630d FG |
338 | pub fn rsa_decrypt_key_config( |
339 | rsa: openssl::rsa::Rsa<openssl::pkey::Private>, | |
340 | key: &[u8], | |
341 | passphrase: &dyn Fn() -> Result<Vec<u8>, Error>, | |
342 | ) -> Result<([u8; 32], i64, Fingerprint), Error> { | |
343 | let mut buffer = vec![0u8; rsa.size() as usize]; | |
344 | let decrypted = rsa | |
345 | .private_decrypt(key, &mut buffer, openssl::rsa::Padding::PKCS1) | |
346 | .map_err(|err| format_err!("failed to decrypt KeyConfig using RSA - {}", err))?; | |
ccec086e | 347 | decrypt_key(&buffer[..decrypted], passphrase) |
7137630d | 348 | } |
73b50117 FG |
349 | |
350 | #[test] | |
351 | fn encrypt_decrypt_test() -> Result<(), Error> { | |
352 | use openssl::bn::BigNum; | |
353 | ||
354 | // hard-coded RSA key to avoid RNG load | |
355 | let n = BigNum::from_dec_str("763297775503047285270249195475255390818773358873206395804367739392073195066702037300664538507287660511788773520960052020490020500131532096848837840341808263208238432840771609456175669299183585737297710099814398628316822920397690811697390531460556770185920171717205255045261184699028939408338685227311360280561223048029934992213591164033485740834987719043448066906674761591422028943934961140687347873900379335604823288576732038392698785999130614670054444889172406669687648738432457362496418067100853836965448514921778954255248154805294695304544857640397043149235605321195443660560591215396460879078079707598866525981810195613239506906019678159905700662365794059211182357495974678620101388841934629146959674859076053348229540838236896752745251734302737503775744293828247434369307467826891918526442390310055226655466835862319406221740752718258752129277114593279326227799698036058425261999904258111333276380007458144919278763944469942242338999234161147188585579934794573969834141472487673642778646170134259790130811461184848743147137198639341697548363179639042991358823669057297753206096865332303845149920379065177826748710006313272747133642274061146677367740923397358666767242901746171920401890395722806446280380164886804469750825832083").expect("converting to bignum failed"); | |
356 | let e = BigNum::from_dec_str("65537").expect("converting to bignum failed"); | |
357 | let d = BigNum::from_dec_str("19834537920284564853674022001226176519590018312725185651690468898251379391772488358073023011091610629897253174637151053464371346136136825929376853412608136964518211867003891708559549030570664609466682947037305962494828103719078802086159819263581307957743290849968728341884428605863043529798446388179368090663224786773806846388143274064254180335413340334940446739125488182098535411927937482988091512111514808559058456451259207186517021416246081401087976557460070014777577029793101223558164090029643622447657946212243306210181845486266030884899215596710196751196243890657122549917370139613045651724521564033154854414253451612565268626314358200247667906740226693180923631251719053819020017537699856142036238058103150388959616397059243552685604990510867544536282659146915388522812398795915840913802745825670833498941795568293354230962683054249223513028733221781409833526268687556063636480230666207346771664323325175723577540510559973905170578206847160551684632855673373061549848844186260938182413805301541655002820734307939021848604620517318497220269398148326924299176570233223593669359192722153811016413065311904503101005564780859010942238851216519088762587394817890851764597501374473176420295837906296738426781972820833509964922715585").expect("converting to bignum failed"); | |
358 | let p = BigNum::from_dec_str("29509637001892646371585718218450720181675215968655693119622290166463846337874978909899277049204111617901784460858811114760264767076166751445502024396748257412446297522757119324882999179307561418697097464139952930737249422485899639568595470472222197161276683797577982497955467948265299386993875583089675892019886767032750524889582030672594405810531152141432362873209548569385820623081973262550874468619670422387868884561012170536839449407663630232422905779693831681822257822783504983493794208329832510955061326579888576047912149807967610736616238778237407615015312695567289456675371922184276823263863231190560557676339").expect("converting to bignum failed"); | |
359 | let q = BigNum::from_dec_str("25866050993920799422553175902510303878636288340476152724026122959148470649546748310678170203350410878157245623372422271950639190884394436256045773535202161325882791039345330048364703416719823181485853395688815455066122599160191671526435061804017559815713791273329637690511813515454721229797045837580571003198471014420883727461348135261877384657284061678787895040009197824032371314493780688519536250146270701914875469190776765810821706480996720025323321483843112182646061748043938180130013308823672610860230340094502643614566152670758944502783858455501528490806234504795239898001698524105646533910560293336400403204897").expect("converting to bignum failed"); | |
360 | let dmp1 = BigNum::from_dec_str("21607770579166338313924278588690558922108583912962897316392792781303188398339022047518905458553289108745759383366535358272664077428797321640702979183532285223743426240475893650342331272664468275332046219832278884297711602396407401980831582724583041600551528176116883960387063733484217876666037528133838392148714866050744345765006980605100330287254053877398358630385580919903058731105447806937933747350668236714360621211130384969129674812319182867594036995223272269821421615266717078107026511273509659211002684589097654567453625356436054504001404801715927134738465685565147724902539753143706245247513141254140715042985").expect("converting to bignum failed"); | |
361 | let dmq1 = BigNum::from_dec_str("294824909477987048059069264677589712640818276551195295555907561384926187881828905626998384758270243160099828809057470393016578048898219996082612765778049262408020582364022789357590879232947921274546172186391582540158896220038500063021605980859684104892476037676079761887366292263067835858498149757735119694054623308549371262243115446856316376077501168409517640338844786525965200908293851935915491689568704919822573134038943559526432621897623477713604851434011395096458613085567264607124524187730342254186063812054159860538030670385536895853938115358646898433438472543479930479076991585011794266310458811393428158049").expect("converting to bignum failed"); | |
362 | let iqmp = BigNum::from_dec_str("19428066064824171668277167138275898936765006396600005071379051329779053619544399695639107933588871625444213173194462077344726482973273922001955114108600584475883837715007613468112455972196002915686862701860412263935895363086514864873592142686096117947515832613228762197577036084559813332497101195090727973644165586960538914545531208630624795512138060798977135902359295307626262953373309121954863020224150277262533638440848025788447039555055470985052690506486164836957350781708784380677438638580158751807723730202286612196281022183410822668814233870246463721184575820166925259871133457423401827024362448849298618281053").expect("converting to bignum failed"); | |
363 | let public = | |
364 | openssl::rsa::Rsa::from_public_components(n.to_owned().unwrap(), e.to_owned().unwrap()) | |
365 | .expect("creating hard-coded RSA public key instance failed"); | |
366 | let private = openssl::rsa::Rsa::from_private_components(n, e, d, p, q, dmp1, dmq1, iqmp) | |
367 | .expect("creating hard-coded RSA key instance failed"); | |
368 | ||
369 | let passphrase = || -> Result<Vec<u8>, Error> { Ok(Vec::new()) }; | |
370 | ||
371 | let key = KeyConfig { | |
372 | kdf: None, | |
6ef1b649 WB |
373 | created: proxmox_time::epoch_i64(), |
374 | modified: proxmox_time::epoch_i64(), | |
73b50117 FG |
375 | data: (0u8..32u8).collect(), |
376 | fingerprint: Some(Fingerprint::new([ | |
377 | 14, 171, 212, 70, 11, 110, 185, 202, 52, 80, 35, 222, 226, 183, 120, 199, 144, 229, 74, | |
378 | 22, 131, 185, 101, 156, 10, 87, 174, 25, 144, 144, 21, 155, | |
379 | ])), | |
82a103c8 | 380 | hint: None, |
73b50117 FG |
381 | }; |
382 | ||
44288184 | 383 | let encrypted = rsa_encrypt_key_config(public, &key).expect("encryption failed"); |
73b50117 | 384 | let (decrypted, created, fingerprint) = |
44288184 | 385 | rsa_decrypt_key_config(private, &encrypted, &passphrase) |
73b50117 FG |
386 | .expect("decryption failed"); |
387 | ||
388 | assert_eq!(key.created, created); | |
389 | assert_eq!(key.data, decrypted); | |
390 | assert_eq!(key.fingerprint, Some(fingerprint)); | |
391 | ||
c0174285 FG |
392 | Ok(()) |
393 | } | |
394 | ||
395 | #[test] | |
396 | fn fingerprint_checks() -> Result<(), Error> { | |
e0af222e FG |
397 | let key = KeyConfig { |
398 | kdf: None, | |
6ef1b649 WB |
399 | created: proxmox_time::epoch_i64(), |
400 | modified: proxmox_time::epoch_i64(), | |
e0af222e FG |
401 | data: (0u8..32u8).collect(), |
402 | fingerprint: Some(Fingerprint::new([0u8; 32])), // wrong FP | |
82a103c8 | 403 | hint: None, |
e0af222e | 404 | }; |
e0af222e | 405 | |
c0174285 FG |
406 | let expected_fingerprint = Fingerprint::new([ |
407 | 14, 171, 212, 70, 11, 110, 185, 202, 52, 80, 35, 222, 226, 183, 120, 199, 144, 229, 74, | |
408 | 22, 131, 185, 101, 156, 10, 87, 174, 25, 144, 144, 21, 155, | |
409 | ]); | |
410 | ||
411 | let mut data = serde_json::to_vec(&key).expect("encoding KeyConfig failed"); | |
412 | decrypt_key(&mut data, &{ || { Ok(Vec::new()) }}).expect_err("decoding KeyConfig with wrong fingerprint worked"); | |
413 | ||
414 | let key = KeyConfig { | |
415 | kdf: None, | |
6ef1b649 WB |
416 | created: proxmox_time::epoch_i64(), |
417 | modified: proxmox_time::epoch_i64(), | |
c0174285 FG |
418 | data: (0u8..32u8).collect(), |
419 | fingerprint: None, | |
82a103c8 | 420 | hint: None, |
c0174285 FG |
421 | }; |
422 | ||
423 | ||
424 | let mut data = serde_json::to_vec(&key).expect("encoding KeyConfig failed"); | |
425 | let (key_data, created, fingerprint) = decrypt_key(&mut data, &{ || { Ok(Vec::new()) }}).expect("decoding KeyConfig without fingerprint failed"); | |
426 | ||
427 | assert_eq!(key.data, key_data); | |
e0af222e | 428 | assert_eq!(key.created, created); |
c0174285 | 429 | assert_eq!(expected_fingerprint, fingerprint); |
e0af222e | 430 | |
73b50117 FG |
431 | Ok(()) |
432 | } |