feat: v0.5.0, supports ChaCha20/Poly1305
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1729,7 +1729,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tiny-encrypt"
|
||||
version = "0.4.4"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"aes-gcm-stream",
|
||||
"base64",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tiny-encrypt"
|
||||
version = "0.4.4"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "A simple and tiny file encrypt tool"
|
||||
@@ -39,7 +39,7 @@ yubikey = { version = "0.8", features = ["untested"] }
|
||||
zeroize = "1.6"
|
||||
|
||||
[patch.crates-io]
|
||||
rust-crypto = { git="https://github.com/jht5945/rust-crypto.git" }
|
||||
rust-crypto = { git = "https://github.com/jht5945/rust-crypto.git" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
@@ -16,14 +16,14 @@ use yubikey::piv::{AlgorithmId, decrypt_data};
|
||||
use yubikey::YubiKey;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::{util, util_enc_file, util_envelop, util_file, util_pgp, util_piv};
|
||||
use crate::{consts, crypto_simple, util, util_enc_file, util_envelop, util_file, util_pgp, util_piv};
|
||||
use crate::compress::GzStreamDecoder;
|
||||
use crate::config::TinyEncryptConfig;
|
||||
use crate::consts::{
|
||||
DATE_TIME_FORMAT, ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519,
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::crypto_aes::{aes_gcm_decrypt, try_aes_gcm_decrypt_with_salt};
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::spec::{EncEncryptedMeta, TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta};
|
||||
use crate::util::SecVec;
|
||||
use crate::util_digest::DigestWrite;
|
||||
@@ -109,6 +109,10 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
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());
|
||||
|
||||
let encryption_algorithm = meta.encryption_algorithm
|
||||
.as_ref().map(String::as_str).unwrap_or(consts::TINY_ENC_AES_GCM);
|
||||
let cryptor = Cryptor::from(encryption_algorithm)?;
|
||||
|
||||
let do_skip_file_out = cmd_decrypt.skip_decrypt_file || cmd_decrypt.direct_print || cmd_decrypt.digest_file;
|
||||
let path_out = &path_display[0..path_display.len() - TINY_ENC_FILE_EXT.len()];
|
||||
if !do_skip_file_out { util::require_file_not_exists(path_out)?; }
|
||||
@@ -127,8 +131,8 @@ pub fn decrypt_single(config: &Option<TinyEncryptConfig>,
|
||||
// debugging!("Decrypt key: {}", hex::encode(&key.0));
|
||||
debugging!("Decrypt nonce: {}", hex::encode(&nonce.0));
|
||||
|
||||
let enc_meta = parse_encrypted_meta(&meta, &key.0, &nonce.0)?;
|
||||
parse_encrypted_comment(&meta, &key.0, &nonce.0)?;
|
||||
let enc_meta = parse_encrypted_meta(&meta, cryptor, &key.0, &nonce.0)?;
|
||||
parse_encrypted_comment(&meta, cryptor, &key.0, &nonce.0)?;
|
||||
|
||||
// Decrypt to output
|
||||
if cmd_decrypt.direct_print {
|
||||
@@ -223,11 +227,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, key: &[u8], nonce: &[u8]) -> XResult<()> {
|
||||
fn parse_encrypted_comment(meta: &TinyEncryptMeta, crypto: Cryptor, key: &[u8], nonce: &[u8]) -> 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 try_aes_gcm_decrypt_with_salt(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)),
|
||||
@@ -239,14 +243,14 @@ fn parse_encrypted_comment(meta: &TinyEncryptMeta, key: &[u8], nonce: &[u8]) ->
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_encrypted_meta(meta: &TinyEncryptMeta, key: &[u8], nonce: &[u8]) -> XResult<Option<EncEncryptedMeta>> {
|
||||
fn parse_encrypted_meta(meta: &TinyEncryptMeta, cryptor: Cryptor, key: &[u8], nonce: &[u8]) -> XResult<Option<EncEncryptedMeta>> {
|
||||
Ok(match &meta.encrypted_meta {
|
||||
None => None,
|
||||
Some(enc_encrypted_meta) => {
|
||||
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(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);
|
||||
@@ -307,7 +311,8 @@ 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 decrypted_key = aes_gcm_decrypt(&key, &wrap_key.nonce, &wrap_key.encrypted_data)?;
|
||||
let decrypted_key = crypto_simple::decrypt(
|
||||
Cryptor::Aes256Gcm, &key, &wrap_key.nonce, &wrap_key.encrypted_data)?;
|
||||
util::zeroize(key);
|
||||
util::zeroize(shared_secret);
|
||||
Ok(decrypted_key)
|
||||
@@ -329,7 +334,8 @@ 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 decrypted_key = aes_gcm_decrypt(&key, &wrap_key.nonce, &wrap_key.encrypted_data)?;
|
||||
let decrypted_key = crypto_simple::decrypt(
|
||||
Cryptor::Aes256Gcm, &key, &wrap_key.nonce, &wrap_key.encrypted_data)?;
|
||||
util::zeroize(key);
|
||||
util::zeroize(shared_secret);
|
||||
Ok(decrypted_key)
|
||||
|
||||
@@ -11,14 +11,14 @@ use rust_util::{debugging, failure, iff, information, opt_result, simple_error,
|
||||
use rust_util::util_time::UnixEpochTime;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use crate::{util, util_enc_file, util_p256, util_p384, util_x25519};
|
||||
use crate::{consts, crypto_simple, util, util_enc_file, util_p256, util_p384, util_x25519};
|
||||
use crate::compress::GzStreamEncoder;
|
||||
use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop};
|
||||
use crate::consts::{
|
||||
ENC_AES256_GCM_P256, ENC_AES256_GCM_P384, ENC_AES256_GCM_X25519,
|
||||
SALT_COMMENT, TINY_ENC_CONFIG_FILE, TINY_ENC_FILE_EXT,
|
||||
};
|
||||
use crate::crypto_aes::{aes_gcm_encrypt, aes_gcm_encrypt_with_salt};
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::crypto_rsa::parse_spki;
|
||||
use crate::spec::{
|
||||
EncEncryptedMeta, EncMetadata, TINY_ENCRYPT_VERSION_10,
|
||||
@@ -58,6 +58,9 @@ pub struct CmdEncrypt {
|
||||
/// Disable compress meta
|
||||
#[arg(long)]
|
||||
pub disable_compress_meta: bool,
|
||||
/// Encryption algorithm (AES/GCM, CHACHA20/POLY1305 or AES, CHACHA20, default AES/GCM)
|
||||
#[arg(long, short = 'A')]
|
||||
pub encryption_algorithm: Option<String>,
|
||||
}
|
||||
|
||||
pub fn encrypt(cmd_encrypt: CmdEncrypt) -> XResult<()> {
|
||||
@@ -116,6 +119,16 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let encryption_algorithm = cmd_encrypt.encryption_algorithm.as_ref()
|
||||
.map(String::as_str).unwrap_or(consts::TINY_ENC_AES_GCM)
|
||||
.to_lowercase();
|
||||
let cryptor = match encryption_algorithm.as_str() {
|
||||
"aes" | "aes/gcm" => Cryptor::Aes256Gcm,
|
||||
"chacha20" | "chacha20/poly1305" => Cryptor::ChaCha20Poly1305,
|
||||
_ => return simple_error!("Unknown encryption algorithm: {}, should be AES or CHACHA20", encryption_algorithm),
|
||||
};
|
||||
information!("Using encryption algorithm: {}", cryptor.get_name());
|
||||
|
||||
util::require_file_exists(path)?;
|
||||
|
||||
let mut file_in = opt_result!(File::open(path), "Open file: {} failed: {}", &path_display);
|
||||
@@ -129,7 +142,8 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
let encrypted_comment = match &cmd_encrypt.encrypted_comment {
|
||||
None => None,
|
||||
Some(encrypted_comment) => Some(util::encode_base64(
|
||||
&aes_gcm_encrypt_with_salt(&key.0, &nonce.0, SALT_COMMENT, encrypted_comment.as_bytes())?))
|
||||
&crypto_simple::encrypt_with_salt(
|
||||
cryptor, &key.0, &nonce.0, SALT_COMMENT, encrypted_comment.as_bytes())?))
|
||||
};
|
||||
|
||||
let file_metadata = opt_result!(fs::metadata(path), "Read file: {} meta failed: {}", path.display());
|
||||
@@ -138,7 +152,8 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
c_time: file_metadata.created().ok().and_then(|t| t.to_millis()),
|
||||
m_time: file_metadata.modified().ok().and_then(|t| t.to_millis()),
|
||||
};
|
||||
let enc_encrypted_meta_bytes = opt_result!(enc_encrypted_meta.seal(&key.0, &nonce.0), "Seal enc-encrypted-meta failed: {}");
|
||||
let enc_encrypted_meta_bytes = opt_result!(enc_encrypted_meta.seal(
|
||||
cryptor, &key.0, &nonce.0), "Seal enc-encrypted-meta failed: {}");
|
||||
|
||||
let enc_metadata = EncMetadata {
|
||||
comment: cmd_encrypt.comment.clone(),
|
||||
@@ -147,11 +162,21 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
compress: cmd_encrypt.compress,
|
||||
};
|
||||
|
||||
let mut encrypt_meta = TinyEncryptMeta::new(&file_metadata, &enc_metadata, &nonce.0, envelops);
|
||||
let mut encrypt_meta = TinyEncryptMeta::new(
|
||||
&file_metadata, &enc_metadata, cryptor, &nonce.0, envelops);
|
||||
debugging!("Encrypted meta: {:?}", encrypt_meta);
|
||||
|
||||
if cmd_encrypt.compatible_with_1_0 {
|
||||
encrypt_meta = process_compatible_with_1_0(cmd_encrypt, encrypt_meta)?;
|
||||
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)?;
|
||||
@@ -172,10 +197,7 @@ fn encrypt_single(path: &PathBuf, envelops: &[&TinyEncryptConfigEnvelop], cmd_en
|
||||
Ok(file_metadata.len())
|
||||
}
|
||||
|
||||
fn process_compatible_with_1_0(cmd_encrypt: &CmdEncrypt, mut encrypt_meta: TinyEncryptMeta) -> XResult<TinyEncryptMeta> {
|
||||
if !cmd_encrypt.disable_compress_meta {
|
||||
return simple_error!("Compatible with 1.0 mode must turns --disable-compress-meta on.");
|
||||
}
|
||||
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 {
|
||||
@@ -309,7 +331,8 @@ fn encrypt_envelop_shared_secret(key: &[u8],
|
||||
let shared_key = util::simple_kdf(shared_secret);
|
||||
let (_, nonce) = util::make_key256_and_nonce();
|
||||
|
||||
let encrypted_key = aes_gcm_encrypt(&shared_key, &nonce.0, key)?;
|
||||
let encrypted_key = crypto_simple::encrypt(
|
||||
Cryptor::Aes256Gcm, &shared_key, &nonce.0, key)?;
|
||||
|
||||
let wrap_key = WrapKey {
|
||||
header: WrapKeyHeader {
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct CmdInfo {
|
||||
/// File
|
||||
pub paths: Vec<PathBuf>,
|
||||
/// Show raw meta
|
||||
#[arg(long, default_value_t = false)]
|
||||
#[arg(long, short = 'R', default_value_t = false)]
|
||||
pub raw_meta: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
use rust_util::{opt_result, XResult};
|
||||
|
||||
pub fn try_aes_gcm_decrypt_with_salt(key: &[u8], nonce: &[u8], salt: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let new_nonce = build_salted_nonce(nonce, salt);
|
||||
if let Ok(decrypted) = aes_gcm_decrypt(key, &new_nonce, message) {
|
||||
return Ok(decrypted);
|
||||
}
|
||||
aes_gcm_decrypt(key, nonce, message)
|
||||
}
|
||||
|
||||
pub fn aes_gcm_decrypt(key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
Ok(opt_result!(aes_gcm_stream::aes_256_gcm_decrypt(key, nonce, message), "Bad key or cipher text: {}"))
|
||||
}
|
||||
|
||||
pub fn aes_gcm_encrypt_with_salt(key: &[u8], nonce: &[u8], salt: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
let new_nonce = build_salted_nonce(nonce, salt);
|
||||
aes_gcm_encrypt(key, &new_nonce, message)
|
||||
}
|
||||
|
||||
pub fn aes_gcm_encrypt(key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
Ok(opt_result!(aes_gcm_stream::aes_256_gcm_encrypt(key, nonce, message), "Bad key length: {}"))
|
||||
}
|
||||
|
||||
fn build_salted_nonce(nonce: &[u8], salt: &[u8]) -> Vec<u8> {
|
||||
let mut nonce_with_salt = nonce.to_vec();
|
||||
nonce_with_salt.extend_from_slice(salt);
|
||||
let input = hex::decode(sha256::digest(nonce_with_salt)).unwrap();
|
||||
input[0..12].to_vec()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_gcm_01() {
|
||||
use aes_gcm_stream::Aes256GcmStreamEncryptor;
|
||||
let data_key = hex::decode("0001020304050607080910111213141516171819202122232425262728293031").unwrap();
|
||||
let nonce = hex::decode("000102030405060708091011").unwrap();
|
||||
|
||||
let plain_text1 = "Hello world!".as_bytes();
|
||||
let encrypted_text1 = "dce9511866417cff5123fa08c9e92cf156c5fc8bf6108ff28816fb58";
|
||||
|
||||
let plain_text2 = "This is a test message.".as_bytes();
|
||||
let encrypted_text2 = "c0e45407290878b0426fea4c09597ce323b056f975c63cce6c8da516c2a78c7d71b590c869cf92";
|
||||
|
||||
let key256: [u8; 32] = data_key.as_slice().try_into().unwrap();
|
||||
{
|
||||
let mut encryptor = Aes256GcmStreamEncryptor::new(key256.clone(), &nonce);
|
||||
let mut encrypted = encryptor.update(plain_text1);
|
||||
let (last_block, tag) = encryptor.finalize();
|
||||
encrypted.extend_from_slice(&last_block);
|
||||
encrypted.extend_from_slice(&tag);
|
||||
assert_eq!(encrypted_text1, hex::encode(&encrypted));
|
||||
}
|
||||
{
|
||||
let mut encryptor = Aes256GcmStreamEncryptor::new(key256.clone(), &nonce);
|
||||
let mut encrypted = encryptor.update(plain_text2);
|
||||
let (last_block, tag) = encryptor.finalize();
|
||||
encrypted.extend_from_slice(&last_block);
|
||||
encrypted.extend_from_slice(&tag);
|
||||
assert_eq!(encrypted_text2, hex::encode(&encrypted));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aes_gcm_02() {
|
||||
use aes_gcm_stream::Aes256GcmStreamDecryptor;
|
||||
let data_key = hex::decode("aa01020304050607080910111213141516171819202122232425262728293031").unwrap();
|
||||
let nonce = hex::decode("aa0102030405060708091011").unwrap();
|
||||
|
||||
let plain_text1 = hex::encode("Hello world!".as_bytes());
|
||||
let encrypted_text1 = hex::decode("42b625d2bacb8a514076f14002f02770e9ccd98c90e556dc267aca30").unwrap();
|
||||
|
||||
let plain_text2 = hex::encode("This is a test message.".as_bytes());
|
||||
let encrypted_text2 = hex::decode("5ebb20cdf5828e1e533ae1043ce6703cfa51574a83a069700aedefdbe2c735b01b74da214cba4a").unwrap();
|
||||
|
||||
let key256: [u8; 32] = data_key.as_slice().try_into().unwrap();
|
||||
{
|
||||
let mut decryptor = Aes256GcmStreamDecryptor::new(key256.clone(), &nonce);
|
||||
let mut plain_text = decryptor.update(encrypted_text1.as_slice());
|
||||
let last_block = decryptor.finalize().unwrap();
|
||||
plain_text.extend_from_slice(&last_block);
|
||||
assert_eq!(plain_text1, hex::encode(&plain_text));
|
||||
}
|
||||
{
|
||||
let mut decryptor = Aes256GcmStreamDecryptor::new(key256.clone(), &nonce);
|
||||
let mut plain_text = decryptor.update(encrypted_text2.as_slice());
|
||||
let last_block = decryptor.finalize().unwrap();
|
||||
plain_text.extend_from_slice(&last_block);
|
||||
assert_eq!(plain_text2, hex::encode(&plain_text));
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,14 @@ impl Cryptor {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> String {
|
||||
let name = match self {
|
||||
Cryptor::Aes256Gcm => consts::TINY_ENC_AES_GCM,
|
||||
Cryptor::ChaCha20Poly1305 => consts::TINY_ENC_CHACHA20_POLY1305,
|
||||
};
|
||||
name.to_string()
|
||||
}
|
||||
|
||||
pub fn encryptor(self, key: &[u8], nonce: &[u8]) -> XResult<Box<dyn Encryptor>> {
|
||||
get_encryptor(self, key, nonce)
|
||||
}
|
||||
|
||||
31
src/crypto_simple.rs
Normal file
31
src/crypto_simple.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
use rust_util::XResult;
|
||||
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
|
||||
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) {
|
||||
return Ok(decrypted);
|
||||
}
|
||||
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 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(crypto: Cryptor, key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Vec<u8>> {
|
||||
Ok(crypto.encryptor(key, nonce)?.encrypt(message))
|
||||
}
|
||||
|
||||
fn build_salted_nonce(nonce: &[u8], salt: &[u8]) -> Vec<u8> {
|
||||
let mut nonce_with_salt = nonce.to_vec();
|
||||
nonce_with_salt.extend_from_slice(salt);
|
||||
let input = hex::decode(sha256::digest(nonce_with_salt)).unwrap();
|
||||
input[0..12].to_vec()
|
||||
}
|
||||
@@ -21,7 +21,7 @@ mod util_x25519;
|
||||
mod compress;
|
||||
mod config;
|
||||
mod spec;
|
||||
mod crypto_aes;
|
||||
mod crypto_simple;
|
||||
mod crypto_rsa;
|
||||
mod crypto_cryptor;
|
||||
mod wrap_key;
|
||||
|
||||
21
src/spec.rs
21
src/spec.rs
@@ -5,8 +5,9 @@ use rust_util::{opt_result, util_time, XResult};
|
||||
use rust_util::util_time::get_millis;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{compress, crypto_aes};
|
||||
use crate::consts::{SALT_META, TINY_ENC_AES_GCM};
|
||||
use crate::{compress, crypto_simple};
|
||||
use crate::consts::SALT_META;
|
||||
use crate::crypto_cryptor::Cryptor;
|
||||
use crate::util::{encode_base64, get_user_agent};
|
||||
|
||||
pub const TINY_ENCRYPT_VERSION_10: &str = "1.0";
|
||||
@@ -104,21 +105,21 @@ pub struct EncEncryptedMeta {
|
||||
}
|
||||
|
||||
impl EncEncryptedMeta {
|
||||
pub fn unseal(key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Self> {
|
||||
let mut decrypted = opt_result!(crypto_aes::try_aes_gcm_decrypt_with_salt(
|
||||
key, nonce, SALT_META, message), "Decrypt failed: {}");
|
||||
pub fn unseal(crypto: Cryptor, key: &[u8], nonce: &[u8], message: &[u8]) -> XResult<Self> {
|
||||
let mut decrypted = opt_result!(crypto_simple::try_decrypt_with_salt(
|
||||
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, key: &[u8], nonce: &[u8]) -> XResult<Vec<u8>> {
|
||||
pub fn seal(&self, crypto: Cryptor, key: &[u8], nonce: &[u8]) -> 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_aes::aes_gcm_encrypt_with_salt(
|
||||
key, nonce, SALT_META, encrypted_meta_json.as_slice()), "Encrypt failed: {}");
|
||||
let encrypted = opt_result!(crypto_simple::encrypt_with_salt(
|
||||
crypto, key, nonce, SALT_META, encrypted_meta_json.as_slice()), "Encrypt failed: {}");
|
||||
Ok(encrypted)
|
||||
}
|
||||
}
|
||||
@@ -131,7 +132,7 @@ pub struct EncMetadata {
|
||||
}
|
||||
|
||||
impl TinyEncryptMeta {
|
||||
pub fn new(metadata: &Metadata, enc_metadata: &EncMetadata, nonce: &[u8], envelops: Vec<TinyEncryptEnvelop>) -> Self {
|
||||
pub fn new(metadata: &Metadata, enc_metadata: &EncMetadata, cryptor: Cryptor, nonce: &[u8], envelops: Vec<TinyEncryptEnvelop>) -> Self {
|
||||
TinyEncryptMeta {
|
||||
version: TINY_ENCRYPT_VERSION_11.to_string(),
|
||||
created: util_time::get_current_millis() as u64,
|
||||
@@ -147,7 +148,7 @@ impl TinyEncryptMeta {
|
||||
ecdh_point: None,
|
||||
envelop: None,
|
||||
envelops: Some(envelops),
|
||||
encryption_algorithm: Some(TINY_ENC_AES_GCM.to_string()),
|
||||
encryption_algorithm: Some(cryptor.get_name()),
|
||||
nonce: encode_base64(nonce),
|
||||
file_length: metadata.len(),
|
||||
file_last_modified: match metadata.modified() {
|
||||
|
||||
Reference in New Issue
Block a user