diff --git a/Cargo.lock b/Cargo.lock index 80a96c1..f0c1f47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1700,7 +1700,7 @@ dependencies = [ [[package]] name = "tiny-encrypt" -version = "1.3.0" +version = "1.3.1" dependencies = [ "aes-gcm-stream", "base64", diff --git a/Cargo.toml b/Cargo.toml index 7dbaa40..e608a94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tiny-encrypt" -version = "1.3.0" +version = "1.3.1" edition = "2021" license = "MIT" description = "A simple and tiny file encrypt tool" diff --git a/src/cmd_encrypt.rs b/src/cmd_encrypt.rs index f54a31a..d93dea5 100644 --- a/src/cmd_encrypt.rs +++ b/src/cmd_encrypt.rs @@ -10,7 +10,7 @@ use rsa::Pkcs1v15Encrypt; use rust_util::{debugging, failure, iff, information, opt_result, simple_error, success, util_size, XResult}; use rust_util::util_time::UnixEpochTime; -use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env, util_p256, util_p384, util_x25519}; +use crate::{crypto_cryptor, crypto_simple, util, util_enc_file, util_env}; use crate::compress::GzStreamEncoder; use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop}; use crate::consts::{ @@ -24,6 +24,7 @@ use crate::spec::{ EncEncryptedMeta, EncMetadata, TinyEncryptEnvelop, TinyEncryptEnvelopType, TinyEncryptMeta, }; +use crate::util_ecdh::{ecdh_p256, ecdh_p384, ecdh_x25519}; use crate::util_progress::Progress; use crate::wrap_key::{WrapKey, WrapKeyHeader}; @@ -285,7 +286,7 @@ fn encrypt_envelops(cryptor: Cryptor, key: &[u8], envelops: &[&TinyEncryptConfig fn encrypt_envelop_ecdh(cryptor: Cryptor, key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult { let public_key_point_hex = &envelop.public_part; - let (shared_secret, ephemeral_spki) = util_p256::compute_p256_shared_secret(public_key_point_hex)?; + let (shared_secret, ephemeral_spki) = ecdh_p256::compute_p256_shared_secret(public_key_point_hex)?; let enc_type = match cryptor { Cryptor::Aes256Gcm => ENC_AES256_GCM_P256, Cryptor::ChaCha20Poly1305 => ENC_CHACHA20_POLY1305_P256, @@ -295,7 +296,7 @@ fn encrypt_envelop_ecdh(cryptor: Cryptor, key: &[u8], envelop: &TinyEncryptConfi fn encrypt_envelop_ecdh_p384(cryptor: Cryptor, key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult { let public_key_point_hex = &envelop.public_part; - let (shared_secret, ephemeral_spki) = util_p384::compute_p384_shared_secret(public_key_point_hex)?; + let (shared_secret, ephemeral_spki) = ecdh_p384::compute_p384_shared_secret(public_key_point_hex)?; let enc_type = match cryptor { Cryptor::Aes256Gcm => ENC_AES256_GCM_P384, Cryptor::ChaCha20Poly1305 => ENC_CHACHA20_POLY1305_P384, @@ -305,7 +306,7 @@ fn encrypt_envelop_ecdh_p384(cryptor: Cryptor, key: &[u8], envelop: &TinyEncrypt fn encrypt_envelop_ecdh_x25519(cryptor: Cryptor, key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult { let public_key_point_hex = &envelop.public_part; - let (shared_secret, ephemeral_spki) = util_x25519::compute_x25519_shared_secret(public_key_point_hex)?; + let (shared_secret, ephemeral_spki) = ecdh_x25519::compute_x25519_shared_secret(public_key_point_hex)?; let enc_type = match cryptor { Cryptor::Aes256Gcm => ENC_AES256_GCM_X25519, Cryptor::ChaCha20Poly1305 => ENC_CHACHA20_POLY1305_X25519, diff --git a/src/lib.rs b/src/lib.rs index fc5fd0c..7cb7c1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,9 +39,7 @@ mod util_progress; mod util_piv; #[cfg(feature = "decrypt")] mod util_pgp; -mod util_p256; -mod util_p384; -mod util_x25519; +mod util_ecdh; mod compress; mod config; mod spec; diff --git a/src/util_ecdh.rs b/src/util_ecdh.rs new file mode 100644 index 0000000..67f5587 --- /dev/null +++ b/src/util_ecdh.rs @@ -0,0 +1,63 @@ +pub mod ecdh_p256 { + use p256::{EncodedPoint, PublicKey}; + use p256::ecdh::EphemeralSecret; + use p256::elliptic_curve::sec1::FromEncodedPoint; + use p256::pkcs8::EncodePublicKey; + use rand::rngs::OsRng; + use rust_util::{opt_result, XResult}; + + pub fn compute_p256_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { + let public_key_point_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse public key point hex failed: {}"); + let encoded_point = opt_result!(EncodedPoint::from_bytes(public_key_point_bytes), "Parse public key point failed: {}"); + let public_key = PublicKey::from_encoded_point(&encoded_point).unwrap(); + + let esk = EphemeralSecret::random(&mut OsRng); + let epk = esk.public_key(); + let shared_secret = esk.diffie_hellman(&public_key); + let epk_public_key_der = opt_result!(epk.to_public_key_der(), "Convert epk to SPKI failed: {}"); + Ok((shared_secret.raw_secret_bytes().as_slice().to_vec(), epk_public_key_der.to_vec())) + } +} + +pub mod ecdh_p384 { + use p384::{EncodedPoint, PublicKey}; + use p384::ecdh::EphemeralSecret; + use p384::elliptic_curve::sec1::FromEncodedPoint; + use p384::pkcs8::EncodePublicKey; + use rand::rngs::OsRng; + use rust_util::{opt_result, XResult}; + + pub fn compute_p384_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { + let public_key_point_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse public key point hex failed: {}"); + let encoded_point = opt_result!(EncodedPoint::from_bytes(public_key_point_bytes), "Parse public key point failed: {}"); + let public_key = PublicKey::from_encoded_point(&encoded_point).unwrap(); + + let esk = EphemeralSecret::random(&mut OsRng); + let epk = esk.public_key(); + let shared_secret = esk.diffie_hellman(&public_key); + let epk_public_key_der = opt_result!(epk.to_public_key_der(), "Convert epk to SPKI failed: {}"); + Ok((shared_secret.raw_secret_bytes().as_slice().to_vec(), epk_public_key_der.to_vec())) + } +} + +pub mod ecdh_x25519 { + use rand::rngs::OsRng; + use rust_util::{opt_result, simple_error, XResult}; + use x25519_dalek::{EphemeralSecret, PublicKey}; + + pub fn compute_x25519_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { + let public_key_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse X25519 public key hex failed: {}"); + if public_key_bytes.len() != 32 { + return simple_error!("Parse X25519 key failed: not 32 bytes"); + } + let public_key_bytes: [u8; 32] = public_key_bytes.try_into().unwrap(); + let public_key_card = PublicKey::from(public_key_bytes); + + let ephemeral_secret = EphemeralSecret::random_from_rng(OsRng); + let ephemeral_public = PublicKey::from(&ephemeral_secret); + + let shared_secret = ephemeral_secret.diffie_hellman(&public_key_card); + + Ok((shared_secret.as_bytes().to_vec(), ephemeral_public.as_bytes().to_vec())) + } +} diff --git a/src/util_p256.rs b/src/util_p256.rs deleted file mode 100644 index 3b49a3e..0000000 --- a/src/util_p256.rs +++ /dev/null @@ -1,18 +0,0 @@ -use p256::{EncodedPoint, PublicKey}; -use p256::ecdh::EphemeralSecret; -use p256::elliptic_curve::sec1::FromEncodedPoint; -use p256::pkcs8::EncodePublicKey; -use rand::rngs::OsRng; -use rust_util::{opt_result, XResult}; - -pub fn compute_p256_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { - let public_key_point_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse public key point hex failed: {}"); - let encoded_point = opt_result!(EncodedPoint::from_bytes(public_key_point_bytes), "Parse public key point failed: {}"); - let public_key = PublicKey::from_encoded_point(&encoded_point).unwrap(); - - let esk = EphemeralSecret::random(&mut OsRng); - let epk = esk.public_key(); - let shared_secret = esk.diffie_hellman(&public_key); - let epk_public_key_der = opt_result!(epk.to_public_key_der(), "Convert epk to SPKI failed: {}"); - Ok((shared_secret.raw_secret_bytes().as_slice().to_vec(), epk_public_key_der.to_vec())) -} \ No newline at end of file diff --git a/src/util_p384.rs b/src/util_p384.rs deleted file mode 100644 index aaf2ad2..0000000 --- a/src/util_p384.rs +++ /dev/null @@ -1,19 +0,0 @@ -use p384::ecdh::EphemeralSecret; -use rand::rngs::OsRng; -use rust_util::{opt_result, XResult}; - -use p384::pkcs8::EncodePublicKey; -use p384::{EncodedPoint, PublicKey}; -use p384::elliptic_curve::sec1::FromEncodedPoint; - -pub fn compute_p384_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { - let public_key_point_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse public key point hex failed: {}"); - let encoded_point = opt_result!(EncodedPoint::from_bytes(public_key_point_bytes), "Parse public key point failed: {}"); - let public_key = PublicKey::from_encoded_point(&encoded_point).unwrap(); - - let esk = EphemeralSecret::random(&mut OsRng); - let epk = esk.public_key(); - let shared_secret = esk.diffie_hellman(&public_key); - let epk_public_key_der = opt_result!(epk.to_public_key_der(), "Convert epk to SPKI failed: {}"); - Ok((shared_secret.raw_secret_bytes().as_slice().to_vec(), epk_public_key_der.to_vec())) -} \ No newline at end of file diff --git a/src/util_x25519.rs b/src/util_x25519.rs deleted file mode 100644 index 694d040..0000000 --- a/src/util_x25519.rs +++ /dev/null @@ -1,19 +0,0 @@ -use rand::rngs::OsRng; -use rust_util::{opt_result, simple_error, XResult}; -use x25519_dalek::{EphemeralSecret, PublicKey}; - -pub fn compute_x25519_shared_secret(public_key_point_hex: &str) -> XResult<(Vec, Vec)> { - let public_key_bytes = opt_result!(hex::decode(public_key_point_hex), "Parse X25519 public key hex failed: {}"); - if public_key_bytes.len() != 32 { - return simple_error!("Parse X25519 key failed: not 32 bytes"); - } - let public_key_bytes: [u8; 32] = public_key_bytes.try_into().unwrap(); - let public_key_card = PublicKey::from(public_key_bytes); - - let ephemeral_secret = EphemeralSecret::random_from_rng(OsRng); - let ephemeral_public = PublicKey::from(&ephemeral_secret); - - let shared_secret = ephemeral_secret.diffie_hellman(&public_key_card); - - Ok((shared_secret.as_bytes().to_vec(), ephemeral_public.as_bytes().to_vec())) -} \ No newline at end of file