Updating crates & README

This commit is contained in:
Matéo Duparc 2021-05-03 13:23:56 +02:00
parent 01e593bbc5
commit ede47d9574
Signed by: hardcoresushi
GPG Key ID: 007F84120107191E
5 changed files with 28 additions and 29 deletions

View File

@ -14,9 +14,10 @@ rusqlite = {version = "0.25.1", features = ["bundled"]}
ed25519-dalek = "1" #for singing ed25519-dalek = "1" #for singing
x25519-dalek = "1.1" #for shared secret x25519-dalek = "1.1" #for shared secret
sha2 = "0.9.3" sha2 = "0.9.3"
hkdf = "0.10.0" hkdf = "0.11.0"
aes-gcm = "0.8.0" aes-gcm = "0.9.0" #PSEC
hmac = "0.10.1" aes-gcm-siv = "0.10.0" #Database
hmac = "0.11.0"
hex = "0.4.3" hex = "0.4.3"
strum_macros = "0.20.1" #display enums strum_macros = "0.20.1" #display enums
actix-web = "3" actix-web = "3"
@ -33,6 +34,5 @@ libmdns = "0.6" #mDNS advertiser
multicast_dns = "0.5" #mDNS browser multicast_dns = "0.5" #mDNS browser
base64 = "0.13.0" base64 = "0.13.0"
time = "0.2.25" time = "0.2.25"
aes-gcm-siv = "0.9.0" scrypt = "0.7.0"
scrypt = "0.6.3"
zeroize = "1.2.0" zeroize = "1.2.0"

View File

@ -1,7 +1,7 @@
# AIRA # AIRA
AIRA is peer-to-peer encrypted communication tool for local networks built on the [PSEC protocol](https://forge.chapril.org/hardcoresushi/PSEC). It allows to securely send text messages and files without any server or Internet access. AIRA is peer-to-peer encrypted communication tool for local networks built on the [PSEC protocol](https://forge.chapril.org/hardcoresushi/PSEC). It allows to securely send text messages and files without any server or Internet access.
<img src="https://forge.chapril.org/hardcoresushi/AIRA/raw/branch/master/screenshot.png"> ![Screenshot of a conversation between Alice and Bob on AIRA](/screenshot.png)
# Rationale # Rationale
When people want to send a file from one computer to another located only meters apart, they usually send it via mail. This mail usually goes through many servers around the world before reaching its final destination. When people want to send a file from one computer to another located only meters apart, they usually send it via mail. This mail usually goes through many servers around the world before reaching its final destination.
@ -19,7 +19,6 @@ AIRA is still under developement and is not ready for production usage yet. Not
- Automatic peer discovery using mDNS - Automatic peer discovery using mDNS
- Manual peer connection - Manual peer connection
- File transferts - File transferts
- Notifications
- Encrypted database - Encrypted database
- Contact verification - Contact verification
- IPv4/v6 compatibility - IPv4/v6 compatibility

View File

@ -4,8 +4,8 @@ use sha2::Sha384;
use hmac::{Hmac, Mac, NewMac}; use hmac::{Hmac, Mac, NewMac};
use scrypt::{scrypt, Params}; use scrypt::{scrypt, Params};
use rand_8::{RngCore, rngs::OsRng}; use rand_8::{RngCore, rngs::OsRng};
use aes_gcm::{aead::{Aead, generic_array::GenericArray}, NewAead}; use aes_gcm::{aead::Aead, NewAead, Nonce};
use aes_gcm_siv::{Aes256GcmSiv}; use aes_gcm_siv::Aes256GcmSiv;
use zeroize::Zeroize; use zeroize::Zeroize;
use strum_macros::Display; use strum_macros::Display;
use crate::utils::*; use crate::utils::*;
@ -128,7 +128,7 @@ impl ApplicationKeys {
pub fn compute_handshake_finished(local_handshake_traffic_secret: [u8; HASH_OUTPUT_LEN], handshake_hash: [u8; HASH_OUTPUT_LEN]) -> [u8; HASH_OUTPUT_LEN] { pub fn compute_handshake_finished(local_handshake_traffic_secret: [u8; HASH_OUTPUT_LEN], handshake_hash: [u8; HASH_OUTPUT_LEN]) -> [u8; HASH_OUTPUT_LEN] {
let mut finished_key = [0; HASH_OUTPUT_LEN]; let mut finished_key = [0; HASH_OUTPUT_LEN];
hkdf_expand_label(&local_handshake_traffic_secret, "finished", None, &mut finished_key); hkdf_expand_label(&local_handshake_traffic_secret, "finished", None, &mut finished_key);
let mut hmac = Hmac::<Sha384>::new_varkey(&finished_key).unwrap(); let mut hmac = Hmac::<Sha384>::new_from_slice(&finished_key).unwrap();
hmac.update(&handshake_hash); hmac.update(&handshake_hash);
hmac.finalize().into_bytes().as_slice().try_into().unwrap() hmac.finalize().into_bytes().as_slice().try_into().unwrap()
} }
@ -136,7 +136,7 @@ pub fn compute_handshake_finished(local_handshake_traffic_secret: [u8; HASH_OUTP
pub fn verify_handshake_finished(peer_handshake_finished: [u8; HASH_OUTPUT_LEN], peer_handshake_traffic_secret: [u8; HASH_OUTPUT_LEN], handshake_hash: [u8; HASH_OUTPUT_LEN]) -> bool { pub fn verify_handshake_finished(peer_handshake_finished: [u8; HASH_OUTPUT_LEN], peer_handshake_traffic_secret: [u8; HASH_OUTPUT_LEN], handshake_hash: [u8; HASH_OUTPUT_LEN]) -> bool {
let mut peer_finished_key = [0; HASH_OUTPUT_LEN]; let mut peer_finished_key = [0; HASH_OUTPUT_LEN];
hkdf_expand_label(&peer_handshake_traffic_secret, "finished", None, &mut peer_finished_key); hkdf_expand_label(&peer_handshake_traffic_secret, "finished", None, &mut peer_finished_key);
let mut hmac = Hmac::<Sha384>::new_varkey(&peer_finished_key).unwrap(); let mut hmac = Hmac::<Sha384>::new_from_slice(&peer_finished_key).unwrap();
hmac.update(&handshake_hash); hmac.update(&handshake_hash);
hmac.verify(&peer_handshake_finished).is_ok() hmac.verify(&peer_handshake_finished).is_ok()
} }
@ -161,11 +161,11 @@ pub fn encrypt_data(data: &[u8], master_key: &[u8]) -> Result<Vec<u8>, CryptoErr
if master_key.len() != MASTER_KEY_LEN { if master_key.len() != MASTER_KEY_LEN {
return Err(CryptoError::InvalidLength); return Err(CryptoError::InvalidLength);
} }
let cipher = Aes256GcmSiv::new(GenericArray::from_slice(master_key)); let cipher = Aes256GcmSiv::new_from_slice(master_key).unwrap();
let mut iv = [0; IV_LEN]; let mut iv = [0; IV_LEN];
OsRng.fill_bytes(&mut iv); //use it for IV for now OsRng.fill_bytes(&mut iv); //use it for IV for now
let mut cipher_text = iv.to_vec(); let mut cipher_text = iv.to_vec();
cipher_text.extend(cipher.encrypt(GenericArray::from_slice(&iv), data).unwrap()); cipher_text.extend(cipher.encrypt(Nonce::from_slice(&iv), data).unwrap());
Ok(cipher_text) Ok(cipher_text)
} }
@ -179,8 +179,8 @@ pub fn decrypt_data(data: &[u8], master_key: &[u8]) -> Result<Vec<u8>, CryptoErr
if data.len() <= IV_LEN || master_key.len() != MASTER_KEY_LEN { if data.len() <= IV_LEN || master_key.len() != MASTER_KEY_LEN {
return Err(CryptoError::InvalidLength); return Err(CryptoError::InvalidLength);
} }
let cipher = Aes256GcmSiv::new(GenericArray::from_slice(master_key)); let cipher = Aes256GcmSiv::new_from_slice(master_key).unwrap();
match cipher.decrypt(GenericArray::from_slice(&data[..IV_LEN]), &data[IV_LEN..]) { match cipher.decrypt(Nonce::from_slice(&data[..IV_LEN]), &data[IV_LEN..]) {
Ok(data) => { Ok(data) => {
Ok(data) Ok(data)
}, },
@ -202,8 +202,8 @@ pub fn encrypt_master_key(mut master_key: [u8; MASTER_KEY_LEN], password: &[u8])
scrypt(password, &salt, &scrypt_params(), &mut password_hash).unwrap(); scrypt(password, &salt, &scrypt_params(), &mut password_hash).unwrap();
let mut output = [0; IV_LEN+MASTER_KEY_LEN+AES_TAG_LEN]; let mut output = [0; IV_LEN+MASTER_KEY_LEN+AES_TAG_LEN];
OsRng.fill_bytes(&mut output); //use it for IV for now OsRng.fill_bytes(&mut output); //use it for IV for now
let cipher = Aes256GcmSiv::new(GenericArray::from_slice(&password_hash)); let cipher = Aes256GcmSiv::new_from_slice(&password_hash).unwrap();
let encrypted_master_key = cipher.encrypt(GenericArray::from_slice(&output[..IV_LEN]), master_key.as_ref()).unwrap(); let encrypted_master_key = cipher.encrypt(Nonce::from_slice(&output[..IV_LEN]), master_key.as_ref()).unwrap();
master_key.zeroize(); master_key.zeroize();
password_hash.zeroize(); password_hash.zeroize();
encrypted_master_key.into_iter().enumerate().for_each(|i|{ encrypted_master_key.into_iter().enumerate().for_each(|i|{
@ -218,8 +218,8 @@ pub fn decrypt_master_key(encrypted_master_key: &[u8], password: &[u8], salt: &[
} }
let mut password_hash = [0; PASSWORD_HASH_LEN]; let mut password_hash = [0; PASSWORD_HASH_LEN];
scrypt(password, salt, &scrypt_params(), &mut password_hash).unwrap(); scrypt(password, salt, &scrypt_params(), &mut password_hash).unwrap();
let cipher = Aes256GcmSiv::new(GenericArray::from_slice(&password_hash)); let cipher = Aes256GcmSiv::new_from_slice(&password_hash).unwrap();
let result = match cipher.decrypt(GenericArray::from_slice(&encrypted_master_key[..IV_LEN]), &encrypted_master_key[IV_LEN..]) { let result = match cipher.decrypt(Nonce::from_slice(&encrypted_master_key[..IV_LEN]), &encrypted_master_key[IV_LEN..]) {
Ok(master_key) => { Ok(master_key) => {
if master_key.len() == MASTER_KEY_LEN { if master_key.len() == MASTER_KEY_LEN {
Ok(master_key.try_into().unwrap()) Ok(master_key.try_into().unwrap())

View File

@ -415,7 +415,7 @@ impl Identity {
Ok(Identity { Ok(Identity {
name: name.to_owned(), name: name.to_owned(),
keypair, keypair,
master_key: master_key, master_key,
}) })
} }

View File

@ -5,7 +5,7 @@ use ed25519_dalek::{ed25519::signature::Signature, Verifier, PUBLIC_KEY_LENGTH,
use x25519_dalek; use x25519_dalek;
use rand_7::{RngCore, rngs::OsRng}; use rand_7::{RngCore, rngs::OsRng};
use sha2::{Sha384, Digest}; use sha2::{Sha384, Digest};
use aes_gcm::{Aes128Gcm, aead::Aead, NewAead, aead::Payload, aead::generic_array::GenericArray}; use aes_gcm::{Aes128Gcm, aead::Aead, NewAead, aead::Payload, Nonce};
use crate::utils::*; use crate::utils::*;
use crate::crypto::*; use crate::crypto::*;
use crate::identity::Identity; use crate::identity::Identity;
@ -112,9 +112,9 @@ impl Session {
} }
fn on_handshake_successful(&mut self, application_keys: ApplicationKeys){ fn on_handshake_successful(&mut self, application_keys: ApplicationKeys){
self.local_cipher = Some(Aes128Gcm::new_varkey(&application_keys.local_key).unwrap()); self.local_cipher = Some(Aes128Gcm::new_from_slice(&application_keys.local_key).unwrap());
self.local_iv = Some(application_keys.local_iv); self.local_iv = Some(application_keys.local_iv);
self.peer_cipher = Some(Aes128Gcm::new_varkey(&application_keys.peer_key).unwrap()); self.peer_cipher = Some(Aes128Gcm::new_from_slice(&application_keys.peer_key).unwrap());
self.peer_iv = Some(application_keys.peer_iv); self.peer_iv = Some(application_keys.peer_iv);
self.handshake_sent_buff.clear(); self.handshake_sent_buff.clear();
self.handshake_sent_buff.shrink_to_fit(); self.handshake_sent_buff.shrink_to_fit();
@ -156,19 +156,19 @@ impl Session {
auth_msg[..PUBLIC_KEY_LENGTH].copy_from_slice(&identity.get_public_key()); auth_msg[..PUBLIC_KEY_LENGTH].copy_from_slice(&identity.get_public_key());
auth_msg[PUBLIC_KEY_LENGTH..].copy_from_slice(&identity.sign(ephemeral_public_key.as_bytes())); auth_msg[PUBLIC_KEY_LENGTH..].copy_from_slice(&identity.sign(ephemeral_public_key.as_bytes()));
//encrypt auth_msg //encrypt auth_msg
let local_cipher = Aes128Gcm::new_varkey(&handshake_keys.local_key).unwrap(); let local_cipher = Aes128Gcm::new_from_slice(&handshake_keys.local_key).unwrap();
let mut local_handshake_counter = 0; let mut local_handshake_counter = 0;
let nonce = iv_to_nonce(&handshake_keys.local_iv, &mut local_handshake_counter); let nonce = iv_to_nonce(&handshake_keys.local_iv, &mut local_handshake_counter);
let encrypted_auth_msg = local_cipher.encrypt(GenericArray::from_slice(&nonce), auth_msg.as_ref()).unwrap(); let encrypted_auth_msg = local_cipher.encrypt(Nonce::from_slice(&nonce), auth_msg.as_ref()).unwrap();
self.handshake_write(&encrypted_auth_msg).await?; self.handshake_write(&encrypted_auth_msg).await?;
let mut encrypted_peer_auth_msg = [0; PUBLIC_KEY_LENGTH+SIGNATURE_LENGTH+AES_TAG_LEN]; let mut encrypted_peer_auth_msg = [0; PUBLIC_KEY_LENGTH+SIGNATURE_LENGTH+AES_TAG_LEN];
self.handshake_read(&mut encrypted_peer_auth_msg).await?; self.handshake_read(&mut encrypted_peer_auth_msg).await?;
//decrypt peer_auth_msg //decrypt peer_auth_msg
let peer_cipher = Aes128Gcm::new_varkey(&handshake_keys.peer_key).unwrap(); let peer_cipher = Aes128Gcm::new_from_slice(&handshake_keys.peer_key).unwrap();
let mut peer_handshake_counter = 0; let mut peer_handshake_counter = 0;
let peer_nonce = iv_to_nonce(&handshake_keys.peer_iv, &mut peer_handshake_counter); let peer_nonce = iv_to_nonce(&handshake_keys.peer_iv, &mut peer_handshake_counter);
match peer_cipher.decrypt(GenericArray::from_slice(&peer_nonce), encrypted_peer_auth_msg.as_ref()) { match peer_cipher.decrypt(Nonce::from_slice(&peer_nonce), encrypted_peer_auth_msg.as_ref()) {
Ok(peer_auth_msg) => { Ok(peer_auth_msg) => {
//verify ephemeral public key signature //verify ephemeral public key signature
self.peer_public_key = Some(to_array_32(&peer_auth_msg[..PUBLIC_KEY_LENGTH])); self.peer_public_key = Some(to_array_32(&peer_auth_msg[..PUBLIC_KEY_LENGTH]));
@ -222,7 +222,7 @@ impl Session {
aad: &cipher_len aad: &cipher_len
}; };
let nonce = iv_to_nonce(&self.local_iv.unwrap(), &mut self.local_counter); let nonce = iv_to_nonce(&self.local_iv.unwrap(), &mut self.local_counter);
let cipher_text = self.local_cipher.as_ref().unwrap().encrypt(GenericArray::from_slice(&nonce), payload).unwrap(); let cipher_text = self.local_cipher.as_ref().unwrap().encrypt(Nonce::from_slice(&nonce), payload).unwrap();
[&cipher_len, cipher_text.as_slice()].concat() [&cipher_len, cipher_text.as_slice()].concat()
} }
@ -247,7 +247,7 @@ impl Session {
msg: &cipher_text, msg: &cipher_text,
aad: &message_len aad: &message_len
}; };
match peer_cipher.decrypt(GenericArray::from_slice(&peer_nonce), payload) { match peer_cipher.decrypt(Nonce::from_slice(&peer_nonce), payload) {
Ok(plain_text) => Ok(Session::unpad(plain_text)), Ok(plain_text) => Ok(Session::unpad(plain_text)),
Err(_) => Err(SessionError::TransmissionCorrupted) Err(_) => Err(SessionError::TransmissionCorrupted)
} }