enprot/
prot.rs

1// Copyright (c) 2018-2020 [Ribose Inc](https://www.ribose.com).
2//
3// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions
5// are met:
6// 1. Redistributions of source code must retain the above copyright
7//    notice, this list of conditions and the following disclaimer.
8// 2. Redistributions in binary form must reproduce the above copyright
9//    notice, this list of conditions and the following disclaimer in the
10//    documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
13// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
14// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
15// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
16// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24use std::collections::BTreeMap;
25
26use cipher;
27use crypto::CryptoPolicy;
28use etree;
29use pbkdf::derive_key;
30use pbkdf::PBKDFCache;
31use utils;
32
33// Get a password
34
35pub 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
49// Encrypt
50
51pub 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 required
70        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        // IV not required
85        return Err("IV was supplied but not expected");
86    }
87    Ok((enc.process(&key, &iv, &[], &pt, policy)?, extfields))
88}
89
90// Decrypt
91
92pub 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}