1use std::cmp;
2use std::time::{SystemTime, UNIX_EPOCH};
3
4#[cfg(any(windows, unix))]
5use rpassword::prompt_password;
6
7use crate::constants::*;
8use crate::errors::*;
9
10#[cfg(not(any(windows, unix)))]
11fn prompt_password(prompt: &str) -> Result<String> {
12 use std::io::{stdin, stdout, Write};
13
14 stdout().write_all(prompt.as_bytes())?;
15 stdout().flush()?;
16 let mut password = String::new();
17 stdin().read_line(&mut password)?;
18 Ok(password)
19}
20
21pub fn store_u64_le(x: u64) -> [u8; 8] {
22 let b1: u8 = (x & 0xff) as u8;
23 let b2: u8 = ((x >> 8) & 0xff) as u8;
24 let b3: u8 = ((x >> 16) & 0xff) as u8;
25 let b4: u8 = ((x >> 24) & 0xff) as u8;
26 let b5: u8 = ((x >> 32) & 0xff) as u8;
27 let b6: u8 = ((x >> 40) & 0xff) as u8;
28 let b7: u8 = ((x >> 48) & 0xff) as u8;
29 let b8: u8 = ((x >> 56) & 0xff) as u8;
30 [b1, b2, b3, b4, b5, b6, b7, b8]
31}
32
33#[allow(clippy::cast_lossless)]
34pub fn load_u64_le(x: &[u8]) -> u64 {
35 (x[0] as u64)
36 | (x[1] as u64) << 8
37 | (x[2] as u64) << 16
38 | (x[3] as u64) << 24
39 | (x[4] as u64) << 32
40 | (x[5] as u64) << 40
41 | (x[6] as u64) << 48
42 | (x[7] as u64) << 56
43}
44
45pub fn raw_scrypt_params(memlimit: usize, opslimit: u64, n_log2_max: u8) -> Result<scrypt::Params> {
46 let opslimit = cmp::max(32768, opslimit);
47 let mut n_log2 = 1u8;
48 let r = 8u32;
49 let p;
50 if opslimit < (memlimit / 32) as u64 {
51 p = 1;
52 let maxn = opslimit / (u64::from(r) * 4);
53 while n_log2 < 63 {
54 if 1u64 << n_log2 > maxn / 2 {
55 break;
56 }
57 n_log2 += 1;
58 }
59 } else {
60 let maxn = memlimit as u64 / (u64::from(r) * 128);
61 while n_log2 < 63 {
62 if 1u64 << n_log2 > maxn / 2 {
63 break;
64 }
65 n_log2 += 1;
66 }
67 let maxrp = cmp::min(0x3fff_ffff_u32, ((opslimit / 4) / (1u64 << n_log2)) as u32);
68 p = maxrp / r;
69 }
70 if n_log2 > n_log2_max {
71 return Err(PError::new(ErrorKind::KDF, "scrypt parameters too high"));
72 }
73 scrypt::Params::new(n_log2, r, p, scrypt::Params::RECOMMENDED_LEN).map_err(Into::into)
74}
75
76pub fn get_password(prompt: &str) -> Result<String> {
77 let pwd = prompt_password(prompt)?;
78 if pwd.is_empty() {
79 println!("<empty>");
80 Ok(pwd)
81 } else if pwd.len() > PASSWORD_MAXBYTES {
82 Err(PError::new(
83 ErrorKind::Misc,
84 "passphrase can't exceed 1024 bytes length",
85 ))
86 } else {
87 Ok(pwd)
88 }
89}
90
91pub fn unix_timestamp() -> u64 {
92 let start = SystemTime::now();
93 let since_the_epoch = start
94 .duration_since(UNIX_EPOCH)
95 .expect("system clock is incorrect");
96 since_the_epoch.as_secs()
97}