Skip to content

Commit 36ede22

Browse files
committed
Overwrite secrets and passwords after use
1 parent eeaf816 commit 36ede22

File tree

6 files changed

+61
-35
lines changed

6 files changed

+61
-35
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ data-encoding = "2.3.2"
2222
totp-lite = "1.0.3"
2323
crossterm = "0.20"
2424
tui = { version = "0.16.0", features = ["crossterm"], default-features = false }
25-
copypasta-ext = "0.3.7"
25+
copypasta-ext = "0.3.7"
26+
zeroize = "1.4.1"

src/argument_functions.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{cryptography, database_loader};
22
use crate::cryptography::prompt_for_passwords;
33
use crate::importers;
44
use crate::otp::{otp_element::OTPElement, otp_helper};
5+
use zeroize::Zeroize;
56

67
pub fn help() {
78
println!("USAGE:");
@@ -45,14 +46,16 @@ pub fn import(args: Vec<String>) {
4546
}
4647
}
4748

48-
match database_loader::overwrite_database(elements, &cryptography::prompt_for_passwords("Choose a password: ", 8, true)) {
49+
let mut pw = cryptography::prompt_for_passwords("Choose a password: ", 8, true);
50+
match database_loader::overwrite_database(elements, &pw) {
4951
Ok(()) => {
5052
println!("Successfully imported database");
5153
}
5254
Err(e) => {
5355
eprintln!("An error occurred during database overwriting: {}", e);
5456
}
5557
}
58+
pw.zeroize();
5659
} else {
5760
println!("Invalid arguments, type cotp --import [APPNAME] [PATH]");
5861
println!("cotp can import backup from:");
@@ -75,10 +78,12 @@ pub fn add(args: Vec<String>) {
7578
return;
7679
}
7780

78-
match database_loader::add_element(&prompt_for_passwords("Insert the secret: ", 0, false), &args[2], &args[3], &args[4], digits) {
81+
let mut secret = prompt_for_passwords("Insert the secret: ", 0, false);
82+
match database_loader::add_element(&secret, &args[2], &args[3], &args[4], digits) {
7983
Ok(()) => println!("Success"),
8084
Err(e) => eprintln!("An error occurred: {}", e)
8185
}
86+
secret.zeroize();
8287
} else {
8388
println!("Invalid arguments, type cotp --add [ISSUER] [LABEL] [ALGORITHM] [DIGITS]");
8489
}
@@ -100,7 +105,7 @@ pub fn remove(args: Vec<String>) {
100105
pub fn edit(args: Vec<String>) {
101106
if args.len() == 7 {
102107
let id = args[2].parse::<usize>().unwrap();
103-
let secret = &prompt_for_passwords("Insert the secret (type ENTER to skip modification): ", 0, false);
108+
let mut secret = prompt_for_passwords("Insert the secret (type ENTER to skip modification): ", 0, false);
104109
let issuer = &args[3];
105110
let label = &args[4];
106111
let algorithm = &args[5];
@@ -112,6 +117,7 @@ pub fn edit(args: Vec<String>) {
112117
Ok(()) => println!("Success"),
113118
Err(e) => eprintln!("An error occurred: {}", e)
114119
}
120+
secret.zeroize();
115121
} else {
116122
println!("Invalid arguments, type cotp --edit [ID] [ISSUER] [LABEL] [ALGORITHM] [DIGITS]\n\nReplace the attribute value with \".\" to skip the attribute modification");
117123
}
@@ -164,7 +170,7 @@ pub fn single(args: Vec<String>) {
164170
pub fn info(args: Vec<String>) {
165171
if args.len() == 3 {
166172
let id = args[2].parse::<usize>().unwrap();
167-
match otp_helper::print_json_result(id) {
173+
match otp_helper::print_element_info(id) {
168174
Ok(()) => {}
169175
Err(e) => eprintln!("An error occurred: {}", e),
170176
}
@@ -175,15 +181,17 @@ pub fn info(args: Vec<String>) {
175181

176182
pub fn change_password(args: Vec<String>) {
177183
if args.len() == 2 {
178-
let old_password = &cryptography::prompt_for_passwords("Old password: ", 8, false);
179-
let decrypted_text = database_loader::read_decrypted_text(old_password);
184+
let mut old_password = cryptography::prompt_for_passwords("Old password: ", 8, false);
185+
let decrypted_text = database_loader::read_decrypted_text(&old_password);
186+
old_password.zeroize();
180187
match decrypted_text {
181188
Ok(s) => {
182-
let new_password = &cryptography::prompt_for_passwords("New password: ", 8, true);
183-
match database_loader::overwrite_database_json(&s, new_password) {
189+
let mut new_password = cryptography::prompt_for_passwords("New password: ", 8, true);
190+
match database_loader::overwrite_database_json(&s, &new_password) {
184191
Ok(()) => println!("Password changed"),
185192
Err(e) => eprintln!("An error has occurred: {}", e),
186193
}
194+
new_password.zeroize();
187195
}
188196
Err(e) => {
189197
eprintln!("An error has occurred: {}", e);

src/cryptography.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,10 @@ fn header_vec_to_header_array(byte_vec: Vec<u8>) -> [u8; 24] {
9696

9797
pub fn prompt_for_passwords(message: &str, minimum_password_length: usize, verify: bool) -> String {
9898
let mut password;
99-
let mut verify_password;
10099
loop {
101100
password = rpassword::prompt_password_stdout(message).unwrap();
102101
if verify {
103-
verify_password = rpassword::prompt_password_stdout("Retype the same password: ").unwrap();
102+
let verify_password = rpassword::prompt_password_stdout("Retype the same password: ").unwrap();
104103
if password != verify_password {
105104
println!("Passwords do not match");
106105
continue;

src/database_loader.rs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use utils::{check_elements, get_db_path};
1010
use crate::cryptography;
1111
use crate::otp::otp_element::OTPElement;
1212
use crate::utils;
13+
use zeroize::Zeroize;
1314

1415
pub fn read_decrypted_text(password: &str) -> Result<String, String> {
1516
let encrypted_contents = read_to_string(&get_db_path()).unwrap();
@@ -48,18 +49,20 @@ pub fn add_element(secret: &String, issuer: &String, label: &String, algorithm:
4849
Ok(()) => {}
4950
Err(error) => return Err(error.to_string())
5051
}
51-
let pw = &cryptography::prompt_for_passwords("Password: ", 8, false);
52+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
5253
let otp_element = OTPElement::new(upper_secret.to_string(), issuer.to_string(), label.to_string(), digits, String::from("TOTP"), String::from(algorithm).to_uppercase(), String::from("Default"), 0, 0, 30, vec![]);
5354
let mut elements;
54-
match read_from_file(pw) {
55+
match read_from_file(&pw) {
5556
Ok(result) => elements = result,
5657
Err(e) => return Err(e)
5758
}
5859
elements.push(otp_element);
59-
match overwrite_database(elements, pw) {
60+
let result = match overwrite_database(elements, &pw) {
6061
Ok(()) => Ok(()),
6162
Err(e) => Err(format!("{}", e))
62-
}
63+
};
64+
pw.zeroize();
65+
result
6366
}
6467

6568
pub fn remove_element_from_db(mut id: usize) -> Result<(), String> {
@@ -70,24 +73,26 @@ pub fn remove_element_from_db(mut id: usize) -> Result<(), String> {
7073
id -= 1;
7174

7275
let mut elements: Vec<OTPElement>;
73-
let pw = &cryptography::prompt_for_passwords("Password: ", 8, false);
74-
match read_from_file(pw) {
76+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
77+
match read_from_file(&pw) {
7578
Ok(result) => elements = result,
7679
Err(e) => {
7780
return Err(e);
7881
}
7982
}
8083

81-
match check_elements(id, &elements) {
84+
let result = match check_elements(id, &elements) {
8285
Ok(()) => {
8386
elements.remove(id);
84-
match overwrite_database(elements, pw) {
87+
match overwrite_database(elements, &pw) {
8588
Ok(()) => Ok(()),
8689
Err(e) => Err(format!("{}", e)),
8790
}
8891
}
8992
Err(e) => Err(e)
90-
}
93+
};
94+
pw.zeroize();
95+
result
9196
}
9297

9398
pub fn edit_element(mut id: usize, secret: &str, issuer: &str, label: &str, algorithm: &str, digits: u64) -> Result<(), String> {
@@ -97,13 +102,13 @@ pub fn edit_element(mut id: usize, secret: &str, issuer: &str, label: &str, algo
97102
id -= 1;
98103

99104
let mut elements: Vec<OTPElement>;
100-
let pw = &cryptography::prompt_for_passwords("Password: ", 8, false);
101-
match read_from_file(pw) {
105+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
106+
match read_from_file(&pw) {
102107
Ok(result) => elements = result,
103108
Err(_e) => return Err(String::from("Cannot decrypt existing database"))
104109
}
105110

106-
match check_elements(id, &elements) {
111+
let result = match check_elements(id, &elements) {
107112
Ok(()) => {
108113
if secret != "" {
109114
elements[id].set_secret(secret.to_string());
@@ -120,20 +125,24 @@ pub fn edit_element(mut id: usize, secret: &str, issuer: &str, label: &str, algo
120125
if digits != 0 {
121126
elements[id].set_digits(digits);
122127
}
123-
match overwrite_database(elements, pw) {
128+
match overwrite_database(elements, &pw) {
124129
Ok(()) => Ok(()),
125130
Err(e) => Err(format!("{}", e)),
126131
}
127132
}
128133
Err(e) => Err(e)
129-
}
134+
};
135+
pw.zeroize();
136+
result
130137
}
131138

132139
pub fn export_database() -> Result<PathBuf, String> {
133140
let exported_path = utils::get_home_folder().join("exported.cotp");
134141
let mut file = File::create(&exported_path).expect("Cannot create file");
135142
let encrypted_contents = read_to_string(&get_db_path()).unwrap();
136-
let contents = cryptography::decrypt_string(&encrypted_contents, &cryptography::prompt_for_passwords("Password: ", 8, false));
143+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
144+
let contents = cryptography::decrypt_string(&encrypted_contents, &pw);
145+
pw.zeroize();
137146
return match contents {
138147
Ok(contents) => {
139148
if contents == "[]" {

src/main.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use interface::event::{Event, EventHandler};
99
use interface::handler::handle_key_events;
1010
use otp::otp_helper;
1111
use interface::ui::Tui;
12+
use zeroize::Zeroize;
1213

1314
mod database_loader;
1415
mod utils;
@@ -37,11 +38,13 @@ fn init() -> Result<bool, String> {
3738
match utils::create_db_if_needed() {
3839
Ok(value) => {
3940
if value {
40-
let pw = &cryptography::prompt_for_passwords("Choose a password: ", 8, true);
41-
return match database_loader::overwrite_database_json("[]", pw) {
41+
let mut pw = cryptography::prompt_for_passwords("Choose a password: ", 8, true);
42+
let result = match database_loader::overwrite_database_json("[]", &pw) {
4243
Ok(()) => Ok(true),
4344
Err(_e) => Err(String::from("An error occurred during database overwriting")),
4445
};
46+
pw.zeroize();
47+
return result;
4548
}
4649
Ok(false)
4750
}

src/otp/otp_helper.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{cryptography, database_loader};
55
use crate::otp::otp_element::OTPElement;
66
use crate::otp::otp_maker::make_totp;
77
use crate::utils::check_elements;
8+
use zeroize::Zeroize;
89

910
#[derive(Serialize, Deserialize)]
1011
struct JsonResult {
@@ -26,10 +27,13 @@ impl JsonResult {
2627
}
2728

2829
pub fn read_codes() -> Result<Vec<OTPElement>, String> {
29-
match database_loader::read_from_file(&cryptography::prompt_for_passwords("Password: ", 8, false)) {
30+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
31+
let result = match database_loader::read_from_file(&pw) {
3032
Ok(result) => Ok(result),
3133
Err(e) => Err(e),
32-
}
34+
};
35+
pw.zeroize();
36+
result
3337
}
3438

3539
pub fn list_codes(elements: &Vec<OTPElement>) {
@@ -51,11 +55,12 @@ pub fn get_good_otp_code(element: &OTPElement) -> String {
5155

5256
pub fn get_json_results() -> Result<String, String> {
5357
let elements: Vec<OTPElement>;
54-
55-
match database_loader::read_from_file(&cryptography::prompt_for_passwords("Password: ", 8, false)) {
58+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
59+
match database_loader::read_from_file(&pw) {
5660
Ok(result) => elements = result,
5761
Err(e) => return Err(e)
5862
}
63+
pw.zeroize();
5964
let mut results: Vec<JsonResult> = Vec::new();
6065

6166
if elements.len() == 0 {
@@ -72,18 +77,19 @@ pub fn get_json_results() -> Result<String, String> {
7277
Ok(json_string.to_string())
7378
}
7479

75-
pub fn print_json_result(mut index: usize) -> Result<(), String> {
80+
pub fn print_element_info(mut index: usize) -> Result<(), String> {
7681
if index == 0 {
7782
return Err(String::from("Invalid element"));
7883
}
7984
index -= 1;
8085

8186
let elements: Vec<OTPElement>;
82-
83-
match database_loader::read_from_file(&cryptography::prompt_for_passwords("Password: ", 8, false)) {
87+
let mut pw = cryptography::prompt_for_passwords("Password: ", 8, false);
88+
match database_loader::read_from_file(&pw) {
8489
Ok(result) => elements = result,
8590
Err(e) => return Err(e),
8691
}
92+
pw.zeroize();
8793

8894
match check_elements(index, &elements) {
8995
Ok(()) => {}

0 commit comments

Comments
 (0)