feat: v0.2.0-dev, encrypt supports x25519

This commit is contained in:
2023-10-08 00:49:17 +08:00
parent 9637ef9e01
commit 0bdb89ad25
6 changed files with 113 additions and 4 deletions

69
Cargo.lock generated
View File

@@ -390,6 +390,33 @@ dependencies = [
"typenum",
]
[[package]]
name = "curve25519-dalek"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"fiat-crypto",
"platforms",
"rustc_version",
"subtle",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "data-encoding"
version = "2.4.0"
@@ -574,6 +601,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "fiat-crypto"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d"
[[package]]
name = "flagset"
version = "0.4.4"
@@ -1339,6 +1372,12 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "platforms"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8"
[[package]]
name = "polyval"
version = "0.6.1"
@@ -1579,6 +1618,15 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "rusticata-macros"
version = "4.1.0"
@@ -1709,6 +1757,12 @@ dependencies = [
"libc",
]
[[package]]
name = "semver"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
[[package]]
name = "serde"
version = "1.0.188"
@@ -2009,7 +2063,7 @@ dependencies = [
[[package]]
name = "tiny-encrypt"
version = "0.1.2"
version = "0.2.0-dev"
dependencies = [
"aes-gcm-stream",
"base64",
@@ -2029,6 +2083,7 @@ dependencies = [
"serde_json",
"sha256",
"simpledateformat",
"x25519-dalek",
"x509-parser",
"yubikey",
"zeroize",
@@ -2428,6 +2483,18 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "x25519-dalek"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96"
dependencies = [
"curve25519-dalek",
"rand_core",
"serde",
"zeroize",
]
[[package]]
name = "x509-cert"
version = "0.2.4"

View File

@@ -1,6 +1,6 @@
[package]
name = "tiny-encrypt"
version = "0.1.2"
version = "0.2.0-dev"
edition = "2021"
license = "MIT"
description = "A simple and tiny file encrypt tool"
@@ -26,6 +26,7 @@ serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
sha256 = "1.4.0"
simpledateformat = "0.1.4"
x25519-dalek = "2.0.0"
x509-parser = "0.15.1"
yubikey = { version = "0.8.0", features = ["untested"] }
zeroize = "1.6.0"

View File

@@ -10,7 +10,7 @@ use rsa::Pkcs1v15Encrypt;
use rust_util::{debugging, failure, information, opt_result, simple_error, success, util_msg, warning, XResult};
use zeroize::Zeroize;
use crate::{util, util_ecdh};
use crate::{util, util_ecdh, util_x25519};
use crate::compress::GzStreamEncoder;
use crate::config::{TinyEncryptConfig, TinyEncryptConfigEnvelop};
use crate::crypto_aes::aes_gcm_encrypt;
@@ -233,6 +233,9 @@ fn encrypt_envelops(key: &[u8], envelops: &[&TinyEncryptConfigEnvelop]) -> XResu
TinyEncryptEnvelopType::Pgp => {
encrypted_envelops.push(encrypt_envelop_pgp(key, envelop)?);
}
TinyEncryptEnvelopType::PgpX25519 => {
encrypted_envelops.push(encrypt_envelop_ecdh_x25519(key, envelop)?);
}
TinyEncryptEnvelopType::Ecdh => {
encrypted_envelops.push(encrypt_envelop_ecdh(key, envelop)?);
}
@@ -245,7 +248,22 @@ fn encrypt_envelops(key: &[u8], envelops: &[&TinyEncryptConfigEnvelop]) -> XResu
fn encrypt_envelop_ecdh(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
let public_key_point_hex = &envelop.public_part;
let (shared_secret, ephemeral_spki) = util_ecdh::compute_shared_secret(public_key_point_hex)?;
let shared_key = util::simple_kdf(shared_secret.as_slice());
encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, envelop)
}
fn encrypt_envelop_ecdh_x25519(key: &[u8], envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
let public_key_point_hex = &envelop.public_part;
let (shared_secret, ephemeral_spki) = util_x25519::compute_x25519_shared_secret(public_key_point_hex)?;
encrypt_envelop_shared_secret(key, &shared_secret, &ephemeral_spki, envelop)
}
fn encrypt_envelop_shared_secret(key: &[u8],
shared_secret: &[u8],
ephemeral_spki: &[u8],
envelop: &TinyEncryptConfigEnvelop) -> XResult<TinyEncryptEnvelop> {
let shared_key = util::simple_kdf(shared_secret);
let (_, nonce) = util::make_key256_and_nonce();
let encrypted_key = aes_gcm_encrypt(&shared_key, &nonce, key)?;

View File

@@ -9,6 +9,7 @@ use crate::cmd_info::CmdInfo;
mod util;
mod util_ecdh;
mod util_x25519;
mod compress;
mod config;
mod spec;

View File

@@ -50,6 +50,8 @@ pub struct TinyEncryptEnvelop {
pub enum TinyEncryptEnvelopType {
#[serde(rename = "pgp")]
Pgp,
#[serde(rename = "pgp-x25519")]
PgpX25519,
#[serde(rename = "age")]
Age,
#[serde(rename = "ecdh")]
@@ -65,6 +67,7 @@ impl TinyEncryptEnvelopType {
pub fn get_name(&self) -> &'static str {
match self {
TinyEncryptEnvelopType::Pgp => "pgp",
TinyEncryptEnvelopType::PgpX25519 => "pgp-x25519",
TinyEncryptEnvelopType::Age => "age",
TinyEncryptEnvelopType::Ecdh => "ecdh",
TinyEncryptEnvelopType::Kms => "kms",

19
src/util_x25519.rs Normal file
View File

@@ -0,0 +1,19 @@
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<u8>, Vec<u8>)> {
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()))
}