2016-02-05 15:58:32 +00:00
|
|
|
// VpnCloud - Peer-to-Peer VPN
|
2017-07-22 14:49:53 +00:00
|
|
|
// Copyright (C) 2015-2017 Dennis Schwerdel
|
2016-02-05 15:58:32 +00:00
|
|
|
// This software is licensed under GPL-3 or newer (see LICENSE.md)
|
|
|
|
|
2019-01-04 12:53:12 +00:00
|
|
|
use ring::aead::*;
|
2019-01-08 19:32:47 +00:00
|
|
|
use ring::pbkdf2;
|
|
|
|
use ring::rand::*;
|
|
|
|
use ring::digest::*;
|
2015-11-30 16:27:50 +00:00
|
|
|
|
|
|
|
use super::types::Error;
|
|
|
|
|
|
|
|
|
2017-07-22 14:34:20 +00:00
|
|
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub enum CryptoMethod {
|
2017-07-22 14:42:32 +00:00
|
|
|
#[serde(rename = "chacha20")]
|
|
|
|
ChaCha20,
|
|
|
|
#[serde(rename = "aes256")]
|
|
|
|
AES256
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
|
2019-01-04 12:53:12 +00:00
|
|
|
pub struct CryptoData {
|
|
|
|
sealing_key: SealingKey,
|
|
|
|
opening_key: OpeningKey,
|
|
|
|
nonce: Vec<u8>
|
|
|
|
}
|
|
|
|
|
2019-01-08 19:32:47 +00:00
|
|
|
#[allow(unknown_lints, clippy::large_enum_variant)]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub enum Crypto {
|
|
|
|
None,
|
2019-01-04 12:53:12 +00:00
|
|
|
ChaCha20Poly1305(CryptoData),
|
|
|
|
AES256GCM(CryptoData)
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
|
2019-01-04 12:53:12 +00:00
|
|
|
fn inc_nonce(nonce: &mut [u8]) {
|
|
|
|
let l = nonce.len();
|
|
|
|
for i in (0..l).rev() {
|
|
|
|
let mut num = nonce[i];
|
2015-11-30 16:27:50 +00:00
|
|
|
num = num.wrapping_add(1);
|
2019-01-04 12:53:12 +00:00
|
|
|
nonce[i] = num;
|
2015-11-30 16:27:50 +00:00
|
|
|
if num > 0 {
|
2019-01-08 19:32:47 +00:00
|
|
|
return
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-08 19:32:47 +00:00
|
|
|
warn!("Nonce overflowed");
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Crypto {
|
2016-06-29 06:43:39 +00:00
|
|
|
#[inline]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub fn init() {
|
|
|
|
}
|
|
|
|
|
2016-06-29 06:43:39 +00:00
|
|
|
#[inline]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub fn sodium_version() -> String {
|
2019-01-08 19:32:47 +00:00
|
|
|
"0".to_string()
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
|
2016-06-29 06:43:39 +00:00
|
|
|
#[inline]
|
2015-11-30 22:04:24 +00:00
|
|
|
pub fn aes256_available() -> bool {
|
2019-01-04 12:53:12 +00:00
|
|
|
true
|
2015-11-30 22:04:24 +00:00
|
|
|
}
|
|
|
|
|
2016-06-29 06:43:39 +00:00
|
|
|
#[inline]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub fn method(&self) -> u8 {
|
2016-06-11 14:08:57 +00:00
|
|
|
match *self {
|
|
|
|
Crypto::None => 0,
|
|
|
|
Crypto::ChaCha20Poly1305{..} => 1,
|
|
|
|
Crypto::AES256GCM{..} => 2
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-29 06:43:39 +00:00
|
|
|
#[inline]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub fn nonce_bytes(&self) -> usize {
|
2016-06-11 14:08:57 +00:00
|
|
|
match *self {
|
|
|
|
Crypto::None => 0,
|
2019-01-04 12:53:12 +00:00
|
|
|
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.sealing_key.algorithm().nonce_len()
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-29 06:43:39 +00:00
|
|
|
#[inline]
|
2019-01-01 23:35:14 +00:00
|
|
|
#[allow(unknown_lints,clippy::match_same_arms)]
|
2015-11-30 16:27:50 +00:00
|
|
|
pub fn additional_bytes(&self) -> usize {
|
2016-06-11 14:08:57 +00:00
|
|
|
match *self {
|
|
|
|
Crypto::None => 0,
|
2019-01-08 19:32:47 +00:00
|
|
|
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => data.sealing_key.algorithm().tag_len()
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn from_shared_key(method: CryptoMethod, password: &str) -> Self {
|
2019-01-04 12:53:12 +00:00
|
|
|
let algo = match method {
|
|
|
|
CryptoMethod::ChaCha20 => &CHACHA20_POLY1305,
|
|
|
|
CryptoMethod::AES256 => &AES_256_GCM
|
|
|
|
};
|
2019-01-08 19:32:47 +00:00
|
|
|
let mut key: Vec<u8> = Vec::with_capacity(algo.key_len());
|
|
|
|
for _ in 0..algo.key_len() {
|
|
|
|
key.push(0);
|
|
|
|
}
|
|
|
|
let salt = b"vpncloudVPNCLOUDvpncl0udVpnCloud";
|
|
|
|
pbkdf2::derive(&SHA256, 4096, salt, password.as_bytes(), &mut key);
|
2019-01-04 12:53:12 +00:00
|
|
|
let sealing_key = SealingKey::new(algo, &key[..algo.key_len()]).expect("Failed to create key");
|
|
|
|
let opening_key = OpeningKey::new(algo, &key[..algo.key_len()]).expect("Failed to create key");
|
|
|
|
let mut nonce: Vec<u8> = Vec::with_capacity(algo.nonce_len());
|
|
|
|
for _ in 0..algo.nonce_len() {
|
|
|
|
nonce.push(0);
|
|
|
|
}
|
2019-01-08 19:32:47 +00:00
|
|
|
if SystemRandom::new().fill(&mut nonce).is_err() {
|
|
|
|
fail!("Randomizing nonce failed");
|
|
|
|
}
|
2019-01-04 12:53:12 +00:00
|
|
|
let data = CryptoData { sealing_key, opening_key, nonce };
|
2015-11-30 16:27:50 +00:00
|
|
|
match method {
|
2019-01-04 12:53:12 +00:00
|
|
|
CryptoMethod::ChaCha20 => Crypto::ChaCha20Poly1305(data),
|
|
|
|
CryptoMethod::AES256 => Crypto::AES256GCM(data)
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-01 21:55:15 +00:00
|
|
|
pub fn decrypt(&self, buf: &mut [u8], nonce: &[u8], header: &[u8]) -> Result<usize, Error> {
|
2016-06-11 14:08:57 +00:00
|
|
|
match *self {
|
|
|
|
Crypto::None => Ok(buf.len()),
|
2019-01-04 12:53:12 +00:00
|
|
|
Crypto::ChaCha20Poly1305(ref data) | Crypto::AES256GCM(ref data) => {
|
2019-01-08 19:32:47 +00:00
|
|
|
match open_in_place(&data.opening_key, nonce, header, 0, buf) {
|
|
|
|
Ok(plaintext) => Ok(plaintext.len()),
|
|
|
|
Err(_) => Err(Error::Crypto("Failed to decrypt"))
|
|
|
|
}
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-01 21:55:15 +00:00
|
|
|
pub fn encrypt(&mut self, buf: &mut [u8], mlen: usize, nonce_bytes: &mut [u8], header: &[u8]) -> usize {
|
2019-01-08 19:32:47 +00:00
|
|
|
let tag_len = self.additional_bytes();
|
2016-06-11 14:08:57 +00:00
|
|
|
match *self {
|
|
|
|
Crypto::None => mlen,
|
2019-01-04 12:53:12 +00:00
|
|
|
Crypto::ChaCha20Poly1305(ref mut data) | Crypto::AES256GCM(ref mut data) => {
|
|
|
|
inc_nonce(&mut data.nonce);
|
|
|
|
assert!(buf.len() - mlen >= tag_len);
|
|
|
|
let buf = &mut buf[.. mlen + tag_len];
|
2019-01-08 19:32:47 +00:00
|
|
|
let new_len = seal_in_place(&data.sealing_key, &data.nonce, header, buf, tag_len).expect("Failed to encrypt");
|
|
|
|
nonce_bytes.clone_from_slice(&data.nonce);
|
2019-01-04 12:53:12 +00:00
|
|
|
new_len
|
2015-11-30 16:27:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|