feat: v0.5.4, many updates
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -377,9 +377,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.10"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4"
|
||||
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -1334,16 +1334,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8"
|
||||
checksum = "86ef35bf3e7fe15a53c4ab08a998e42271eab13eb0db224126bc7bc4c4bad96d"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"const-oid",
|
||||
"digest",
|
||||
"num-bigint-dig",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-traits",
|
||||
"pkcs1",
|
||||
"pkcs8",
|
||||
@@ -1416,9 +1414,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.20"
|
||||
version = "0.38.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
@@ -1470,18 +1468,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.189"
|
||||
version = "1.0.190"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
|
||||
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.189"
|
||||
version = "1.0.190"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
|
||||
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1729,7 +1727,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tiny-encrypt"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
dependencies = [
|
||||
"aes-gcm-stream",
|
||||
"base64",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tiny-encrypt"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "A simple and tiny file encrypt tool"
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::consts::{
|
||||
ENC_CHACHA20_POLY1305_P256, ENC_CHACHA20_POLY1305_P384, ENC_CHACHA20_POLY1305_X25519,
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
use crate::spec::{EncEncryptedMeta, TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta};
|
||||
use crate::util::SecVec;
|
||||
use crate::util_digest::DigestWrite;
|
||||
@@ -114,7 +114,7 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
util::require_tiny_enc_file_and_exists(path)?;
|
||||
|
||||
let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display);
|
||||
let meta = opt_result!(
|
||||
let (_, meta) = opt_result!(
|
||||
util_enc_file::read_tiny_encrypt_meta_and_normalize(&mut file_in), "Read file: {}, failed: {}", &path_display);
|
||||
debugging!("Found meta: {}", serde_json::to_string_pretty(&meta).unwrap());
|
||||
|
||||
@@ -136,12 +136,13 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
|
||||
let key = SecVec(try_decrypt_key(config, selected_envelop, pin, slot)?);
|
||||
let nonce = SecVec(opt_result!(util::decode_base64(&meta.nonce), "Decode nonce failed: {}"));
|
||||
let key_nonce = KeyNonce { k: &key.0, n: &nonce.0 };
|
||||
|
||||
// debugging!("Decrypt key: {}", hex::encode(&key.0));
|
||||
debugging!("Decrypt nonce: {}", hex::encode(&nonce.0));
|
||||
|
||||
let enc_meta = parse_encrypted_meta(&meta, cryptor, &key.0, &nonce.0)?;
|
||||
parse_encrypted_comment(&meta, cryptor, &key.0, &nonce.0)?;
|
||||
let enc_meta = parse_encrypted_meta(&meta, cryptor, &key_nonce)?;
|
||||
parse_encrypted_comment(&meta, cryptor, &key_nonce)?;
|
||||
|
||||
// Decrypt to output
|
||||
if cmd_decrypt.direct_print {
|
||||
@@ -152,7 +153,7 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
|
||||
let mut output: Vec<u8> = Vec::with_capacity(10 * 1024);
|
||||
let _ = decrypt_file(
|
||||
&mut file_in, meta.file_length, &mut output, cryptor, &key.0, &nonce.0, meta.compress,
|
||||
&mut file_in, meta.file_length, &mut output, cryptor, &key_nonce, meta.compress,
|
||||
)?;
|
||||
match String::from_utf8(output) {
|
||||
Err(_) => warning!("File is not UTF-8 content."),
|
||||
@@ -169,7 +170,7 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
if cmd_decrypt.digest_file {
|
||||
let mut digest_write = DigestWrite::from_algo(digest_algorithm)?;
|
||||
let _ = decrypt_file(
|
||||
&mut file_in, meta.file_length, &mut digest_write, cryptor, &key.0, &nonce.0, meta.compress,
|
||||
&mut file_in, meta.file_length, &mut digest_write, cryptor, &key_nonce, meta.compress,
|
||||
)?;
|
||||
let digest = digest_write.digest();
|
||||
success!("File digest {}: {}", digest_algorithm.to_uppercase(), hex::encode(digest));
|
||||
@@ -187,7 +188,7 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
|
||||
let mut file_out = File::create(path_out)?;
|
||||
let _ = decrypt_file(
|
||||
&mut file_in, meta.file_length, &mut file_out, cryptor, &key.0, &nonce.0, meta.compress,
|
||||
&mut file_in, meta.file_length, &mut file_out, cryptor, &key_nonce, meta.compress,
|
||||
)?;
|
||||
drop(file_out);
|
||||
util_file::update_out_file_time(enc_meta, path_out);
|
||||
@@ -200,11 +201,11 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
}
|
||||
|
||||
fn decrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write,
|
||||
cryptor: Cryptor, key: &[u8], nonce: &[u8], compress: bool) -> XResult<u64> {
|
||||
cryptor: Cryptor, key_nonce: &KeyNonce, compress: bool) -> XResult<u64> {
|
||||
let mut total_len = 0_u64;
|
||||
let mut buffer = [0u8; 1024 * 8];
|
||||
let progress = Progress::new(file_len);
|
||||
let mut decryptor = cryptor.decryptor(key, nonce)?;
|
||||
let mut decryptor = cryptor.decryptor(key_nonce)?;
|
||||
let mut gz_decoder = GzStreamDecoder::new();
|
||||
loop {
|
||||
let len = opt_result!(file_in.read(&mut buffer), "Read file failed: {}");
|
||||
@@ -237,11 +238,11 @@ fn decrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write,
|
||||
Ok(total_len)
|
||||
}
|
||||
|
||||
fn parse_encrypted_comment(meta: &TinyEncryptMeta, crypto: Cryptor, key: &[u8], nonce: &[u8]) -> XResult<()> {
|
||||
fn parse_encrypted_comment(meta: &TinyEncryptMeta, crypto: Cryptor, key_nonce: &KeyNonce) -> XResult<()> {
|
||||
if let Some(encrypted_comment) = &meta.encrypted_comment {
|
||||
match util::decode_base64(encrypted_comment) {
|
||||
Err(e) => warning!("Decode encrypted comment failed: {}", e),
|
||||
Ok(ec_bytes) => match crypto_simple::try_decrypt_with_salt(crypto, key, nonce, SALT_COMMENT, &ec_bytes) {
|
||||
Ok(ec_bytes) => match crypto_simple::try_decrypt_with_salt(crypto, key_nonce, SALT_COMMENT, &ec_bytes) {
|
||||
Err(e) => warning!("Decrypt encrypted comment failed: {}", e),
|
||||
Ok(decrypted_comment_bytes) => match String::from_utf8(decrypted_comment_bytes.clone()) {
|
||||
Err(_) => success!("Encrypted message hex: {}", hex::encode(&decrypted_comment_bytes)),
|
||||
@@ -253,7 +254,7 @@ fn parse_encrypted_comment(meta: &TinyEncryptMeta, crypto: Cryptor, key: &[u8],
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_encrypted_meta(meta: &TinyEncryptMeta, cryptor: Cryptor, key: &[u8], nonce: &[u8]) -> XResult<Option<EncEncryptedMeta>> {
|
||||
fn parse_encrypted_meta(meta: &TinyEncryptMeta, cryptor: Cryptor, key_nonce: &KeyNonce) -> XResult<Option<EncEncryptedMeta>> {
|
||||
let enc_encrypted_meta = match &meta.encrypted_meta {
|
||||
None => return Ok(None),
|
||||
Some(enc_encrypted_meta) => enc_encrypted_meta,
|
||||
@@ -261,7 +262,7 @@ fn parse_encrypted_meta(meta: &TinyEncryptMeta, cryptor: Cryptor, key: &[u8], no
|
||||
let enc_encrypted_meta_bytes = opt_result!(
|
||||
util::decode_base64(enc_encrypted_meta), "Decode enc-encrypted-meta failed: {}");
|
||||
let enc_meta = opt_result!(
|
||||
EncEncryptedMeta::unseal(cryptor, key, nonce, &enc_encrypted_meta_bytes), "Unseal enc-encrypted-meta failed: {}");
|
||||
EncEncryptedMeta::unseal(cryptor, key_nonce, &enc_encrypted_meta_bytes), "Unseal enc-encrypted-meta failed: {}");
|
||||
debugging!("Encrypted meta: {:?}", enc_meta);
|
||||
if let Some(filename) = &enc_meta.filename {
|
||||
information!("Source filename: {}", filename);
|
||||
@@ -320,8 +321,9 @@ fn try_decrypt_key_ecdh(config: &Option<TinyEncryptConfig>,
|
||||
slot_id,
|
||||
), "Decrypt via PIV card failed: {}");
|
||||
let key = util::simple_kdf(shared_secret.as_slice());
|
||||
let key_nonce = KeyNonce { k: &key, n: &wrap_key.nonce };
|
||||
let decrypted_key = crypto_simple::decrypt(
|
||||
cryptor, &key, &wrap_key.nonce, &wrap_key.encrypted_data)?;
|
||||
cryptor, &key_nonce, &wrap_key.encrypted_data)?;
|
||||
util::zeroize(pin);
|
||||
util::zeroize(key);
|
||||
util::zeroize(shared_secret);
|
||||
@@ -346,8 +348,9 @@ fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option<St
|
||||
let shared_secret = trans.decipher(Cryptogram::ECDH(&epk_bytes))?;
|
||||
|
||||
let key = util::simple_kdf(shared_secret.as_slice());
|
||||
let key_nonce = KeyNonce { k: &key, n: &wrap_key.nonce };
|
||||
let decrypted_key = crypto_simple::decrypt(
|
||||
cryptor, &key, &wrap_key.nonce, &wrap_key.encrypted_data)?;
|
||||
cryptor, &key_nonce, &wrap_key.encrypted_data)?;
|
||||
util::zeroize(key);
|
||||
util::zeroize(shared_secret);
|
||||
Ok(decrypted_key)
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::consts::{
|
||||
ENC_CHACHA20_POLY1305_P256, ENC_CHACHA20_POLY1305_P384, ENC_CHACHA20_POLY1305_X25519,
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
use crate::crypto_rsa;
|
||||
use crate::spec::{
|
||||
EncEncryptedMeta, EncMetadata, TINY_ENCRYPT_VERSION_10,
|
||||
@@ -112,7 +112,13 @@ pub fn encrypt(cmd_encrypt: CmdEncrypt) -> XResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_encrypt: &CmdEncrypt) -> XResult<u64> {
|
||||
pub fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_encrypt: &CmdEncrypt) -> XResult<u64> {
|
||||
let path_display = format!("{}", path.display());
|
||||
let path_out = format!("{}{}", path_display, TINY_ENC_FILE_EXT);
|
||||
encrypt_single_file_out(path, &path_out, envelops, cmd_encrypt)
|
||||
}
|
||||
|
||||
pub fn encrypt_single_file_out(path: &PathBuf, path_out: &str, envelops: &[&TinyEncryptConfigEnvelop], cmd_encrypt: &CmdEncrypt) -> XResult<u64> {
|
||||
let path_display = format!("{}", path.display());
|
||||
if path_display.ends_with(TINY_ENC_FILE_EXT) {
|
||||
information!("Tiny enc file skipped: {}", path_display);
|
||||
@@ -126,17 +132,17 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
|
||||
let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display);
|
||||
|
||||
let path_out = format!("{}{}", path_display, TINY_ENC_FILE_EXT);
|
||||
util::require_file_not_exists(path_out.as_str())?;
|
||||
util::require_file_not_exists(path_out)?;
|
||||
|
||||
let (key, nonce) = util::make_key256_and_nonce();
|
||||
let key_nonce = KeyNonce { k: &key.0, n: &nonce.0 };
|
||||
let envelops = encrypt_envelops(cryptor, &key.0, envelops)?;
|
||||
|
||||
let encrypted_comment = match &cmd_encrypt.encrypted_comment {
|
||||
None => None,
|
||||
Some(encrypted_comment) => Some(util::encode_base64(
|
||||
&crypto_simple::encrypt_with_salt(
|
||||
cryptor, &key.0, &nonce.0, SALT_COMMENT, encrypted_comment.as_bytes())?))
|
||||
cryptor, &key_nonce, SALT_COMMENT, encrypted_comment.as_bytes())?))
|
||||
};
|
||||
|
||||
let file_metadata = opt_result!(fs::metadata(path), "Read file: {} meta failed: {}", path.display());
|
||||
@@ -146,7 +152,7 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
m_time: file_metadata.modified().ok().and_then(|t| t.to_millis()),
|
||||
};
|
||||
let enc_encrypted_meta_bytes = opt_result!(enc_encrypted_meta.seal(
|
||||
cryptor, &key.0, &nonce.0), "Seal enc-encrypted-meta failed: {}");
|
||||
cryptor, &key_nonce), "Seal enc-encrypted-meta failed: {}");
|
||||
|
||||
let enc_metadata = EncMetadata {
|
||||
comment: cmd_encrypt.comment.clone(),
|
||||
@@ -172,7 +178,7 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
}
|
||||
}
|
||||
|
||||
let mut file_out = File::create(&path_out)?;
|
||||
let mut file_out = File::create(path_out)?;
|
||||
let compress_meta = !cmd_encrypt.disable_compress_meta;
|
||||
let _ = util_enc_file::write_tiny_encrypt_meta(&mut file_out, &encrypt_meta, compress_meta)?;
|
||||
|
||||
@@ -183,7 +189,7 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
let start = Instant::now();
|
||||
encrypt_file(
|
||||
&mut file_in, file_metadata.len(), &mut file_out, cryptor,
|
||||
&key.0, &nonce.0, &compress_level,
|
||||
&key_nonce, &compress_level,
|
||||
)?;
|
||||
drop(file_out);
|
||||
let encrypt_duration = start.elapsed();
|
||||
@@ -216,7 +222,7 @@ fn process_compatible_with_1_0(mut encrypt_meta: TinyEncryptMeta) -> XResult<Tin
|
||||
}
|
||||
|
||||
fn encrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write, cryptor: Cryptor,
|
||||
key: &[u8], nonce: &[u8], compress_level: &Option<u32>) -> XResult<u64> {
|
||||
key_nonce: &KeyNonce, compress_level: &Option<u32>) -> XResult<u64> {
|
||||
let compress = compress_level.is_some();
|
||||
let mut total_len = 0_u64;
|
||||
let mut write_len = 0_u64;
|
||||
@@ -231,7 +237,7 @@ fn encrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write, cr
|
||||
}
|
||||
};
|
||||
let progress = Progress::new(file_len);
|
||||
let mut encryptor = cryptor.encryptor(key, nonce)?;
|
||||
let mut encryptor = cryptor.encryptor(key_nonce)?;
|
||||
loop {
|
||||
let len = opt_result!(file_in.read(&mut buffer), "Read file failed: {}");
|
||||
if len == 0 {
|
||||
@@ -334,9 +340,10 @@ fn encrypt_envelop_shared_secret(cryptor: Cryptor,
|
||||
envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
|
||||
let shared_key = util::simple_kdf(shared_secret);
|
||||
let nonce = util::make_nonce();
|
||||
let key_nonce = KeyNonce { k: &shared_key, n: &nonce.0 };
|
||||
|
||||
let encrypted_key = crypto_simple::encrypt(
|
||||
cryptor, &shared_key, &nonce.0, key)?;
|
||||
cryptor, &key_nonce, key)?;
|
||||
|
||||
let wrap_key = WrapKey {
|
||||
header: WrapKeyHeader {
|
||||
|
||||
@@ -4,13 +4,15 @@ use std::path::PathBuf;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use clap::Args;
|
||||
use rust_util::{opt_result, simple_error, success, util_time, warning, XResult};
|
||||
use rust_util::{debugging, failure, iff, opt_result, simple_error, success, util_msg, util_size, util_time, XResult};
|
||||
use rust_util::util_msg::MessageType;
|
||||
use rust_util::util_time::UnixEpochTime;
|
||||
use simpledateformat::format_human2;
|
||||
|
||||
use crate::{util_enc_file, util_envelop};
|
||||
use crate::{util, util_enc_file, util_envelop};
|
||||
use crate::config::TinyEncryptConfig;
|
||||
use crate::consts::{DATE_TIME_FORMAT, TINY_ENC_AES_GCM, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT};
|
||||
use crate::wrap_key::WrapKey;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct CmdInfo {
|
||||
@@ -25,7 +27,7 @@ pub fn info(cmd_info: CmdInfo) -> XResult<()> {
|
||||
for (i, path) in cmd_info.paths.iter().enumerate() {
|
||||
if i > 0 { println!("{}", "-".repeat(88)); }
|
||||
if let Err(e) = info_single(path, &cmd_info) {
|
||||
warning!("Parse Tiny Encrypt file info failed: {}", e);
|
||||
failure!("Parse Tiny Encrypt file info failed: {}", e);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
@@ -40,7 +42,9 @@ pub fn info_single(path: &PathBuf, cmd_info: &CmdInfo) -> XResult<()> {
|
||||
|
||||
let config = TinyEncryptConfig::load(TINY_ENC_CONFIG_FILE).ok();
|
||||
let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display);
|
||||
let meta = opt_result!(
|
||||
let file_in_len = file_in.metadata().map(|m| m.len()).unwrap_or(0);
|
||||
|
||||
let (meta_len, meta) = opt_result!(
|
||||
util_enc_file::read_tiny_encrypt_meta_and_normalize(&mut file_in), "Read file: {}, failed: {}", &path_display
|
||||
);
|
||||
|
||||
@@ -53,7 +57,20 @@ pub fn info_single(path: &PathBuf, cmd_info: &CmdInfo) -> XResult<()> {
|
||||
infos.push("Tiny Encrypt File Info".to_string());
|
||||
let compressed = if meta.compress { " [compressed]" } else { "" };
|
||||
infos.push(format!("{}: {}{}", header("File name"), path_display, compressed));
|
||||
infos.push(format!("{}: {} bytes", header("File size"), meta.file_length));
|
||||
|
||||
if meta.compress && file_in_len > (2 + 4 + meta_len as u64) {
|
||||
let actual_file_in_len = file_in_len - 2 - 4 - meta_len as u64;
|
||||
infos.push(format!("{}: {}, after compressed {}, ratio: {}%",
|
||||
header("File size"),
|
||||
util_size::get_display_size(meta.file_length as i64),
|
||||
util_size::get_display_size(actual_file_in_len as i64),
|
||||
util::ratio(actual_file_in_len, meta.file_length)
|
||||
));
|
||||
} else {
|
||||
infos.push(format!("{}: {}", header("File size"),
|
||||
util_size::get_display_size(meta.file_length as i64)));
|
||||
}
|
||||
|
||||
infos.push(format!("{}: Version: {}, Agent: {}",
|
||||
header("File summary"), meta.version, meta.user_agent)
|
||||
);
|
||||
@@ -77,6 +94,11 @@ pub fn info_single(path: &PathBuf, cmd_info: &CmdInfo) -> XResult<()> {
|
||||
header(&format!("Envelop #{}", i + 1)),
|
||||
util_envelop::format_envelop(envelop, &config)
|
||||
));
|
||||
util_msg::when(MessageType::DEBUG, || {
|
||||
if let Ok(wrap_key) = WrapKey::parse(&envelop.encrypted_key) {
|
||||
debugging!("Wrap key: {}", serde_json::to_string(&wrap_key).expect("SHOULD NOT HAPPEN"));
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@@ -105,5 +127,5 @@ fn header(h: &str) -> String {
|
||||
}
|
||||
|
||||
fn to_yes_or_no(opt: &Option<String>) -> String {
|
||||
opt.as_ref().map(|_| "YES".to_string()).unwrap_or_else(|| "NO".to_string())
|
||||
iff!(opt.is_some(), "YES", "NO").to_string()
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use clap::Args;
|
||||
use rust_util::XResult;
|
||||
|
||||
use crate::util;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
|
||||
@@ -4,6 +4,10 @@ use flate2::Compression;
|
||||
use flate2::write::{GzDecoder, GzEncoder};
|
||||
use rust_util::{simple_error, XResult};
|
||||
|
||||
pub fn compress_default(message: &[u8]) -> XResult<Vec<u8>> {
|
||||
compress(Compression::default(), message)
|
||||
}
|
||||
|
||||
pub fn compress(compression: Compression, message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let mut encoder = GzStreamEncoder::new(compression);
|
||||
let mut buff = encoder.update(message)?;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
use rust_util::{debugging, iff, opt_result, simple_error, XResult};
|
||||
use rust_util::{debugging, opt_result, simple_error, XResult};
|
||||
use rust_util::util_file::resolve_file_path;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -57,20 +57,20 @@ impl TinyEncryptConfig {
|
||||
);
|
||||
let mut config: TinyEncryptConfig = opt_result!(
|
||||
serde_json::from_str(&config_contents),"Parse file: {}, failed: {}", file);
|
||||
let mut splitted_profiles = HashMap::new();
|
||||
let mut splited_profiles = HashMap::new();
|
||||
for (k, v) in config.profiles.into_iter() {
|
||||
if !k.contains(',') {
|
||||
splitted_profiles.insert(k, v);
|
||||
splited_profiles.insert(k, v);
|
||||
} else {
|
||||
k.split(',')
|
||||
.map(|k| k.trim())
|
||||
.filter(|k| !k.is_empty())
|
||||
.for_each(|k| {
|
||||
splitted_profiles.insert(k.to_string(), v.clone());
|
||||
splited_profiles.insert(k.to_string(), v.clone());
|
||||
});
|
||||
}
|
||||
}
|
||||
config.profiles = splitted_profiles;
|
||||
config.profiles = splited_profiles;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ impl TinyEncryptConfig {
|
||||
|
||||
pub fn find_by_kid(&self, kid: &str) -> Option<&TinyEncryptConfigEnvelop> {
|
||||
let config_envelops = self.find_by_kid_or_filter(kid, |_| false);
|
||||
iff!(config_envelops.is_empty(), None, Some(config_envelops[0]))
|
||||
config_envelops.first().map(|e| *e)
|
||||
}
|
||||
|
||||
pub fn find_by_kid_or_type(&self, k_filter: &str) -> Vec<&TinyEncryptConfigEnvelop> {
|
||||
|
||||
@@ -5,6 +5,12 @@ use zeroize::Zeroize;
|
||||
|
||||
use crate::{consts, util_env};
|
||||
|
||||
pub struct KeyNonce<'a, 'b> {
|
||||
pub k: &'a [u8],
|
||||
pub n: &'b [u8],
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Cryptor {
|
||||
Aes256Gcm,
|
||||
@@ -28,12 +34,12 @@ impl Cryptor {
|
||||
name.to_string()
|
||||
}
|
||||
|
||||
pub fn encryptor(self, key: &[u8], nonce: &[u8]) -> XResult<Box<dyn Encryptor>> {
|
||||
get_encryptor(self, key, nonce)
|
||||
pub fn encryptor(self, key_nonce: &KeyNonce) -> XResult<Box<dyn Encryptor>> {
|
||||
get_encryptor(self, key_nonce)
|
||||
}
|
||||
|
||||
pub fn decryptor(self, key: &[u8], nonce: &[u8]) -> XResult<Box<dyn Decryptor>> {
|
||||
get_decryptor(self, key, nonce)
|
||||
pub fn decryptor(self, key_nonce: &KeyNonce) -> XResult<Box<dyn Decryptor>> {
|
||||
get_decryptor(self, key_nonce)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,34 +70,34 @@ pub trait Decryptor {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_encryptor(crypto: Cryptor, key: &[u8], nonce: &[u8]) -> XResult<Box<dyn Encryptor>> {
|
||||
fn get_encryptor(crypto: Cryptor, key_nonce: &KeyNonce) -> XResult<Box<dyn Encryptor>> {
|
||||
match crypto {
|
||||
Cryptor::Aes256Gcm => {
|
||||
let mut key: [u8; 32] = opt_result!(key.try_into(), "Bad AES 256 key: {}");
|
||||
let aes256_gcm_stream_encryptor = Aes256GcmStreamEncryptor::new(key, nonce);
|
||||
let mut key: [u8; 32] = opt_result!(key_nonce.k.try_into(), "Bad AES 256 key: {}");
|
||||
let aes256_gcm_stream_encryptor = Aes256GcmStreamEncryptor::new(key, key_nonce.n);
|
||||
key.zeroize();
|
||||
Ok(Box::new(Aes256GcmEncryptor {
|
||||
aes256_gcm_stream_encryptor,
|
||||
}))
|
||||
}
|
||||
Cryptor::ChaCha20Poly1305 => Ok(Box::new(ChaCha20Poly1305Encryptor {
|
||||
chacha20_poly1305_stream_encryptor: ChaCha20Poly1305StreamEncryptor::new(key, nonce)?,
|
||||
chacha20_poly1305_stream_encryptor: ChaCha20Poly1305StreamEncryptor::new(key_nonce.k, key_nonce.n)?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_decryptor(crypto: Cryptor, key: &[u8], nonce: &[u8]) -> XResult<Box<dyn Decryptor>> {
|
||||
fn get_decryptor(crypto: Cryptor, key_nonce: &KeyNonce) -> XResult<Box<dyn Decryptor>> {
|
||||
match crypto {
|
||||
Cryptor::Aes256Gcm => {
|
||||
let mut key: [u8; 32] = opt_result!(key.try_into(), "Bad AES 256 key: {}");
|
||||
let aes256_gcm_stream_decryptor = Aes256GcmStreamDecryptor::new(key, nonce);
|
||||
let mut key: [u8; 32] = opt_result!(key_nonce.k.try_into(), "Bad AES 256 key: {}");
|
||||
let aes256_gcm_stream_decryptor = Aes256GcmStreamDecryptor::new(key, key_nonce.n);
|
||||
key.zeroize();
|
||||
Ok(Box::new(Aes256GcmDecryptor {
|
||||
aes256_gcm_stream_decryptor,
|
||||
}))
|
||||
}
|
||||
Cryptor::ChaCha20Poly1305 => Ok(Box::new(ChaCha20Poly1305Decryptor {
|
||||
chacha20_poly1305_stream_decryptor: ChaCha20Poly1305StreamDecryptor::new(key, nonce)?,
|
||||
chacha20_poly1305_stream_decryptor: ChaCha20Poly1305StreamDecryptor::new(key_nonce.k, key_nonce.n)?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -170,9 +176,10 @@ pub fn get_cryptor_by_encryption_algorithm(encryption_algorithm: &Option<String>
|
||||
fn test_cryptor() {
|
||||
let key = [0u8; 32];
|
||||
let nonce = [0u8; 12];
|
||||
let ciphertext = Cryptor::Aes256Gcm.encryptor(&key, &nonce).unwrap()
|
||||
let key_nonce = KeyNonce { k: &key, n: &nonce };
|
||||
let ciphertext = Cryptor::Aes256Gcm.encryptor(&key_nonce).unwrap()
|
||||
.encrypt(b"hello world");
|
||||
let plaintext = Cryptor::Aes256Gcm.decryptor(&key, &nonce).unwrap()
|
||||
let plaintext = Cryptor::Aes256Gcm.decryptor(&key_nonce).unwrap()
|
||||
.decrypt(&ciphertext).unwrap();
|
||||
|
||||
assert_eq!(b"hello world", plaintext.as_slice());
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
use rust_util::XResult;
|
||||
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
|
||||
pub fn try_decrypt_with_salt(crypto: Cryptor, key: &[u8], nonce: &[u8], salt: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let new_nonce = build_salted_nonce(nonce, salt);
|
||||
if let Ok(decrypted) = decrypt(crypto, key, &new_nonce, message) {
|
||||
pub fn try_decrypt_with_salt(crypto: Cryptor, key_nonce: &KeyNonce, salt: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let new_nonce = build_salted_nonce(key_nonce.n, salt);
|
||||
let new_key_nonce = KeyNonce { k: key_nonce.k, n: &new_nonce };
|
||||
if let Ok(decrypted) = decrypt(crypto, &new_key_nonce, message) {
|
||||
return Ok(decrypted);
|
||||
}
|
||||
decrypt(crypto, key, nonce, message)
|
||||
decrypt(crypto, key_nonce, message)
|
||||
}
|
||||
|
||||
pub fn decrypt(crypto: Cryptor, key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
crypto.decryptor(key, nonce)?.decrypt(message)
|
||||
pub fn decrypt(crypto: Cryptor, key_nonce: &KeyNonce, message: &[u8]) -> XResult<Vec<u8>> {
|
||||
crypto.decryptor(key_nonce)?.decrypt(message)
|
||||
}
|
||||
|
||||
pub fn encrypt_with_salt(crypto: Cryptor, key: &[u8], nonce: &[u8], salt: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let new_nonce = build_salted_nonce(nonce, salt);
|
||||
encrypt(crypto, key, &new_nonce, message)
|
||||
pub fn encrypt_with_salt(crypto: Cryptor, key_nonce: &KeyNonce, salt: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let new_nonce = build_salted_nonce(key_nonce.n, salt);
|
||||
let new_key_nonce = KeyNonce { k: key_nonce.k, n: &new_nonce };
|
||||
encrypt(crypto, &new_key_nonce, message)
|
||||
}
|
||||
|
||||
pub fn encrypt(crypto: Cryptor, key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
Ok(crypto.encryptor(key, nonce)?.encrypt(message))
|
||||
pub fn encrypt(crypto: Cryptor, key_nonce: &KeyNonce, message: &[u8]) -> XResult<Vec<u8>> {
|
||||
Ok(crypto.encryptor(key_nonce)?.encrypt(message))
|
||||
}
|
||||
|
||||
fn build_salted_nonce(nonce: &[u8], salt: &[u8]) -> Vec<u8> {
|
||||
|
||||
41
src/lib.rs
Normal file
41
src/lib.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
pub use cmd_config::CmdConfig;
|
||||
pub use cmd_config::config;
|
||||
pub use cmd_decrypt::CmdDecrypt;
|
||||
pub use cmd_decrypt::decrypt;
|
||||
pub use cmd_decrypt::decrypt_single;
|
||||
pub use cmd_encrypt::CmdEncrypt;
|
||||
pub use cmd_encrypt::encrypt;
|
||||
pub use cmd_encrypt::encrypt_single;
|
||||
pub use cmd_encrypt::encrypt_single_file_out;
|
||||
pub use cmd_info::CmdInfo;
|
||||
pub use cmd_info::info;
|
||||
pub use cmd_info::info_single;
|
||||
pub use cmd_version::CmdVersion;
|
||||
pub use cmd_version::version;
|
||||
|
||||
mod consts;
|
||||
mod util;
|
||||
mod util_env;
|
||||
mod util_digest;
|
||||
mod util_progress;
|
||||
mod util_piv;
|
||||
mod util_pgp;
|
||||
mod util_p256;
|
||||
mod util_p384;
|
||||
mod util_x25519;
|
||||
mod compress;
|
||||
mod config;
|
||||
mod spec;
|
||||
mod crypto_simple;
|
||||
mod crypto_rsa;
|
||||
mod crypto_cryptor;
|
||||
mod wrap_key;
|
||||
mod util_envelop;
|
||||
mod util_file;
|
||||
mod util_enc_file;
|
||||
mod cmd_version;
|
||||
mod cmd_config;
|
||||
mod cmd_info;
|
||||
mod cmd_decrypt;
|
||||
mod cmd_encrypt;
|
||||
|
||||
42
src/main.rs
42
src/main.rs
@@ -3,37 +3,7 @@ extern crate core;
|
||||
use clap::{Parser, Subcommand};
|
||||
use rust_util::XResult;
|
||||
|
||||
use crate::cmd_config::CmdConfig;
|
||||
use crate::cmd_decrypt::CmdDecrypt;
|
||||
use crate::cmd_encrypt::CmdEncrypt;
|
||||
use crate::cmd_info::CmdInfo;
|
||||
use crate::cmd_version::CmdVersion;
|
||||
|
||||
mod consts;
|
||||
mod util;
|
||||
mod util_env;
|
||||
mod util_digest;
|
||||
mod util_progress;
|
||||
mod util_piv;
|
||||
mod util_pgp;
|
||||
mod util_p256;
|
||||
mod util_p384;
|
||||
mod util_x25519;
|
||||
mod compress;
|
||||
mod config;
|
||||
mod spec;
|
||||
mod crypto_simple;
|
||||
mod crypto_rsa;
|
||||
mod crypto_cryptor;
|
||||
mod wrap_key;
|
||||
mod util_envelop;
|
||||
mod util_file;
|
||||
mod util_enc_file;
|
||||
mod cmd_version;
|
||||
mod cmd_config;
|
||||
mod cmd_info;
|
||||
mod cmd_decrypt;
|
||||
mod cmd_encrypt;
|
||||
use tiny_encrypt::{CmdConfig, CmdDecrypt, CmdEncrypt, CmdInfo, CmdVersion};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "tiny-encrypt-rs")]
|
||||
@@ -65,10 +35,10 @@ enum Commands {
|
||||
fn main() -> XResult<()> {
|
||||
let args = Cli::parse();
|
||||
match args.command {
|
||||
Commands::Encrypt(cmd_encrypt) => cmd_encrypt::encrypt(cmd_encrypt),
|
||||
Commands::Decrypt(cmd_decrypt) => cmd_decrypt::decrypt(cmd_decrypt),
|
||||
Commands::Info(cmd_info) => cmd_info::info(cmd_info),
|
||||
Commands::Version(cmd_version) => cmd_version::version(cmd_version),
|
||||
Commands::Config(cmd_config) => cmd_config::config(cmd_config),
|
||||
Commands::Encrypt(cmd_encrypt) => tiny_encrypt::encrypt(cmd_encrypt),
|
||||
Commands::Decrypt(cmd_decrypt) => tiny_encrypt::decrypt(cmd_decrypt),
|
||||
Commands::Info(cmd_info) => tiny_encrypt::info(cmd_info),
|
||||
Commands::Version(cmd_version) => tiny_encrypt::version(cmd_version),
|
||||
Commands::Config(cmd_config) => tiny_encrypt::config(cmd_config),
|
||||
}
|
||||
}
|
||||
10
src/spec.rs
10
src/spec.rs
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{compress, crypto_simple};
|
||||
use crate::consts::SALT_META;
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::crypto_cryptor::{Cryptor, KeyNonce};
|
||||
use crate::util::{encode_base64, get_user_agent};
|
||||
|
||||
pub const TINY_ENCRYPT_VERSION_10: &str = "1.0";
|
||||
@@ -105,21 +105,21 @@ pub struct EncEncryptedMeta {
|
||||
}
|
||||
|
||||
impl EncEncryptedMeta {
|
||||
pub fn unseal(crypto: Cryptor, key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Self> {
|
||||
pub fn unseal(crypto: Cryptor, key_nonce: &KeyNonce, message: &[u8]) -> XResult<Self> {
|
||||
let mut decrypted = opt_result!(crypto_simple::try_decrypt_with_salt(
|
||||
crypto, key, nonce, SALT_META, message), "Decrypt failed: {}");
|
||||
crypto, key_nonce, SALT_META, message), "Decrypt failed: {}");
|
||||
decrypted = opt_result!(compress::decompress(&decrypted), "Decode faield: {}");
|
||||
let meta = opt_result!(
|
||||
serde_json::from_slice::<Self>(&decrypted), "Parse failed: {}");
|
||||
Ok(meta)
|
||||
}
|
||||
|
||||
pub fn seal(&self, crypto: Cryptor, key: &[u8], nonce: &[u8]) -> XResult<Vec<u8>> {
|
||||
pub fn seal(&self, crypto: Cryptor, key_nonce: &KeyNonce) -> XResult<Vec<u8>> {
|
||||
let mut encrypted_meta_json = serde_json::to_vec(self).unwrap();
|
||||
encrypted_meta_json = opt_result!(
|
||||
compress::compress(Compression::default(), &encrypted_meta_json), "Compress failed: {}");
|
||||
let encrypted = opt_result!(crypto_simple::encrypt_with_salt(
|
||||
crypto, key, nonce, SALT_META, encrypted_meta_json.as_slice()), "Encrypt failed: {}");
|
||||
crypto, key_nonce, SALT_META, encrypted_meta_json.as_slice()), "Encrypt failed: {}");
|
||||
Ok(encrypted)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use flate2::Compression;
|
||||
use rust_util::{debugging, iff, opt_result, simple_error, XResult};
|
||||
|
||||
use crate::compress;
|
||||
@@ -13,7 +12,7 @@ pub fn write_tiny_encrypt_meta(w: &mut impl Write, meta: &TinyEncryptMeta, compr
|
||||
let mut encrypted_meta_bytes = opt_result!(serde_json::to_vec(&meta), "Generate meta json bytes failed: {}");
|
||||
if compress_meta {
|
||||
encrypted_meta_bytes = opt_result!(
|
||||
compress::compress(Compression::default(), &encrypted_meta_bytes), "Compress encrypted meta failed: {}");
|
||||
compress::compress_default(&encrypted_meta_bytes), "Compress encrypted meta failed: {}");
|
||||
}
|
||||
let encrypted_meta_bytes_len = encrypted_meta_bytes.len() as u32;
|
||||
debugging!("Encrypted meta len: {}", encrypted_meta_bytes_len);
|
||||
@@ -23,16 +22,17 @@ pub fn write_tiny_encrypt_meta(w: &mut impl Write, meta: &TinyEncryptMeta, compr
|
||||
Ok(encrypted_meta_bytes.len() + 2 + 4)
|
||||
}
|
||||
|
||||
pub fn read_tiny_encrypt_meta_and_normalize(r: &mut impl Read) -> XResult<TinyEncryptMeta> {
|
||||
let mut meta = read_tiny_encrypt_meta(r);
|
||||
let _ = meta.as_mut().map(|meta| meta.normalize());
|
||||
meta
|
||||
pub fn read_tiny_encrypt_meta_and_normalize(r: &mut impl Read) -> XResult<(u32, TinyEncryptMeta)> {
|
||||
let mut meta_and_len = read_tiny_encrypt_meta(r);
|
||||
let _ = meta_and_len.as_mut().map(|meta| meta.1.normalize());
|
||||
meta_and_len
|
||||
}
|
||||
|
||||
pub fn read_tiny_encrypt_meta(r: &mut impl Read) -> XResult<TinyEncryptMeta> {
|
||||
pub fn read_tiny_encrypt_meta(r: &mut impl Read) -> XResult<(u32, TinyEncryptMeta)> {
|
||||
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);
|
||||
debugging!("Found tag: {}", tag);
|
||||
let is_normal_tiny_enc = tag == TINY_ENC_MAGIC_TAG;
|
||||
let is_compressed_tiny_enc = tag == TINY_ENC_COMPRESSED_MAGIC_TAG;
|
||||
if !is_normal_tiny_enc && !is_compressed_tiny_enc {
|
||||
@@ -57,5 +57,5 @@ pub fn read_tiny_encrypt_meta(r: &mut impl Read) -> XResult<TinyEncryptMeta> {
|
||||
}
|
||||
debugging!("Encrypted meta: {}", String::from_utf8_lossy(&meta_buff));
|
||||
|
||||
Ok(opt_result!(serde_json::from_slice(&meta_buff), "Parse meta failed: {}"))
|
||||
Ok((length, opt_result!(serde_json::from_slice(&meta_buff), "Parse meta failed: {}")))
|
||||
}
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
use std::env;
|
||||
|
||||
use rust_util::{debugging, warning};
|
||||
|
||||
use crate::consts;
|
||||
|
||||
pub fn get_default_encryption_algorithm() -> Option<&'static str> {
|
||||
let env_default_algorithm = env::var(consts::TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM).ok();
|
||||
debugging!("Environment variable {} = {:?}", consts::TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM, env_default_algorithm);
|
||||
if let Some(env_algorithm) = env_default_algorithm {
|
||||
let lower_default_algorithm = env_algorithm.to_lowercase();
|
||||
match lower_default_algorithm.as_str() {
|
||||
"aes" | "aes/gcm" => return Some(consts::TINY_ENC_AES_GCM),
|
||||
"chacha20" | "chacha20/poly1305" => return Some(consts::TINY_ENC_CHACHA20_POLY1305),
|
||||
_ => {}
|
||||
_ => { warning!("Not matched any algorithm: {}", env_algorithm); }
|
||||
}
|
||||
}
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user