Skip to content

Commit

Permalink
Merge pull request #3 from amiremohamadi/feat/aead
Browse files Browse the repository at this point in the history
feat: AEAD
  • Loading branch information
amiremohamadi authored Mar 22, 2024
2 parents 6d3e036 + 7f2ac22 commit b6ed756
Show file tree
Hide file tree
Showing 10 changed files with 454 additions and 85 deletions.
95 changes: 95 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ hmac = "0.12"
md-5 = "0.10"
aes = "0.8"
rand = "0.8"
crc32fast = "1.4"
sha2 = "0.10"
aes-gcm = "0.10"
1 change: 1 addition & 0 deletions config/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ address = "0.0.0.0:1090"
[outbound]
address = "127.0.0.1:1094"
uuid = "96850032-1b92-46e9-a4f2-b99631456894"
aead = true
30 changes: 30 additions & 0 deletions src/aead.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::vmess::VmessWriter;
use aes::cipher::{generic_array::GenericArray, BlockEncrypt, KeyInit};
use aes::Aes128;
use md5::{Digest, Md5};
use rand::Rng;
use tokio::io::AsyncWrite;

impl<W: AsyncWrite + Unpin> VmessWriter<W> {
pub(crate) fn create_auth_id(&self, time: &[u8; 8]) -> [u8; 16] {
let mut buf = [0u8; 16];

buf[..8].copy_from_slice(time);

let mut salt = [0u8; 4];
rand::thread_rng().fill(&mut salt);
buf[8..12].copy_from_slice(&salt);

let crc = crc32fast::hash(&buf[..12]);
buf[12..].copy_from_slice(&crc.to_be_bytes());

let key = md5!(&self.uuid, b"c48619fe-8f02-49e0-b9e9-edf763e17e21");
let key = crate::hash::kdf(&key, &[b"AES Auth ID Encryption"]);
let cipher = Aes128::new((&key[..16]).into());

let mut b = GenericArray::from([0u8; 16]);
cipher.encrypt_block_b2b(&buf.into(), &mut b);

b.into()
}
}
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct Inbound {
pub struct Outbound {
pub address: String,
pub uuid: Uuid,
pub aead: bool,
}

impl Config {
Expand Down
125 changes: 125 additions & 0 deletions src/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use sha2::{Digest, Sha256};

trait Hasher {
fn clone(&self) -> Box<dyn Hasher>;
fn update(&mut self, data: &[u8]);
fn finalize(&mut self) -> [u8; 32];
}

struct Sha256Hash(Sha256);

impl Sha256Hash {
fn new() -> Self {
Self(Sha256::new())
}
}

impl Hasher for Sha256Hash {
fn clone(&self) -> Box<dyn Hasher> {
Box::new(Self(self.0.clone()))
}

fn update(&mut self, data: &[u8]) {
self.0.update(data);
}

fn finalize(&mut self) -> [u8; 32] {
self.0.clone().finalize().into()
}
}

struct RecursiveHash {
inner: Box<dyn Hasher>,
outer: Box<dyn Hasher>,
ipad: [u8; 64],
opad: [u8; 64],
}

impl RecursiveHash {
fn new(key: &[u8], hash: Box<dyn Hasher>) -> Self {
let mut ipad = [0u8; 64];
let mut opad = [0u8; 64];

ipad[..key.len()].copy_from_slice(&key);
opad[..key.len()].copy_from_slice(&key);

for b in ipad.iter_mut() {
*b ^= 0x36;
}

for b in opad.iter_mut() {
*b ^= 0x5c;
}

let mut inner = hash.clone();
let outer = hash;

inner.update(&ipad);
Self {
inner,
outer,
ipad,
opad,
}
}
}

impl Hasher for RecursiveHash {
fn clone(&self) -> Box<dyn Hasher> {
let inner = self.inner.clone();
let outer = self.outer.clone();
let ipad = self.ipad.clone();
let opad = self.opad.clone();

Box::new(Self {
inner,
outer,
ipad,
opad,
})
}

fn update(&mut self, data: &[u8]) {
self.inner.update(data);
}

fn finalize(&mut self) -> [u8; 32] {
let result: [u8; 32] = self.inner.finalize().into();
self.outer.update(&self.opad);
self.outer.update(&result);
self.outer.finalize().into()
}
}

pub fn kdf(key: &[u8], path: &[&[u8]]) -> [u8; 32] {
let mut current = Box::new(RecursiveHash::new(
b"VMess AEAD KDF",
Box::new(Sha256Hash::new()),
));

for p in path.into_iter() {
current = Box::new(RecursiveHash::new(p, current));
}

current.update(key);
current.finalize()
}

#[cfg(test)]
mod tests {
use super::*;
use md5::Md5;

#[test]
fn test_kdf() {
let uuid = uuid::uuid!("96850032-1b92-46e9-a4f2-b99631456894").as_bytes();
let key = md5!(&uuid, b"c48619fe-8f02-49e0-b9e9-edf763e17e21");

let res = kdf(&key, &[b"AES Auth ID Encryption"]);

assert_eq!(
res[..16],
[117, 82, 144, 159, 147, 65, 74, 253, 91, 74, 70, 84, 114, 118, 203, 30]
);
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#[macro_use]
pub mod utils;
pub mod aead;
pub mod config;
pub mod hash;
pub mod proxy;
pub mod vmess;
6 changes: 5 additions & 1 deletion src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ pub async fn run(config: &Config) -> io::Result<()> {
let (conn, _) = listener.accept().await?;

let upstream = TcpStream::connect(&config.outbound.address).await?;
let vmess = Vmess::new(upstream, *config.outbound.uuid.as_bytes());
let vmess = Vmess::new(
upstream,
*config.outbound.uuid.as_bytes(),
config.outbound.aead,
);

let (mut reader, mut writer) = conn.into_split();
let (mut ureader, mut uwriter) = vmess.into_split();
Expand Down
Loading

0 comments on commit b6ed756

Please sign in to comment.