1use std::cmp;
2use std::fmt::Write as fmtWrite;
3use std::fmt::{self, Formatter};
4use std::fs;
5use std::io::{self, Write};
6use std::io::{Cursor, Read};
7use std::path::Path;
8
9use ct_codecs::{Base64, Decoder, Encoder};
10
11use crate::constants::*;
12use crate::crypto::blake2b::Blake2b;
13use crate::crypto::util::fixed_time_eq;
14use crate::errors::*;
15use crate::helpers::*;
16use crate::keynum::*;
17use crate::Result;
18
19#[derive(Clone, Debug)]
29pub struct SecretKeyBox(String);
30
31impl From<SecretKeyBox> for String {
32 fn from(skb: SecretKeyBox) -> String {
33 skb.0
34 }
35}
36
37impl From<String> for SecretKeyBox {
38 fn from(s: String) -> SecretKeyBox {
39 SecretKeyBox(s)
40 }
41}
42
43impl std::fmt::Display for SecretKeyBox {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 write!(f, "{}", self.0)
46 }
47}
48
49impl SecretKeyBox {
50 pub fn from_string(s: &str) -> Result<SecretKeyBox> {
52 Ok(s.to_string().into())
53 }
54
55 pub fn into_string(self) -> String {
57 self.into()
58 }
59
60 pub fn into_secret_key(self, password: Option<String>) -> Result<SecretKey> {
63 SecretKey::from_box(self, password)
64 }
65
66 pub fn into_unencrypted_secret_key(self) -> Result<SecretKey> {
68 SecretKey::from_unencrypted_box(self)
69 }
70
71 pub fn to_bytes(&self) -> Vec<u8> {
73 self.to_string().as_bytes().to_vec()
74 }
75}
76
77#[derive(Clone)]
79pub struct SecretKey {
80 pub(crate) sig_alg: [u8; TWOBYTES],
81 pub(crate) kdf_alg: [u8; TWOBYTES],
82 pub(crate) chk_alg: [u8; TWOBYTES],
83 pub(crate) kdf_salt: [u8; KDF_SALTBYTES],
84 pub(crate) kdf_opslimit_le: [u8; KEYNUM_BYTES],
85 pub(crate) kdf_memlimit_le: [u8; KEYNUM_BYTES],
86 pub(crate) keynum_sk: KeynumSK,
87}
88
89impl SecretKey {
90 pub(crate) fn write_checksum(&mut self) -> Result<()> {
91 let h = self.read_checksum()?;
92 self.keynum_sk.chk.copy_from_slice(&h[..]);
93 Ok(())
94 }
95
96 pub(crate) fn read_checksum(&self) -> Result<Vec<u8>> {
97 let mut state = Blake2b::new(CHK_BYTES);
98 state.update(&self.sig_alg);
99 state.update(&self.keynum_sk.keynum);
100 state.update(&self.keynum_sk.sk);
101 let mut h = vec![0u8; CHK_BYTES];
102 state.finalize(&mut h);
103 Ok(h)
104 }
105
106 pub(crate) fn xor_keynum(&mut self, stream: &[u8]) {
107 for (byte, stream) in self.keynum_sk.keynum.iter_mut().zip(stream.iter()) {
108 *byte ^= *stream
109 }
110 let keynum_len = self.keynum_sk.keynum.len();
111 for (byte, stream) in self
112 .keynum_sk
113 .sk
114 .iter_mut()
115 .zip(stream[keynum_len..].iter())
116 {
117 *byte ^= *stream
118 }
119 let sk_len = self.keynum_sk.sk.len();
120 for (byte, stream) in self
121 .keynum_sk
122 .chk
123 .iter_mut()
124 .zip(stream[keynum_len + sk_len..].iter())
125 {
126 *byte ^= *stream
127 }
128 }
129
130 pub(crate) fn encrypt(mut self, password: String) -> Result<SecretKey> {
131 let mut stream = [0u8; CHK_BYTES + SECRETKEY_BYTES + KEYNUM_BYTES];
132 let opslimit = load_u64_le(&self.kdf_opslimit_le);
133 let memlimit = load_u64_le(&self.kdf_memlimit_le) as usize;
134 if memlimit > MEMLIMIT_MAX {
135 return Err(PError::new(ErrorKind::KDF, "scrypt parameters too high"));
136 }
137 let params = raw_scrypt_params(memlimit, opslimit, N_LOG2_MAX)?;
138 scrypt::scrypt(password.as_bytes(), &self.kdf_salt, ¶ms, &mut stream)?;
139 self.xor_keynum(&stream);
140 Ok(self)
141 }
142
143 pub fn keynum(&self) -> &[u8] {
145 &self.keynum_sk.keynum[..]
146 }
147
148 pub fn is_encrypted(&self) -> bool {
151 if self.kdf_alg == KDF_NONE {
152 return false;
153 }
154
155 match self.read_checksum() {
158 Ok(checksum_vec) => {
159 let mut expected_chk = [0u8; CHK_BYTES];
160 expected_chk.copy_from_slice(&checksum_vec[..]);
161 expected_chk != self.keynum_sk.chk
162 }
163 Err(_) => true, }
165 }
166
167 pub fn from_bytes(bytes_buf: &[u8]) -> Result<SecretKey> {
171 let mut buf = Cursor::new(bytes_buf);
172 let mut sig_alg = [0u8; TWOBYTES];
173 let mut kdf_alg = [0u8; TWOBYTES];
174 let mut chk_alg = [0u8; TWOBYTES];
175 let mut kdf_salt = [0u8; KDF_SALTBYTES];
176 let mut ops_limit = [0u8; KEYNUM_BYTES];
177 let mut mem_limit = [0u8; KEYNUM_BYTES];
178 let mut keynum = [0u8; KEYNUM_BYTES];
179 let mut sk = [0u8; SECRETKEY_BYTES];
180 let mut chk = [0u8; CHK_BYTES];
181 buf.read_exact(&mut sig_alg)?;
182 buf.read_exact(&mut kdf_alg)?;
183 buf.read_exact(&mut chk_alg)?;
184 buf.read_exact(&mut kdf_salt)?;
185 buf.read_exact(&mut ops_limit)?;
186 buf.read_exact(&mut mem_limit)?;
187 buf.read_exact(&mut keynum)?;
188 buf.read_exact(&mut sk)?;
189 buf.read_exact(&mut chk)?;
190
191 Ok(SecretKey {
192 sig_alg,
193 kdf_alg,
194 chk_alg,
195 kdf_salt,
196 kdf_opslimit_le: ops_limit,
197 kdf_memlimit_le: mem_limit,
198 keynum_sk: KeynumSK { keynum, sk, chk },
199 })
200 }
201
202 pub fn to_bytes(&self) -> Vec<u8> {
206 let mut iters = Vec::new();
207 iters.push(self.sig_alg.iter());
208 iters.push(self.kdf_alg.iter());
209 iters.push(self.chk_alg.iter());
210 iters.push(self.kdf_salt.iter());
211 iters.push(self.kdf_opslimit_le.iter());
212 iters.push(self.kdf_memlimit_le.iter());
213 iters.push(self.keynum_sk.keynum.iter());
214 iters.push(self.keynum_sk.sk.iter());
215 iters.push(self.keynum_sk.chk.iter());
216 let v: Vec<u8> = iters.iter().flat_map(|b| b.clone().cloned()).collect();
217 v
218 }
219
220 fn from_box_(
221 sk_box: SecretKeyBox,
222 password: Option<String>,
223 unencrypted_key: bool,
224 ) -> Result<SecretKey> {
225 let s = sk_box.0;
226 let mut lines = s.lines();
227 lines.next().ok_or_else(|| {
228 PError::new(ErrorKind::Io, "Missing comment in secret key".to_string())
229 })?;
230 let encoded_sk = lines.next().ok_or_else(|| {
231 PError::new(
232 ErrorKind::Io,
233 "Missing encoded key in secret key".to_string(),
234 )
235 })?;
236 let mut sk = SecretKey::from_base64(encoded_sk)?;
237 if unencrypted_key {
238 if sk.kdf_alg != KDF_NONE {
239 return Err(PError::new(
240 ErrorKind::Io,
241 "Key might be encrypted".to_string(),
242 ));
243 }
244 } else {
245 match sk.kdf_alg {
246 KDF_NONE => {
247 return Err(PError::new(
248 ErrorKind::Io,
249 "Key might be encrypted".to_string(),
250 ))
251 }
252 KDF_ALG => {}
253 _ => {
254 return Err(PError::new(
255 ErrorKind::Io,
256 "Unsupported encryption algorithm".to_string(),
257 ))
258 }
259 }
260 let interactive = password.is_none();
261 let password = match password {
262 Some(password) => password,
263 None => {
264 let password = get_password("Password: ")?;
265 write!(
266 io::stdout(),
267 "Deriving a key from the password and decrypting the secret key... "
268 )
269 .map_err(|e| PError::new(ErrorKind::Io, e))?;
270 io::stdout().flush()?;
271 password
272 }
273 };
274 sk = sk.encrypt(password)?;
275 if interactive {
276 writeln!(io::stdout(), "done").map_err(|e| PError::new(ErrorKind::Io, e))?
277 }
278 }
279 let checksum_vec = sk.read_checksum()?;
280 let mut chk = [0u8; CHK_BYTES];
281 chk.copy_from_slice(&checksum_vec[..]);
282 if chk != sk.keynum_sk.chk {
283 if unencrypted_key {
284 Err(PError::new(ErrorKind::Verify, "Corrupted key"))
285 } else {
286 Err(PError::new(
287 ErrorKind::Verify,
288 "Wrong password for that key",
289 ))
290 }
291 } else {
292 Ok(sk)
293 }
294 }
295
296 pub fn from_box(sk_box: SecretKeyBox, password: Option<String>) -> Result<SecretKey> {
299 Self::from_box_(sk_box, password, false)
300 }
301
302 pub fn from_unencrypted_box(sk_box: SecretKeyBox) -> Result<SecretKey> {
304 Self::from_box_(sk_box, None, true)
305 }
306
307 pub fn to_box(&self, comment: Option<&str>) -> Result<SecretKeyBox> {
309 let mut s = String::new();
310 write!(s, "{COMMENT_PREFIX}")?;
311 if let Some(comment) = comment {
312 writeln!(s, "{comment}")?;
313 } else {
314 writeln!(s, "{SECRETKEY_DEFAULT_COMMENT}")?;
315 }
316 writeln!(s, "{}", self.to_base64())?;
317 Ok(s.into())
318 }
319
320 pub(crate) fn from_base64(s: &str) -> Result<SecretKey> {
321 let bytes = Base64::decode_to_vec(s, None)?;
322 SecretKey::from_bytes(&bytes[..])
323 }
324
325 pub(crate) fn to_base64(&self) -> String {
326 Base64::encode_to_string(self.to_bytes().as_slice()).unwrap()
327 }
328
329 pub fn from_file<P: AsRef<Path>>(sk_path: P, password: Option<String>) -> Result<SecretKey> {
331 let s = fs::read_to_string(sk_path)?;
332 SecretKey::from_box(s.into(), password)
333 }
334}
335
336impl fmt::Debug for SecretKey {
337 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
338 for byte in self.keynum_sk.sk.iter() {
339 write!(f, "{byte:x}")?
340 }
341 Ok(())
342 }
343}
344
345impl cmp::PartialEq for SecretKey {
346 fn eq(&self, other: &SecretKey) -> bool {
347 fixed_time_eq(&self.keynum_sk.sk, &other.keynum_sk.sk)
348 }
349}
350impl cmp::Eq for SecretKey {}