Updating crates & README
This commit is contained in:
parent
01e593bbc5
commit
ede47d9574
10
Cargo.toml
10
Cargo.toml
@ -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"
|
@ -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
|
||||||
|
@ -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())
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user