Switch to Ed25519 signature + XChaCha20
also add infoq nodeinfo
This commit is contained in:
@@ -2,6 +2,8 @@ use super::key::*;
|
||||
use crate::intf::*;
|
||||
use crate::xx::*;
|
||||
use crate::*;
|
||||
use chacha20::cipher::{NewCipher, StreamCipher};
|
||||
use chacha20::XChaCha20;
|
||||
use chacha20poly1305 as ch;
|
||||
use chacha20poly1305::aead::{AeadInPlace, NewAead};
|
||||
use core::convert::TryInto;
|
||||
@@ -16,7 +18,7 @@ pub type SharedSecret = [u8; 32];
|
||||
pub type Nonce = [u8; 24];
|
||||
|
||||
const DH_CACHE_SIZE: usize = 1024;
|
||||
pub const ENCRYPTION_OVERHEAD: usize = 16;
|
||||
pub const AEAD_OVERHEAD: usize = 16;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
struct DHCacheKey {
|
||||
@@ -222,7 +224,7 @@ impl Crypto {
|
||||
s
|
||||
}
|
||||
|
||||
pub fn decrypt_in_place(
|
||||
pub fn decrypt_in_place_aead(
|
||||
body: &mut Vec<u8>,
|
||||
nonce: &Nonce,
|
||||
shared_secret: &SharedSecret,
|
||||
@@ -236,20 +238,20 @@ impl Crypto {
|
||||
.map_err(logthru_crypto!())
|
||||
}
|
||||
|
||||
pub fn decrypt(
|
||||
pub fn decrypt_aead(
|
||||
body: &[u8],
|
||||
nonce: &Nonce,
|
||||
shared_secret: &SharedSecret,
|
||||
associated_data: Option<&[u8]>,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
let mut out = body.to_vec();
|
||||
Self::decrypt_in_place(&mut out, nonce, shared_secret, associated_data)
|
||||
Self::decrypt_in_place_aead(&mut out, nonce, shared_secret, associated_data)
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_crypto!())?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn encrypt_in_place(
|
||||
pub fn encrypt_in_place_aead(
|
||||
body: &mut Vec<u8>,
|
||||
nonce: &Nonce,
|
||||
shared_secret: &SharedSecret,
|
||||
@@ -264,16 +266,27 @@ impl Crypto {
|
||||
.map_err(logthru_crypto!())
|
||||
}
|
||||
|
||||
pub fn encrypt(
|
||||
pub fn encrypt_aead(
|
||||
body: &[u8],
|
||||
nonce: &Nonce,
|
||||
shared_secret: &SharedSecret,
|
||||
associated_data: Option<&[u8]>,
|
||||
) -> Result<Vec<u8>, String> {
|
||||
let mut out = body.to_vec();
|
||||
Self::encrypt_in_place(&mut out, nonce, shared_secret, associated_data)
|
||||
Self::encrypt_in_place_aead(&mut out, nonce, shared_secret, associated_data)
|
||||
.map_err(map_to_string)
|
||||
.map_err(logthru_crypto!())?;
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn crypt_in_place_no_auth(body: &mut Vec<u8>, nonce: &Nonce, shared_secret: &SharedSecret) {
|
||||
let mut cipher = XChaCha20::new(shared_secret.into(), nonce.into());
|
||||
cipher.apply_keystream(body);
|
||||
}
|
||||
|
||||
pub fn crypt_no_auth(body: &[u8], nonce: &Nonce, shared_secret: &SharedSecret) -> Vec<u8> {
|
||||
let mut out = body.to_vec();
|
||||
Self::crypt_in_place_no_auth(&mut out, nonce, shared_secret);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
@@ -29,14 +29,13 @@ use core::convert::TryInto;
|
||||
// sender_id: [u8; 32], // 0x2A: Node ID of the message source, which is the Ed25519 public key of the sender (must be verified with find_node if this is a new node_id/address combination)
|
||||
// recipient_id: [u8; 32], // 0x4A: Node ID of the intended recipient, which is the Ed25519 public key of the recipient (must be the receiving node, or a relay lease holder)
|
||||
// // 0x6A: message is appended (operations)
|
||||
// // encrypted by XChaCha20Poly1305(nonce,x25519(recipient_id, sender_secret_key))
|
||||
// // decryptable by XChaCha20Poly1305(nonce,x25519(sender_id, recipient_secret_key))
|
||||
// // entire header needs to be included in message digest, relays are not allowed to modify the envelope without invalidating the signature.
|
||||
// // encrypted by XChaCha20Poly1305(nonce,x25519(recipient_id, sender_secret_key))
|
||||
// signature: [u8; 64], // 0x?? (end-0x40): Ed25519 signature of the entire envelope including header is appended to the packet
|
||||
// // entire header needs to be included in message digest, relays are not allowed to modify the envelope without invalidating the signature.
|
||||
// }
|
||||
|
||||
pub const MAX_ENVELOPE_SIZE: usize = 65507;
|
||||
pub const MIN_ENVELOPE_SIZE: usize = 106;
|
||||
pub const AEAD_ADDITIONAL_SIZE: usize = 16;
|
||||
pub const MIN_ENVELOPE_SIZE: usize = 0x6A + 0x40; // Header + Signature
|
||||
pub const ENVELOPE_MAGIC: &[u8; 4] = b"VLID";
|
||||
pub const MIN_VERSION: u8 = 0u8;
|
||||
pub const MAX_VERSION: u8 = 0u8;
|
||||
@@ -77,7 +76,7 @@ impl Envelope {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_data(data: &[u8]) -> Result<Envelope, ()> {
|
||||
pub fn from_signed_data(data: &[u8]) -> Result<Envelope, ()> {
|
||||
// Ensure we are at least the length of the envelope
|
||||
if data.len() < MIN_ENVELOPE_SIZE {
|
||||
trace!("envelope too small: len={}", data.len());
|
||||
@@ -155,6 +154,12 @@ impl Envelope {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Get signature
|
||||
let signature = DHTSignature::new(data[(data.len() - 64)..].try_into().map_err(drop)?);
|
||||
|
||||
// Validate signature
|
||||
verify(&sender_id, &data[0..(data.len() - 64)], &signature).map_err(drop)?;
|
||||
|
||||
// Return envelope
|
||||
Ok(Self {
|
||||
version,
|
||||
@@ -176,13 +181,8 @@ impl Envelope {
|
||||
// Get DH secret
|
||||
let dh_secret = crypto.cached_dh(&self.sender_id, node_id_secret)?;
|
||||
|
||||
// Decrypt message and authenticate, including the envelope header as associated data to authenticate
|
||||
let body = Crypto::decrypt(
|
||||
&data[0x6A..],
|
||||
&self.nonce,
|
||||
&dh_secret,
|
||||
Some(&data[0..MIN_ENVELOPE_SIZE]),
|
||||
)?;
|
||||
// Decrypt message without authentication
|
||||
let body = Crypto::crypt_no_auth(&data[0x6A..data.len() - 64], &self.nonce, &dh_secret);
|
||||
|
||||
Ok(body)
|
||||
}
|
||||
@@ -203,7 +203,7 @@ impl Envelope {
|
||||
}
|
||||
|
||||
// Ensure body isn't too long
|
||||
let envelope_size: usize = body.len() + MIN_ENVELOPE_SIZE + AEAD_ADDITIONAL_SIZE;
|
||||
let envelope_size: usize = body.len() + MIN_ENVELOPE_SIZE;
|
||||
if envelope_size > MAX_ENVELOPE_SIZE {
|
||||
return Err(());
|
||||
}
|
||||
@@ -234,11 +234,23 @@ impl Envelope {
|
||||
.map_err(drop)?;
|
||||
|
||||
// Encrypt and authenticate message
|
||||
let encrypted_body =
|
||||
Crypto::encrypt(body, &self.nonce, &dh_secret, Some(&data[0..0x6A])).map_err(drop)?;
|
||||
let encrypted_body = Crypto::crypt_no_auth(body, &self.nonce, &dh_secret);
|
||||
|
||||
// Write body
|
||||
data[0x6A..].copy_from_slice(encrypted_body.as_slice());
|
||||
if !encrypted_body.is_empty() {
|
||||
data[0x6A..envelope_size - 64].copy_from_slice(encrypted_body.as_slice());
|
||||
}
|
||||
|
||||
// Sign the envelope
|
||||
let signature = sign(
|
||||
&self.sender_id,
|
||||
node_id_secret,
|
||||
&data[0..(envelope_size - 64)],
|
||||
)
|
||||
.map_err(drop)?;
|
||||
|
||||
// Append the signature
|
||||
data[(envelope_size - 64)..].copy_from_slice(&signature.bytes);
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
Reference in New Issue
Block a user