mirror of https://github.com/dswd/vpncloud.git
Added support for AES128
This commit is contained in:
parent
b6dafdaeee
commit
dfad73065c
|
@ -2,6 +2,12 @@
|
|||
|
||||
This project follows [semantic versioning](http://semver.org).
|
||||
|
||||
|
||||
### UNRELEASED
|
||||
|
||||
- [added] Added crypto option AES128
|
||||
|
||||
|
||||
### v1.4.0 (2020-06-03)
|
||||
|
||||
- [added] Added option to listen on specified IP
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Planned breaking changes
|
||||
|
||||
Due to semantic versioning, any breaking change after 1.0 requires a new major version number.
|
||||
This is a list of breaking changes to do in such a case:
|
||||
- Change default crypto to AES128
|
||||
- Remove network-id parameter
|
||||
- Remove port config option
|
|
@ -50,6 +50,19 @@ fn crypto_aes256(b: &mut Bencher) {
|
|||
b.bytes = 1400;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn crypto_aes128(b: &mut Bencher) {
|
||||
let mut crypto = Crypto::from_shared_key(CryptoMethod::AES128, "test");
|
||||
let mut payload = [0; 1500];
|
||||
let header = [0; 8];
|
||||
let mut nonce_bytes = [0; 12];
|
||||
b.iter(|| {
|
||||
let len = crypto.encrypt(&mut payload, 1400, &mut nonce_bytes, &header);
|
||||
assert!(crypto.decrypt(&mut payload[..len], &nonce_bytes, &header).is_ok());
|
||||
});
|
||||
b.bytes = 1400;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn message_encode(b: &mut Bencher) {
|
||||
let mut crypto = Crypto::None;
|
||||
|
|
|
@ -17,7 +17,9 @@ pub enum CryptoMethod {
|
|||
#[serde(rename = "chacha20")]
|
||||
ChaCha20,
|
||||
#[serde(rename = "aes256")]
|
||||
AES256
|
||||
AES256,
|
||||
#[serde(rename = "aes128")]
|
||||
AES128
|
||||
}
|
||||
impl FromStr for CryptoMethod {
|
||||
type Err = &'static str;
|
||||
|
@ -25,7 +27,8 @@ impl FromStr for CryptoMethod {
|
|||
fn from_str(text: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match &text.to_lowercase() as &str {
|
||||
"chacha20" | "chacha" => Self::ChaCha20,
|
||||
"aes256" | "aes" => Self::AES256,
|
||||
"aes256" => Self::AES256,
|
||||
"aes128" | "aes" => Self::AES128,
|
||||
_ => return Err("Unknown method")
|
||||
})
|
||||
}
|
||||
|
@ -41,7 +44,8 @@ pub struct CryptoData {
|
|||
pub enum Crypto {
|
||||
None,
|
||||
ChaCha20Poly1305(CryptoData),
|
||||
AES256GCM(CryptoData)
|
||||
AES256GCM(CryptoData),
|
||||
AES128GCM(CryptoData)
|
||||
}
|
||||
|
||||
fn inc_nonce(nonce: &mut [u8]) {
|
||||
|
@ -63,7 +67,8 @@ impl Crypto {
|
|||
match *self {
|
||||
Crypto::None => 0,
|
||||
Crypto::ChaCha20Poly1305 { .. } => 1,
|
||||
Crypto::AES256GCM { .. } => 2
|
||||
Crypto::AES256GCM { .. } => 2,
|
||||
Crypto::AES128GCM { .. } => 3
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +76,9 @@ impl Crypto {
|
|||
pub fn nonce_bytes(&self) -> usize {
|
||||
match *self {
|
||||
Crypto::None => 0,
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.crypto_key.algorithm().nonce_len()
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) | Crypto::AES128GCM(ref data) => {
|
||||
data.crypto_key.algorithm().nonce_len()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +86,7 @@ impl Crypto {
|
|||
pub fn get_key(&self) -> &[u8] {
|
||||
match *self {
|
||||
Crypto::None => &[],
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => &data.key
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) | Crypto::AES128GCM(ref data) => &data.key
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,14 +95,17 @@ impl Crypto {
|
|||
pub fn additional_bytes(&self) -> usize {
|
||||
match *self {
|
||||
Crypto::None => 0,
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.crypto_key.algorithm().tag_len()
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) | Crypto::AES128GCM(ref data) => {
|
||||
data.crypto_key.algorithm().tag_len()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_shared_key(method: CryptoMethod, password: &str) -> Self {
|
||||
let algo = match method {
|
||||
CryptoMethod::ChaCha20 => &CHACHA20_POLY1305,
|
||||
CryptoMethod::AES256 => &AES_256_GCM
|
||||
CryptoMethod::AES256 => &AES_256_GCM,
|
||||
CryptoMethod::AES128 => &AES_128_GCM
|
||||
};
|
||||
let mut key: Vec<u8> = Vec::with_capacity(algo.key_len());
|
||||
for _ in 0..algo.key_len() {
|
||||
|
@ -137,14 +147,15 @@ impl Crypto {
|
|||
let data = CryptoData { crypto_key, nonce, key };
|
||||
match method {
|
||||
CryptoMethod::ChaCha20 => Crypto::ChaCha20Poly1305(data),
|
||||
CryptoMethod::AES256 => Crypto::AES256GCM(data)
|
||||
CryptoMethod::AES256 => Crypto::AES256GCM(data),
|
||||
CryptoMethod::AES128 => Crypto::AES128GCM(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrypt(&self, buf: &mut [u8], nonce: &[u8], header: &[u8]) -> Result<usize, Error> {
|
||||
match *self {
|
||||
Crypto::None => Ok(buf.len()),
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => {
|
||||
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) | Crypto::AES128GCM(ref data) => {
|
||||
let nonce = Nonce::try_assume_unique_for_key(nonce).unwrap();
|
||||
match data.crypto_key.open_in_place(nonce, Aad::from(header), buf) {
|
||||
Ok(plaintext) => Ok(plaintext.len()),
|
||||
|
@ -158,7 +169,9 @@ impl Crypto {
|
|||
let tag_len = self.additional_bytes();
|
||||
match *self {
|
||||
Crypto::None => mlen,
|
||||
Crypto::ChaCha20Poly1305(ref mut data) | Crypto::AES256GCM(ref mut data) => {
|
||||
Crypto::ChaCha20Poly1305(ref mut data)
|
||||
| Crypto::AES256GCM(ref mut data)
|
||||
| Crypto::AES128GCM(ref mut data) => {
|
||||
inc_nonce(&mut data.nonce);
|
||||
assert!(buf.len() - mlen >= tag_len);
|
||||
let nonce = Nonce::try_assume_unique_for_key(&data.nonce).unwrap();
|
||||
|
@ -217,3 +230,25 @@ fn encrypt_decrypt_aes256() {
|
|||
receiver.decrypt(&mut buffer[..size], &nonce2, &header).unwrap();
|
||||
assert_eq!(msg_bytes, &buffer[..msg_bytes.len()] as &[u8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encrypt_decrypt_aes128() {
|
||||
let mut sender = Crypto::from_shared_key(CryptoMethod::AES128, "test");
|
||||
let receiver = Crypto::from_shared_key(CryptoMethod::AES128, "test");
|
||||
let msg = "HelloWorld0123456789";
|
||||
let msg_bytes = msg.as_bytes();
|
||||
let mut buffer = [0u8; 1024];
|
||||
let header = [0u8; 8];
|
||||
buffer[..msg_bytes.len()].clone_from_slice(&msg_bytes);
|
||||
let mut nonce1 = [0u8; 12];
|
||||
let size = sender.encrypt(&mut buffer, msg_bytes.len(), &mut nonce1, &header);
|
||||
assert_eq!(size, msg_bytes.len() + sender.additional_bytes());
|
||||
assert!(msg_bytes != &buffer[..msg_bytes.len()] as &[u8]);
|
||||
receiver.decrypt(&mut buffer[..size], &nonce1, &header).unwrap();
|
||||
assert_eq!(msg_bytes, &buffer[..msg_bytes.len()] as &[u8]);
|
||||
let mut nonce2 = [0u8; 12];
|
||||
let size = sender.encrypt(&mut buffer, msg_bytes.len(), &mut nonce2, &header);
|
||||
assert!(nonce1 != nonce2);
|
||||
receiver.decrypt(&mut buffer[..size], &nonce2, &header).unwrap();
|
||||
assert_eq!(msg_bytes, &buffer[..msg_bytes.len()] as &[u8]);
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ pub struct Args {
|
|||
#[structopt(short, long, aliases=&["shared-key", "secret-key", "secret"])]
|
||||
key: Option<String>,
|
||||
|
||||
/// The encryption method to use ("aes256", or "chacha20")
|
||||
/// The encryption method to use ("aes128", "aes256", or "chacha20")
|
||||
#[structopt(long)]
|
||||
crypto: Option<CryptoMethod>,
|
||||
|
||||
|
|
|
@ -59,9 +59,9 @@ vpncloud - Peer-to-peer VPN
|
|||
the traffic will be sent unencrypted.
|
||||
|
||||
*--crypto <method>*::
|
||||
The encryption method to use ("aes256", or "chacha20"). Most current CPUs
|
||||
have special support for AES256 so this should be faster. For older
|
||||
computers lacking this support, only CHACHA20 is supported.
|
||||
The encryption method to use ("aes128", "aes256", or "chacha20"). Most
|
||||
current CPUs have special support for AES256 so this should be faster. For
|
||||
older computers lacking this support, CHACHA20 is the fastest option.
|
||||
[default: *chacha20*]
|
||||
|
||||
*--magic <id>*::
|
||||
|
@ -258,10 +258,10 @@ side effects.
|
|||
. VpnCloud is not designed for high security use cases. Although the used crypto
|
||||
primitives are expected to be very secure, their application has not been
|
||||
reviewed.
|
||||
The shared key is hashed using _ScryptSalsa208Sha256_ to derive a key,
|
||||
which is used to encrypt the payload of messages using _ChaCha20Poly1305_ or
|
||||
_AES256-GCM_. The encryption includes an authentication that also protects the
|
||||
header.
|
||||
The shared key is hashed using _PBKDF2_HMAC_SHA256_ to derive a key,
|
||||
which is used to encrypt the payload of messages using _ChaCha20Poly1305_,
|
||||
_AES128-GCM_, or _AES256-GCM_. The encryption includes an authentication that
|
||||
also protects the header.
|
||||
This method does only protect against attacks on single messages but not
|
||||
against attacks that manipulate the message series itself (i.e. suppress
|
||||
messages, reorder them, or duplicate them).
|
||||
|
|
Loading…
Reference in New Issue