fulfills basic aead protocol

This commit is contained in:
Y. T. Chung
2017-02-16 02:01:38 +08:00
parent 7498af56fd
commit bf8a463579
5 changed files with 195 additions and 49 deletions

View File

@@ -21,6 +21,8 @@
//! Cipher defined with Rust-Crypto
use std::mem;
use rust_crypto::symmetriccipher::SynchronousStreamCipher;
use rust_crypto::chacha20::ChaCha20;
use rust_crypto::salsa20::Salsa20;
@@ -76,13 +78,23 @@ pub enum CryptoAeadCryptoVariant {
pub struct CryptoAeadCrypto {
cipher: CryptoAeadCryptoVariant,
cipher_type: CipherType,
key: Vec<u8>,
nounce: Vec<u8>,
}
impl CryptoAeadCrypto {
pub fn new(t: CipherType, key: &[u8], nounce: &[u8]) -> CryptoAeadCrypto {
let var = match t {
CryptoAeadCrypto {
cipher: CryptoAeadCrypto::new_variant(t, key, nounce),
cipher_type: t,
key: key.to_owned(),
nounce: nounce.to_owned(),
}
}
fn new_variant(t: CipherType, key: &[u8], nounce: &[u8]) -> CryptoAeadCryptoVariant {
match t {
CipherType::Aes128Gcm => {
CryptoAeadCryptoVariant::AesGcm(AesGcm::new(KeySize::KeySize128, key, nounce, &[]))
}
@@ -94,9 +106,12 @@ impl CryptoAeadCrypto {
}
_ => panic!("Unsupported {:?}", t),
};
}
}
CryptoAeadCrypto { cipher: var }
fn reset(&mut self) {
let var = CryptoAeadCrypto::new_variant(self.cipher_type, &self.key, &self.nounce);
mem::replace(&mut self.cipher, var);
}
}
@@ -104,12 +119,16 @@ impl AeadEncryptor for CryptoAeadCrypto {
fn encrypt(&mut self, input: &[u8], output: &mut [u8], tag: &mut [u8]) {
use rust_crypto::aead::AeadEncryptor;
let CryptoAeadCrypto { ref mut cipher, .. } = *self;
match *cipher {
CryptoAeadCryptoVariant::AesGcm(ref mut gcm) => {
gcm.encrypt(input, output, tag);
{
let CryptoAeadCrypto { ref mut cipher, .. } = *self;
match *cipher {
CryptoAeadCryptoVariant::AesGcm(ref mut gcm) => {
gcm.encrypt(input, output, tag);
}
}
}
self.reset();
}
}
@@ -117,16 +136,22 @@ impl AeadDecryptor for CryptoAeadCrypto {
fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> CipherResult<()> {
use rust_crypto::aead::AeadDecryptor;
let CryptoAeadCrypto { ref mut cipher, .. } = *self;
match *cipher {
CryptoAeadCryptoVariant::AesGcm(ref mut gcm) => {
if !gcm.decrypt(input, output, tag) {
Err(Error::AeadDecryptFailed)
} else {
Ok(())
let r = {
let CryptoAeadCrypto { ref mut cipher, .. } = *self;
match *cipher {
CryptoAeadCryptoVariant::AesGcm(ref mut gcm) => {
if !gcm.decrypt(input, output, tag) {
Err(Error::AeadDecryptFailed)
} else {
Ok(())
}
}
}
}
};
self.reset();
r
}
}

View File

@@ -26,7 +26,7 @@ use std::convert::From;
use openssl::symm;
pub use self::cipher::{CipherType, CipherResult};
pub use self::cipher::{CipherType, CipherCategory, CipherResult};
pub use self::stream::{StreamCipher, StreamCipherVariant, new_stream};
pub use self::aead::{AeadEncryptor, AeadDecryptor, new_aead_encryptor, new_aead_decryptor};

View File

@@ -36,7 +36,7 @@ use std::io::{self, Read, Write, BufRead, Cursor};
use std::cmp;
use std::u16;
use byteorder::{BigEndian, WriteBytesExt};
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
use crypto::{self, CipherType, AeadEncryptor, AeadDecryptor};
@@ -134,8 +134,12 @@ impl<R> DecryptedReader<R>
let mut len_buf = [0u8; 2];
self.cipher.decrypt(data, &mut len_buf, tag)?;
let len = ((len_buf[0] as u16) << 8) | (len_buf[1] as u16);
self.read_step = ReadingStep::DataAndTag(u16::from_be(len) as usize);
let len = {
let mut cur = Cursor::new(&mut len_buf);
cur.read_u16::<BigEndian>().unwrap() as usize
};
self.read_step = ReadingStep::DataAndTag(len);
}
self.buffer.clear();
}
@@ -167,8 +171,14 @@ impl<R> DecryptedReader<R>
while !self.sent_final {
match self.read_step {
ReadingStep::DataLength => self.read_length()?,
ReadingStep::DataAndTag(dlen) => self.read_data(dlen)?,
ReadingStep::DataDone => self.read_step = ReadingStep::DataLength,
ReadingStep::DataAndTag(dlen) => {
self.read_data(dlen)?;
break; // Read finished! Break out
}
ReadingStep::DataDone => {
self.read_step = ReadingStep::DataLength;
self.data.clear();
}
}
}
Ok(())
@@ -194,7 +204,7 @@ impl<R> BufRead for DecryptedReader<R>
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.buffer.len());
self.pos = cmp::min(self.pos + amt, self.data.len());
}
}
@@ -270,8 +280,10 @@ impl<W> EncryptedWrite for EncryptedWriter<W>
buf.reserve(data.len() + self.tag_size);
buf.resize(orig_buf_len + data.len(), 0);
self.cipher.encrypt(data, &mut buf[orig_buf_len..], &mut tag_buf);
buf.append(&mut tag_buf);
Ok(())
}
}

View File

@@ -12,7 +12,7 @@ use super::BUFFER_SIZE;
pub trait DecryptedRead: BufRead {}
pub trait EncryptedWrite: Sized {
pub trait EncryptedWrite {
/// Writes raw bytes directly to the writer directly
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize>;
/// Flush the writer
@@ -21,7 +21,9 @@ pub trait EncryptedWrite: Sized {
fn encrypt(&mut self, data: &[u8], buf: &mut Vec<u8>) -> io::Result<()>;
/// Encrypt data in `buf` and write all to the writer
fn write_all<B: AsRef<[u8]>>(self, buf: B) -> EncryptedWriteAll<Self, B> {
fn write_all<B: AsRef<[u8]>>(self, buf: B) -> EncryptedWriteAll<Self, B>
where Self: Sized
{
EncryptedWriteAll::Writing {
writer: self,
buf: buf,
@@ -32,7 +34,9 @@ pub trait EncryptedWrite: Sized {
}
/// Copies all data from `r`
fn copy<R: Read>(self, r: R) -> EncryptedCopy<R, Self> {
fn copy<R: Read>(self, r: R) -> EncryptedCopy<R, Self>
where Self: Sized
{
EncryptedCopy {
reader: r,
writer: self,
@@ -45,12 +49,16 @@ pub trait EncryptedWrite: Sized {
}
/// Copies all data from `r` with timeout
fn copy_timeout<R: Read>(self, r: R, timeout: Duration, handle: Handle) -> EncryptedCopyTimeout<R, Self> {
fn copy_timeout<R: Read>(self, r: R, timeout: Duration, handle: Handle) -> EncryptedCopyTimeout<R, Self>
where Self: Sized
{
EncryptedCopyTimeout::new(r, self, timeout, handle)
}
/// Copies all data from `r` with optional timeout
fn copy_timeout_opt<R: Read>(self, r: R, timeout: Option<Duration>, handle: Handle) -> EncryptedCopyOpt<R, Self> {
fn copy_timeout_opt<R: Read>(self, r: R, timeout: Option<Duration>, handle: Handle) -> EncryptedCopyOpt<R, Self>
where Self: Sized
{
match timeout {
Some(t) => EncryptedCopyOpt::CopyTimeout(self.copy_timeout(r, t, handle)),
None => EncryptedCopyOpt::Copy(self.copy(r)),

View File

@@ -21,14 +21,14 @@
//! Relay for TCP implementation
use std::io::{self, Read, Write};
use std::io::{self, Read, Write, BufRead};
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::rc::Rc;
use std::mem;
use std::time::Duration;
use crypto;
use crypto::CryptoMode;
use crypto::{CryptoMode, CipherCategory};
use relay::socks5::Address;
use relay::{BoxIoFuture, boxed_future};
use relay::dns_resolver::DnsResolver;
@@ -46,9 +46,11 @@ use net2::TcpBuilder;
use ip::IpAddr;
use self::stream::{EncryptedWriter, DecryptedReader};
pub use self::crypto_io::{DecryptedRead, EncryptedWrite};
use self::stream::{DecryptedReader as StreamDecryptedReader, EncryptedWriter as StreamEncryptedWriter};
use self::aead::{DecryptedReader as AeadDecryptedReader, EncryptedWriter as AeadEncryptedWriter};
pub mod local;
mod socks5_local;
pub mod server;
@@ -68,12 +70,94 @@ pub enum TunnelDirection {
Server2Client,
}
// TODO: `DecryptedHalf` and `EncryptedHalf` should be `Box<DecryptedRead>` and `Box<EncryptedWrite>`
type TcpReadHalf = ReadHalf<TcpStream>;
type TcpWriteHalf = WriteHalf<TcpStream>;
/// `ReadHalf `of `TcpStream` with decryption
pub type DecryptedHalf = DecryptedReader<ReadHalf<TcpStream>>;
pub enum DecryptedHalf {
Stream(StreamDecryptedReader<TcpReadHalf>),
Aead(AeadDecryptedReader<TcpReadHalf>),
}
impl Read for DecryptedHalf {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self {
DecryptedHalf::Stream(ref mut d) => d.read(buf),
DecryptedHalf::Aead(ref mut d) => d.read(buf),
}
}
}
impl DecryptedRead for DecryptedHalf {}
impl BufRead for DecryptedHalf {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
match *self {
DecryptedHalf::Stream(ref mut d) => d.fill_buf(),
DecryptedHalf::Aead(ref mut d) => d.fill_buf(),
}
}
fn consume(&mut self, amt: usize) {
match *self {
DecryptedHalf::Stream(ref mut d) => d.consume(amt),
DecryptedHalf::Aead(ref mut d) => d.consume(amt),
}
}
}
impl From<StreamDecryptedReader<TcpReadHalf>> for DecryptedHalf {
fn from(r: StreamDecryptedReader<TcpReadHalf>) -> DecryptedHalf {
DecryptedHalf::Stream(r)
}
}
impl From<AeadDecryptedReader<TcpReadHalf>> for DecryptedHalf {
fn from(r: AeadDecryptedReader<TcpReadHalf>) -> DecryptedHalf {
DecryptedHalf::Aead(r)
}
}
/// `WriteHalf` of `TcpStream` with encryption
pub type EncryptedHalf = EncryptedWriter<WriteHalf<TcpStream>>;
pub enum EncryptedHalf {
Stream(StreamEncryptedWriter<TcpWriteHalf>),
Aead(AeadEncryptedWriter<TcpWriteHalf>),
}
impl EncryptedWrite for EncryptedHalf {
fn write_raw(&mut self, data: &[u8]) -> io::Result<usize> {
match *self {
EncryptedHalf::Stream(ref mut e) => e.write_raw(data),
EncryptedHalf::Aead(ref mut e) => e.write_raw(data),
}
}
fn flush(&mut self) -> io::Result<()> {
match *self {
EncryptedHalf::Stream(ref mut e) => e.flush(),
EncryptedHalf::Aead(ref mut e) => e.flush(),
}
}
fn encrypt(&mut self, data: &[u8], buf: &mut Vec<u8>) -> io::Result<()> {
match *self {
EncryptedHalf::Stream(ref mut e) => e.encrypt(data, buf),
EncryptedHalf::Aead(ref mut e) => e.encrypt(data, buf),
}
}
}
impl From<StreamEncryptedWriter<TcpWriteHalf>> for EncryptedHalf {
fn from(d: StreamEncryptedWriter<TcpWriteHalf>) -> EncryptedHalf {
EncryptedHalf::Stream(d)
}
}
impl From<AeadEncryptedWriter<TcpWriteHalf>> for EncryptedHalf {
fn from(d: AeadEncryptedWriter<TcpWriteHalf>) -> EncryptedHalf {
EncryptedHalf::Aead(d)
}
}
/// Boxed future of `DecryptedHalf`
pub type DecryptedHalfFut = BoxIoFuture<DecryptedHalf>;
@@ -116,7 +200,10 @@ pub fn proxy_server_handshake(remote_stream: TcpStream,
// Send relay address to remote
let local_buf = Vec::new();
relay_addr.write_to(local_buf)
.and_then(move |buf| try_timeout(enc_w.write_all(buf), timeout, &handle))
.and_then(move |buf| {
trace!("Sending address buffer as {:?}", buf);
try_timeout(enc_w.write_all(buf), timeout, &handle)
})
.map(|(w, _)| w)
});
@@ -146,14 +233,20 @@ pub fn proxy_handshake(remote_stream: TcpStream,
trace!("Going to send initialize vector: {:?}", local_iv);
try_timeout(write_all(w, local_iv), timeout, &handle).and_then(move |(w, local_iv)| {
// TODO: If crypto type is Aead, returns `aead::EncryptedWriter` instead
match svr_cfg.method().category() {
CipherCategory::Stream => {
let encryptor = crypto::new_stream(svr_cfg.method(),
svr_cfg.key(),
&local_iv[..],
CryptoMode::Encrypt);
let encryptor = crypto::new_stream(svr_cfg.method(),
svr_cfg.key(),
&local_iv[..],
CryptoMode::Encrypt);
Ok(EncryptedWriter::new(w, encryptor))
Ok(From::from(StreamEncryptedWriter::new(w, encryptor)))
}
CipherCategory::Aead => {
let wtr = AeadEncryptedWriter::new(w, svr_cfg.method(), svr_cfg.key(), &local_iv[..]);
Ok(From::from(wtr))
}
}
})
};
@@ -167,13 +260,21 @@ pub fn proxy_handshake(remote_stream: TcpStream,
trace!("Got initialize vector {:?}", remote_iv);
let decryptor = crypto::new_stream(svr_cfg.method(),
svr_cfg.key(),
&remote_iv[..],
CryptoMode::Decrypt);
let decrypt_stream = DecryptedReader::new(r, decryptor);
match svr_cfg.method().category() {
CipherCategory::Stream => {
let decryptor = crypto::new_stream(svr_cfg.method(),
svr_cfg.key(),
&remote_iv[..],
CryptoMode::Decrypt);
let decrypt_stream = StreamDecryptedReader::new(r, decryptor);
Ok(decrypt_stream)
Ok(From::from(decrypt_stream))
}
CipherCategory::Aead => {
let dr = AeadDecryptedReader::new(r, svr_cfg.method(), svr_cfg.key(), &remote_iv[..]);
Ok(From::from(dr))
}
}
})
};