feat: v0.6.0

This commit is contained in:
2023-10-28 11:38:16 +08:00
parent 9ec0dba5b3
commit 373b3bcefc
9 changed files with 56 additions and 62 deletions

2
Cargo.lock generated
View File

@@ -1727,7 +1727,7 @@ dependencies = [
[[package]]
name = "tiny-encrypt"
version = "0.5.4"
version = "0.6.0"
dependencies = [
"aes-gcm-stream",
"base64",

View File

@@ -1,6 +1,6 @@
[package]
name = "tiny-encrypt"
version = "0.5.4"
version = "0.6.0"
edition = "2021"
license = "MIT"
description = "A simple and tiny file encrypt tool"

View File

@@ -345,7 +345,7 @@ fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option<St
let epk_bytes = opt_result!(util::decode_base64_url_no_pad(e_pub_key), "Invalid envelop: {}");
let mut pgp = util_pgp::get_openpgp()?;
let mut trans = opt_result!(pgp.transaction(), "Open card failed: {}");
let mut trans = opt_result!(pgp.transaction(), "Connect PIV card failed: {}");
util_pgp::read_and_verify_openpgp_pin(&mut trans, pin)?;
@@ -362,7 +362,7 @@ fn try_decrypt_key_ecdh_pgp_x25519(envelop: &TinyEncryptEnvelop, pin: &Option<St
fn try_decrypt_key_pgp(envelop: &TinyEncryptEnvelop, pin: &Option<String>) -> XResult<Vec<u8>> {
let mut pgp = util_pgp::get_openpgp()?;
let mut trans = opt_result!(pgp.transaction(), "Open card failed: {}");
let mut trans = opt_result!(pgp.transaction(), "Connect OpenPGP card failed: {}");
util_pgp::read_and_verify_openpgp_pin(&mut trans, pin)?;

View File

@@ -10,7 +10,7 @@ use rsa::Pkcs1v15Encrypt;
use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, XResult};
use rust_util::util_time::UnixEpochTime;
use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_p256, util_p384, util_x25519};
use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env, util_p256, util_p384, util_x25519};
use crate::compress::GzStreamEncoder;
use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop};
use crate::consts::{
@@ -21,7 +21,7 @@ use crate::consts::{
use crate::crypto_cryptor::{Cryptor, KeyNonce};
use crate::crypto_rsa;
use crate::spec::{
EncEncryptedMeta, EncMetadata, TINY_ENCRYPT_VERSION_10,
EncEncryptedMeta, EncMetadata,
TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta,
};
use crate::util_progress::Progress;
@@ -49,9 +49,6 @@ pub struct CmdEncrypt {
/// Compress level (from 0[none], 1[fast] .. 6[default] .. to 9[best])
#[arg(long, short = 'L')]
pub compress_level: Option<u32>,
/// Compatible with 1.0 (requires assign --disable-compress-meta)
#[arg(long, short = '1')]
pub compatible_with_1_0: bool,
/// Remove source file
#[arg(long, short = 'R')]
pub remove_file: bool,
@@ -136,6 +133,7 @@ pub fn encrypt_single_file_out(path: &PathBuf, path_out: &str, envelops: &[&Tiny
let (key, nonce) = util::make_key256_and_nonce();
let key_nonce = KeyNonce { k: &key.0, n: &nonce.0 };
// Encrypt session key to envelops
let envelops = encrypt_envelops(cryptor, &key.0, envelops)?;
let encrypted_comment = match &cmd_encrypt.encrypted_comment {
@@ -154,38 +152,25 @@ pub fn encrypt_single_file_out(path: &PathBuf, path_out: &str, envelops: &[&Tiny
let enc_encrypted_meta_bytes = opt_result!(enc_encrypted_meta.seal(
cryptor, &key_nonce), "Seal enc-encrypted-meta failed: {}");
let compress_level = get_compress_level(cmd_encrypt);
let enc_metadata = EncMetadata {
comment: cmd_encrypt.comment.clone(),
encrypted_comment,
encrypted_meta: Some(util::encode_base64(&enc_encrypted_meta_bytes)),
compress: cmd_encrypt.compress,
compress: compress_level.is_some(),
};
let mut encrypt_meta = TinyEncryptMeta::new(
let encrypt_meta = TinyEncryptMeta::new(
&file_metadata, &enc_metadata, cryptor, &nonce.0, envelops);
debugging!("Encrypted meta: {:?}", encrypt_meta);
if cmd_encrypt.compatible_with_1_0 {
if !cmd_encrypt.disable_compress_meta {
return simple_error!("Compatible with 1.0 mode must turns --disable-compress-meta on.");
}
if let Cryptor::Aes256Gcm = Cryptor::Aes256Gcm {} else {
return simple_error!("Compatible with 1.0 mode must use AES/GCM.");
}
encrypt_meta = process_compatible_with_1_0(encrypt_meta)?;
if encrypt_meta.pgp_envelop.is_none() && encrypt_meta.ecdh_envelop.is_none() {
return simple_error!("Compatible with 1.0 mode must contains PGP or ECDH Envelop.");
}
}
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)?;
let compress_desc = iff!(cmd_encrypt.compress, " [with compress]", "");
let compress_desc = iff!(compress_level.is_some(), " [with compress]", "");
let compress_level = iff!(cmd_encrypt.compress,
Some(cmd_encrypt.compress_level.unwrap_or_else(|| Compression::default().level())), None);
let start = Instant::now();
encrypt_file(
&mut file_in, file_metadata.len(), &mut file_out, cryptor,
@@ -199,28 +184,6 @@ pub fn encrypt_single_file_out(path: &PathBuf, path_out: &str, envelops: &[&Tiny
Ok(file_metadata.len())
}
fn process_compatible_with_1_0(mut encrypt_meta: TinyEncryptMeta) -> XResult<TinyEncryptMeta> {
if let Some(envelops) = encrypt_meta.envelops {
let mut filter_envelops = vec![];
for envelop in envelops {
if (envelop.r#type == TinyEncryptEnvelopType::Pgp) && encrypt_meta.pgp_envelop.is_none() {
encrypt_meta.pgp_fingerprint = Some(format!("KID:{}", envelop.kid));
encrypt_meta.pgp_envelop = Some(envelop.encrypted_key.clone());
} else if (envelop.r#type == TinyEncryptEnvelopType::Ecdh) && encrypt_meta.ecdh_envelop.is_none() {
encrypt_meta.ecdh_point = Some(format!("KID:{}", envelop.kid));
encrypt_meta.ecdh_envelop = Some(envelop.encrypted_key.clone());
} else {
filter_envelops.push(envelop);
}
}
encrypt_meta.envelops = if filter_envelops.is_empty() { None } else { Some(filter_envelops) };
if encrypt_meta.envelops.is_none() {
encrypt_meta.version = TINY_ENCRYPT_VERSION_10.to_string();
}
}
Ok(encrypt_meta)
}
fn encrypt_file(file_in: &mut File, file_len: u64, file_out: &mut impl Write, cryptor: Cryptor,
key_nonce: &KeyNonce, compress_level: &Option<u32>) -> XResult<u64> {
let compress = compress_level.is_some();
@@ -375,3 +338,11 @@ fn encrypt_envelop_pgp(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResul
encrypted_key: util::encode_base64(&encrypted_key),
})
}
fn get_compress_level(cmd_encrypt: &CmdEncrypt) -> Option<u32> {
if cmd_encrypt.compress || util_env::get_default_compress().unwrap_or(false) {
Some(cmd_encrypt.compress_level.unwrap_or_else(|| Compression::default().level()))
} else {
None
}
}

View File

@@ -10,7 +10,6 @@ pub const ENC_CHACHA20_POLY1305_X25519: &str = "chacha20-poly1305-x25519";
pub const TINY_ENC_FILE_EXT: &str = ".tinyenc";
pub const TINY_ENC_CONFIG_FILE: &str = "~/.tinyencrypt/config-rs.json";
pub const TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM: &str = "TINY_ENCRYPT_DEFAULT_ALGORITHM";
pub const TINY_ENC_AES_GCM: &str = "AES/GCM";
pub const TINY_ENC_CHACHA20_POLY1305: &str = "CHACHA20/POLY1305";

View File

@@ -10,7 +10,8 @@ use crate::consts::SALT_META;
use crate::crypto_cryptor::{Cryptor, KeyNonce};
use crate::util::{encode_base64, get_user_agent};
pub const TINY_ENCRYPT_VERSION_10: &str = "1.0";
// Compatible with 1.0 is removed from v0.6.0
// pub const TINY_ENCRYPT_VERSION_10: &str = "1.0";
pub const TINY_ENCRYPT_VERSION_11: &str = "1.1";
/// Specification: [Tiny Encrypt Spec V1.1](https://github.com/OpenWebStandard/tiny-encrypt-format-spec/blob/main/TinyEncryptSpecv1.1.md)

View File

@@ -9,6 +9,7 @@ use rust_util::{information, print_ex, simple_error, util_term, warning, XResult
use zeroize::Zeroize;
use crate::consts::TINY_ENC_FILE_EXT;
use crate::util_digest::DigestWrite;
pub struct SecVec(pub Vec<u8>);
@@ -93,14 +94,13 @@ pub fn make_key256_and_nonce() -> (SecVec, SecVec) {
}
pub fn simple_kdf(input: &[u8]) -> Vec<u8> {
let input = hex::decode(sha256::digest(input)).unwrap();
let input = hex::decode(sha256::digest(input)).unwrap();
let input = hex::decode(sha256::digest(input)).unwrap();
let input = hex::decode(sha256::digest(input)).unwrap();
let input = hex::decode(sha256::digest(input)).unwrap();
let input = hex::decode(sha256::digest(input)).unwrap();
let input = hex::decode(sha256::digest(input)).unwrap();
hex::decode(sha256::digest(input)).unwrap()
let mut input = input.to_vec();
for _ in 0..8 {
let mut sha256 = DigestWrite::sha256().expect("SHOULD NOT HAPPEN");
sha256.write_all(&input).expect("SHOULD NOT HAPPEN");
input = sha256.digest();
}
input
}
pub fn decode_base64(input: &str) -> XResult<Vec<u8>> {
@@ -213,3 +213,14 @@ pub fn ratio(numerator: u64, denominator: u64) -> String {
let r = (numerator * 10000) / denominator;
format!("{:.2}", r as f64 / 100f64)
}
#[test]
fn test_simple_kdf() {
assert_eq!("30edbc354e8cf656adcddbeefbf3f5073372cdc42e4eca2e797bda8abebb6a05",
hex::encode(simple_kdf(b"")));
assert_eq!("0624d2a57bcb50f70aa19bab9fa75af1ca66cc701c341df865d430e2e6d9d936",
hex::encode(simple_kdf(b"hello")));
assert_eq!("43367d255eddedc3c84b692b68de6d3d21da28caad6abd20ed85a4f2c89706ad",
hex::encode(simple_kdf(b"hello world")));
}

View File

@@ -33,6 +33,10 @@ impl DigestWrite {
}
}
pub fn sha256() -> XResult<Self> {
Ok(Self { digest: Box::new(Sha256::new()) })
}
pub fn digest(self) -> Vec<u8> {
let mut digest = self.digest;
let mut buf: Vec<u8> = repeat(0).take((digest.output_bits() + 7) / 8).collect();

View File

@@ -1,12 +1,16 @@
use std::env;
use rust_util::{debugging, warning};
use rust_util::{debugging, iff, warning};
use rust_util::util_env as rust_util_env;
use crate::consts;
pub const TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM: &str = "TINY_ENCRYPT_DEFAULT_ALGORITHM";
pub const TINY_ENCRYPT_ENV_DEFAULT_COMPRESS: &str = "TINY_ENCRYPT_DEFAULT_COMPRESS";
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);
let env_default_algorithm = env::var(TINY_ENCRYPT_ENV_DEFAULT_ALGORITHM).ok();
debugging!("Environment variable {} = {:?}", 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() {
@@ -16,4 +20,8 @@ pub fn get_default_encryption_algorithm() -> Option<&'static str> {
}
}
None
}
pub fn get_default_compress() -> Option<bool> {
iff!(rust_util_env::is_env_off(TINY_ENCRYPT_ENV_DEFAULT_COMPRESS), Some(true), None)
}