1use std::collections::BTreeMap;
25
26use cipher;
27use crypto::CryptoPolicy;
28use etree;
29use pbkdf::derive_key;
30use pbkdf::PBKDFCache;
31use utils;
32
33pub fn get_password(name: &str, rep: bool) -> String {
36 let prompt = "Password for ".to_string() + name + ": ";
37 let mut pass = rpassword::prompt_password_stdout(&prompt).unwrap();
38 if rep {
39 let prompt = "Repeat password for ".to_string() + name + ": ";
40 let pass2 = rpassword::prompt_password_stdout(&prompt).unwrap();
41 if pass != pass2 {
42 eprintln!("Password mismatch. Try again.");
43 pass = get_password(name, rep);
44 }
45 }
46 pass
47}
48
49pub fn encrypt(
52 pt: Vec<u8>,
53 password: &str,
54 rng: &Option<botan::RandomNumberGenerator>,
55 pbkdfopts: &etree::PBKDFOptions,
56 cipheropts: &etree::CipherOptions,
57 cache: &mut Option<PBKDFCache>,
58 policy: &Box<dyn CryptoPolicy>,
59) -> Result<(Vec<u8>, BTreeMap<String, String>), &'static str> {
60 let enc = cipher::encryption(&cipheropts.alg)?;
61 let key_len = enc.key_len_max();
62 let (key, pbkdf) = derive_key(password, key_len, rng, pbkdfopts, cache, policy)?;
63 let mut extfields: BTreeMap<String, String> = BTreeMap::new();
64 if pbkdf != None {
65 extfields.insert("pbkdf".to_string(), pbkdf.unwrap());
66 }
67 let mut iv: Vec<u8> = Vec::new();
68 if cipheropts.alg != "aes-256-siv" {
69 iv = if let Some(myiv) = cipheropts.iv.clone() {
71 myiv
72 } else {
73 let ivlen = enc.nonce_len();
74 rng.as_ref()
75 .ok_or("Missing RNG")?
76 .read(ivlen)
77 .map_err(|_| "RNG error")?
78 };
79 extfields.insert(
80 "cipher".to_string(),
81 format!("{}$iv={}", &cipheropts.alg, utils::base64_encode(&iv)?).to_string(),
82 );
83 } else if cipheropts.iv != None {
84 return Err("IV was supplied but not expected");
86 }
87 Ok((enc.process(&key, &iv, &[], &pt, policy)?, extfields))
88}
89
90pub fn decrypt(
93 ct: Vec<u8>,
94 password: &str,
95 pbkdf: &Option<&String>,
96 cipher: &Option<&String>,
97 cache: &mut Option<PBKDFCache>,
98 policy: &Box<dyn CryptoPolicy>,
99) -> Result<Vec<u8>, &'static str> {
100 let cipher_alg;
101 let mut iv = Vec::new();
102 if let Some(cipher) = cipher {
103 let mut it = cipher.split("$");
104 cipher_alg = it.next().ok_or("Invalid cipher extfield")?;
105 let mut fields = BTreeMap::new();
106 for val in it {
107 let mut it = val.splitn(2, '=');
108 let key = it.next().ok_or("Missing field key")?;
109 let value = it.collect::<String>();
110 fields.insert(key, value);
111 }
112 if let Some(myiv) = fields.get("iv") {
113 iv = utils::base64_decode(myiv)?;
114 }
115 } else {
116 cipher_alg = "aes-256-siv";
117 }
118 let dec = cipher::decryption(&cipher_alg)?;
119 let key_len = dec.key_len_max();
120 let key: Vec<u8>;
121 if let Some(pbkdf) = pbkdf {
122 let phc: phc::raw::RawPHC = pbkdf.parse().map_err(|_| "Failed to parse PHC")?;
123 let alg = phc.id();
124 let mut params_map: BTreeMap<String, usize> = BTreeMap::new();
125 params_map.extend(
126 phc.params()
127 .iter()
128 .map(|v| (v.0.to_string(), v.1.parse::<usize>().unwrap())),
129 );
130 let salt = match phc.salt().ok_or("Missing salt")? {
131 phc::Salt::Ascii(s) => utils::base64_decode(s)?,
132 phc::Salt::Binary(b) => utils::base64_decode(std::str::from_utf8(b).unwrap())?,
133 };
134 let pbkdfopts = etree::PBKDFOptions {
135 alg: alg.to_string(),
136 saltlen: 0,
137 salt: Some(salt),
138 msec: None,
139 params: Some(params_map),
140 };
141 let (thekey, _) = derive_key(password, key_len, &None, &pbkdfopts, cache, policy)?;
142 key = thekey;
143 } else {
144 let (thekey, _) = derive_key(
145 password,
146 key_len,
147 &None,
148 &etree::PBKDFOptions {
149 alg: "legacy".to_string(),
150 saltlen: 0,
151 salt: None,
152 msec: None,
153 params: None,
154 },
155 cache,
156 policy,
157 )?;
158 key = thekey;
159 }
160 Ok(dec.process(&key, &iv, &[], &ct, policy)?)
161}