feat: v0.6.0
This commit is contained in:
@@ -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)?;
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
27
src/util.rs
27
src/util.rs
@@ -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")));
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user