use crate::error::Error;
use crate::node::Address;
use crate::node::Center;
use crate::transaction::Class;
use sodiumoxide::crypto::box_::{self, curve25519xsalsa20poly1305::Nonce};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Message {
pub class: Class,
pub source: Address,
pub target: Address,
pub topic: Address,
pub seed: Seed,
pub body: Body,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Body {
is_plain: bool,
bytes: Vec<u8>,
}
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Seed(Nonce);
impl Message {
pub fn new(
class: Class,
source: Address,
target: Address,
topic: Address,
body: Vec<u8>,
) -> Self {
Self {
class,
source,
target,
topic,
seed: Seed::new(box_::gen_nonce()),
body: Body::new(body),
}
}
pub fn create(
class: Class,
source: Address,
target: Address,
topic: Address,
seed: Seed,
body: Vec<u8>,
) -> Self {
Self {
class,
source,
target,
topic,
seed,
body: Body::new(body),
}
}
pub fn encrypt(&mut self, center: &Center) {
self.body.encrypt(&self.seed, ¢er, &self.target);
}
pub fn decrypt(&mut self, center: &Center) -> Result<(), Error> {
self.body.decrypt(&self.seed, ¢er, &self.source)
}
pub fn len(&self) -> [u8; 2] {
self.body.len()
}
}
impl Body {
pub fn new(bytes: Vec<u8>) -> Self {
Self {
is_plain: true,
bytes,
}
}
pub fn as_bytes(&self) -> Vec<u8> {
self.bytes.clone()
}
fn encrypt(&mut self, seed: &Seed, center: &Center, target: &Address) {
if self.is_plain {
let enc = box_::seal(&self.bytes, &seed.0, &target.key, ¢er.secret);
self.bytes = enc;
self.is_plain = false;
}
}
fn decrypt(&mut self, seed: &Seed, center: &Center, source: &Address) -> Result<(), Error> {
if !self.is_plain {
let dec = box_::open(&self.bytes, &seed.0, &source.key, ¢er.secret)?;
self.bytes = dec;
self.is_plain = true;
Ok(())
} else {
Err(Error::Invalid(String::from("not encrypted")))
}
}
pub fn len(&self) -> [u8; 2] {
crate::util::compute_length(&self.bytes)
}
}
impl Seed {
fn new(nonce: Nonce) -> Self {
Self(nonce)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if let Some(nonce) = Nonce::from_slice(bytes) {
Ok(Self(nonce))
} else {
Err(Error::Invalid(String::from(
"provided nonce bytes are invalid",
)))
}
}
pub fn as_bytes(&self) -> [u8; 24] {
let mut bytes: [u8; 24] = [0; 24];
for (i, j) in self.0.as_ref().into_iter().enumerate() {
bytes[i] = *j;
}
return bytes;
}
}
#[cfg(test)]
mod tests {
use super::*;
use sodiumoxide::crypto::box_;
#[test]
fn test_seed_parse() {
let seed = box_::gen_nonce();
let s = Seed::from_bytes(&seed.0).unwrap();
assert_eq!(s.as_bytes(), seed.0[..]);
}
#[test]
fn test_message_encrypt() {
let mut m = Message::new(
Class::Ping,
Address::generate("a"),
Address::generate("b"),
Address::random(),
Vec::new(),
);
let center = Center::new(box_::gen_keypair().1, String::from(""), 0);
m.encrypt(¢er);
assert_ne!(m.body.as_bytes().len(), 1);
}
#[test]
fn test_message_decrypt() {
let (theirpk, theirsk) = box_::gen_keypair();
let (ourpk, oursk) = box_::gen_keypair();
let mut m = Message::new(
Class::Ping,
Address::new(theirpk),
Address::new(ourpk),
Address::random(),
[111, 42].to_vec(),
);
let theircenter = Center::new(theirsk, String::from(""), 0);
let ourcenter = Center::new(oursk, String::from(""), 0);
m.encrypt(&theircenter);
m.decrypt(&ourcenter).unwrap();
assert_eq!(m.body.as_bytes(), [111, 42]);
}
#[test]
fn test_length_empty() {
let body = Body::new(Vec::new());
let len = body.len();
assert_eq!(len, [0, 0]);
}
#[test]
fn test_length_once() {
let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let body = Body::new(data);
let len = body.len();
assert_eq!(len, [0, 10]);
}
#[test]
fn test_length_full() {
let mut data = Vec::new();
for i in 0..255 {
data.push(i);
}
for i in 0..255 {
data.push(i);
}
data.push(42);
let body = Body::new(data);
let len = body.len();
assert_eq!(len, [2, 1]);
}
}