From cfa66dabaf56038baab8589047d21fe73e97aa7a Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 12 Feb 2023 14:42:50 +0800 Subject: [PATCH] feat: add file --- src/crypto.rs | 13 +++++----- src/file.rs | 39 +++++++++++++++++++++++++++++ src/main.rs | 3 +++ src/spec.rs | 69 +++++++++++++++++++++++++++++---------------------- 4 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 src/file.rs diff --git a/src/crypto.rs b/src/crypto.rs index 458599e..473cfba 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -1,12 +1,8 @@ -use aes_gcm::{Aes256Gcm, AesGcm, Key, KeyInit, Nonce}; -use aes_gcm::aead::{Aead, AeadMut, OsRng}; -use aes_gcm::aead::generic_array::GenericArray; -use aes_gcm::aes::{Aes256, Aes256Enc}; -use aes_gcm::aes::cipher::{Block, BlockEncrypt, BlockEncryptMut, Iv}; -use aes_gcm::aes::cipher::inout::{InOut, InOutBuf}; - #[test] fn test_aes_gcm_01() { + use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce}; + use aes_gcm::aead::{Aead}; + let data_key = hex::decode("0001020304050607080910111213141516171819202122232425262728293031").unwrap(); let nonce = hex::decode("000102030405060708091011").unwrap(); @@ -32,6 +28,9 @@ fn test_aes_gcm_01() { #[test] fn test_aes_gcm_02() { + use aes_gcm::{Aes256Gcm, Key, KeyInit, Nonce}; + use aes_gcm::aead::{Aead}; + let data_key = hex::decode("aa01020304050607080910111213141516171819202122232425262728293031").unwrap(); let nonce = hex::decode("aa0102030405060708091011").unwrap(); diff --git a/src/file.rs b/src/file.rs new file mode 100644 index 0000000..078b6d9 --- /dev/null +++ b/src/file.rs @@ -0,0 +1,39 @@ +use std::fs::File; +use std::io::{Read, Write}; + +use rust_util::{opt_result, simple_error, XResult}; + +use crate::spec::TinyEncryptMeta; + +fn write_tiny_encrypt_meta(w: &mut W, meta: &TinyEncryptMeta) -> XResult { + let meta_json = opt_result!( serde_json::to_string(meta), "Meta to JSON failed: {}"); + let meta_json_bytes = meta_json.as_bytes(); + let meta_json_bytes_len = meta_json_bytes.len(); + + opt_result!(w.write_all(&((0x01) as u16).to_be_bytes()), "Write tag failed: {}"); + opt_result!(w.write_all(&(meta_json_bytes_len as u32).to_be_bytes()), "Write length failed: {}"); + opt_result!(w.write_all(&meta_json_bytes), "Write meta failed: {}"); + + Ok(meta_json_bytes_len + 2 + 4) +} + +fn read_tiny_encrypt_meta(r: &mut R) -> XResult { + let mut tag_buff = [0_u8; 2]; + opt_result!(r.read_exact(&mut tag_buff), "Read tag failed: {}"); + let tag = u16::from_be_bytes(tag_buff); + if tag != 0x01 { + return simple_error!("Tag is not 0x01, but is: 0x{:x}", tag); + } + + let mut length_buff = [0_u8; 4]; + opt_result!(r.read_exact(&mut length_buff), "Read length failed: {}"); + let length = u32::from_be_bytes(length_buff); + if length > 1024 * 1024 { + return simple_error!("Meta too large: {}", length); + } + + let mut meta_buff = Vec::with_capacity(length as usize); + opt_result!( r.read_exact(meta_buff.as_mut_slice()), "Read meta failed: {}"); + + Ok(opt_result!(serde_json::from_slice(&meta_buff), "Parse meta failed: {}")) +} diff --git a/src/main.rs b/src/main.rs index 5891ac3..1ee32ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +extern crate core; + use std::path::PathBuf; use clap::{Parser, Subcommand}; @@ -5,6 +7,7 @@ use rust_util::information; mod spec; mod crypto; +mod file; #[derive(Debug, Parser)] #[command(name = "tiny-encrypt-rs")] diff --git a/src/spec.rs b/src/spec.rs index 41ea6db..54bd6e6 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -1,37 +1,46 @@ use serde::{Deserialize, Serialize}; -// File format -// [MAGIC; 4 bytes][VERSION; 1 byte] -// [META_LENGTH; 4 bytes] -// [META; META_LENGTH bytes] -// [ENCRYPTED DATA; n bytes] - -pub const EXT: &'static str = "ers"; -pub const MAGIC: u16 = 0xECF0; - -pub const VERSION_1: u8 = 0x01; +pub const TINY_ENCRYPT_VERSION: &'static str = "1.0"; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MetaBock { - pub meta_random_hex: String, - pub desc: Option, - pub encrypted_desc: String, - pub keys: Vec, - pub iv_nonce_hex: String, +#[serde(rename_all = "camelCase")] +pub struct TinyEncryptMeta { + pub version: String, + pub created: u64, + pub user_agent: String, + pub comment: Option, + pub encrypted_comment: Option, + pub pgp_envelop: Option, + pub pgp_fingerprint: Option, + pub envelop: Option, + pub nonce: String, + pub file_length: u64, + pub file_last_modified: u64, + pub compress: Option, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct DescBlock { - pub file_id: Option, - pub author: Option, - pub description: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KeyBlock { - pub key_type: String, - pub key_id: Option, - pub encrypted_key_hex: String, - pub key_verification_code_hex: String, - pub extended_information: Option, +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