diff --git a/src/cmd_decrypt.rs b/src/cmd_decrypt.rs index da77edc..b62fd63 100644 --- a/src/cmd_decrypt.rs +++ b/src/cmd_decrypt.rs @@ -11,7 +11,10 @@ use crate::file; pub fn decrypt(path: PathBuf, pin: &Option) -> XResult<()> { let path_display = format!("{}", path.display()); let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display); - let meta = opt_result!(file::read_tiny_encrypt_meta(&mut file_in), "Read file: {}, failed: {}", &path_display); + let mut meta = opt_result!(file::read_tiny_encrypt_meta(&mut file_in), "Read file: {}, failed: {}", &path_display); + meta.normalize(); + + debugging!("Found meta: {}", serde_json::to_string_pretty(&meta).unwrap()); let mut card = match get_card() { Err(e) => { diff --git a/src/cmd_info.rs b/src/cmd_info.rs index 4b9bc8e..794eb20 100644 --- a/src/cmd_info.rs +++ b/src/cmd_info.rs @@ -3,13 +3,14 @@ use std::fs::File; use std::ops::Add; use std::path::PathBuf; use std::time::{Duration, SystemTime}; -use rust_util::{information, opt_result, simple_error, success, XResult}; +use rust_util::{iff, information, opt_result, simple_error, success, XResult}; use crate::file; pub fn info(path: PathBuf, raw_meta: bool) -> XResult<()> { let path_display = format!("{}", path.display()); let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display); - let meta = opt_result!(file::read_tiny_encrypt_meta(&mut file_in), "Read file: {}, failed: {}", &path_display); + let mut meta = opt_result!(file::read_tiny_encrypt_meta(&mut file_in), "Read file: {}, failed: {}", &path_display); + meta.normalize(); if raw_meta { success!("Meta data:\n{}", serde_json::to_string_pretty(&meta).expect("SHOULD NOT HAPPEN")); @@ -29,11 +30,14 @@ pub fn info(path: PathBuf, raw_meta: bool) -> XResult<()> { infos.push(format!("{}: {}", header("Last modified"), fmt.format_local(from_unix_epoch(meta.file_last_modified)))); infos.push(format!("{}: {}", header("Enc file created"), fmt.format_local(from_unix_epoch(meta.created)))); - infos.push(format!("{}: KMS: {}, PGP: {}", - header("Envelops"), - to_yes_or_no(&meta.envelop), - to_yes_or_no(&meta.pgp_envelop) - )); + meta.envelops.as_ref().map(|envelops| envelops.iter().enumerate().for_each(|(i, envelop)| { + infos.push(format!("{}: {}{}{}", + header(&format!("Envelop #{}", i + 1)), + envelop.r#type.to_uppercase(), + iff!(envelop.kid.is_empty(), "".into(), format!(", Kid: {}", envelop.kid)), + iff!(envelop.desc.is_none(), "".into(), format!(", Desc: {}", envelop.desc.as_ref().unwrap())) + )); + })); meta.pgp_fingerprint.map(|fingerprint| { infos.push(format!("{}: {}", header("PGP fingerprint"), fingerprint)); }); @@ -41,6 +45,13 @@ pub fn info(path: PathBuf, raw_meta: bool) -> XResult<()> { infos.push(format!("{}: {}", header("Comment"), comment)); }); infos.push(format!("{}: {}", header("Encrypted comment"), to_yes_or_no(&meta.encrypted_comment))); + infos.push(format!("{}: {}", header("Encrypted meta"), to_yes_or_no(&meta.encrypted_meta))); + let encryption_algorithm = if let Some(encryption_algorithm) = &meta.encryption_algorithm { + encryption_algorithm.to_string() + } else { + "AES/GCM (default)".to_string() + }; + infos.push(format!("{}: {}", header("Encryption algorithm"), encryption_algorithm)); success!("{}\n", infos.join("\n")); Ok(()) @@ -51,7 +62,7 @@ fn from_unix_epoch(t: u64) -> SystemTime { } fn header(h: &str) -> String { - let width = 18; + let width = 21; h.to_string() + ".".repeat(max(width - h.len(), 0)).as_str() } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..00de0b4 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TinyEncryptConfig { + // card cli is not used by tiny-encrypt-rs + pub card_cli: String, + pub default_key_name: String, + pub local_private_key_pem_challenge: String, + pub local_private_key_pem_encrypted: String, + pub local_public_key_pem: String, + pub pgp_encrypt_public_key_pem: Option, +} diff --git a/src/main.rs b/src/main.rs index 5bad060..3a52f4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; use rust_util::{information, XResult}; +mod util; +mod config; mod spec; mod crypto; mod file; diff --git a/src/spec.rs b/src/spec.rs index 8528776..3abc1a5 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -2,18 +2,6 @@ use serde::{Deserialize, Serialize}; pub const TINY_ENCRYPT_VERSION: &'static str = "1.0"; -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TinyEncryptConfig { - // card cli is not used by tiny-encrypt-rs - pub card_cli: String, - pub default_key_name: String, - pub local_private_key_pem_challenge: String, - pub local_private_key_pem_encrypted: String, - pub local_public_key_pem: String, - pub pgp_encrypt_public_key_pem: Option, -} - /// Specification: [Tiny Encrypt Spec V1.1](https://git.hatter.ink/hatter/tiny-encrypt-java/src/branch/master/TinyEncryptSpecV1.1.md) #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -33,7 +21,7 @@ pub struct TinyEncryptMeta { pub ecdh_point: Option, pub envelop: Option, // --------------------------------------- - pub envelops: Vec, + pub envelops: Option>, pub encryption_algorithm: Option, pub nonce: String, pub file_length: u64, @@ -60,6 +48,9 @@ pub enum TinyEncryptEnvelopType { impl TinyEncryptMeta { pub fn normalize(&mut self) { + if self.envelops.is_none() { + self.envelops = Some(vec![]); + } self.normalize_ppg_envelop(); self.normalize_age_envelop(); self.normalize_ecdh_envelop(); @@ -67,8 +58,9 @@ impl TinyEncryptMeta { } fn normalize_ppg_envelop(&mut self) { - if let (Some(pgp_envelop), Some(pgp_fingerprint)) = (&self.pgp_envelop, &self.pgp_fingerprint) { - self.envelops.push(TinyEncryptEnvelop { + if let (Some(pgp_envelop), Some(pgp_fingerprint), Some(envelops)) + = (&self.pgp_envelop, &self.pgp_fingerprint, &mut self.envelops) { + envelops.push(TinyEncryptEnvelop { r#type: "pgp".to_string(), kid: pgp_fingerprint.into(), desc: None, @@ -80,8 +72,9 @@ impl TinyEncryptMeta { } fn normalize_age_envelop(&mut self) { - if let (Some(age_envelop), Some(age_recipient)) = (&self.age_envelop, &self.age_recipient) { - self.envelops.push(TinyEncryptEnvelop { + if let (Some(age_envelop), Some(age_recipient), Some(envelops)) + = (&self.age_envelop, &self.age_recipient, &mut self.envelops) { + envelops.push(TinyEncryptEnvelop { r#type: "age".to_string(), kid: age_recipient.into(), desc: None, @@ -93,8 +86,9 @@ impl TinyEncryptMeta { } fn normalize_ecdh_envelop(&mut self) { - if let (Some(ecdh_envelop), Some(ecdh_point)) = (&self.ecdh_envelop, &self.ecdh_point) { - self.envelops.push(TinyEncryptEnvelop { + if let (Some(ecdh_envelop), Some(ecdh_point), Some(envelops)) + = (&self.ecdh_envelop, &self.ecdh_point, &mut self.envelops) { + envelops.push(TinyEncryptEnvelop { r#type: "ecdh".to_string(), kid: ecdh_point.into(), desc: None, @@ -106,10 +100,10 @@ impl TinyEncryptMeta { } fn normalize_envelop(&mut self) { - if let Some(envelop) = &self.envelop { - self.envelops.push(TinyEncryptEnvelop { + if let (Some(envelop), Some(envelops)) = (&self.envelop, &mut self.envelops) { + envelops.push(TinyEncryptEnvelop { r#type: "kms".to_string(), - kid: "#default".into(), + kid: "".into(), desc: None, encrypted_key: envelop.into(), }); @@ -117,29 +111,3 @@ impl TinyEncryptMeta { } } } - -pub fn get_user_agent() -> String { - format!("TinyEncrypt-rs v{}@{}", env!("CARGO_PKG_VERSION"), - if cfg!(target_os = "macos") { - "MacOS" - } else if cfg!(target_os = "ios") { - "iOS" - } else if cfg!(target_os = "android") { - "Android" - } else if cfg!(target_os = "windows") { - "Windows" - } else if cfg!(target_os = "linux") { - "Linux" - } else if cfg!(target_os = "freebsd") { - "FreeBSD" - } else if cfg!(target_os = "dragonfly") { - "Dragonfly" - } else if cfg!(target_os = "openbsd") { - "OpenBSD" - } else if cfg!(target_os = "netbsd") { - "NetBSD" - } else { - panic!("Unsupported OS!"); - } - ) -} \ No newline at end of file diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..86b9796 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,26 @@ + +pub fn get_user_agent() -> String { + format!("TinyEncrypt-rs v{}@{}", env!("CARGO_PKG_VERSION"), + if cfg!(target_os = "macos") { + "MacOS" + } else if cfg!(target_os = "ios") { + "iOS" + } else if cfg!(target_os = "android") { + "Android" + } else if cfg!(target_os = "windows") { + "Windows" + } else if cfg!(target_os = "linux") { + "Linux" + } else if cfg!(target_os = "freebsd") { + "FreeBSD" + } else if cfg!(target_os = "dragonfly") { + "Dragonfly" + } else if cfg!(target_os = "openbsd") { + "OpenBSD" + } else if cfg!(target_os = "netbsd") { + "NetBSD" + } else { + panic!("Unsupported OS!"); + } + ) +} \ No newline at end of file