feat: v0.5.4, many updates

This commit is contained in:
2023-10-28 00:10:27 +08:00
parent 19269bf6de
commit 80e3a3540e
15 changed files with 186 additions and 128 deletions

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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()
}

View File

@@ -1,5 +1,6 @@
use clap::Args;
use rust_util::XResult;
use crate::util;
#[derive(Debug, Args)]

View File

@@ -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)?;

View File

@@ -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> {

View File

@@ -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());

View File

@@ -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
View 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;

View File

@@ -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),
}
}

View File

@@ -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)
}
}

View File

@@ -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: {}")))
}

View File

@@ -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