Browse Source

Cryptography in message (signing, checks), new serialization for PublicKey

master
Lev 3 years ago
parent
commit
41a0842193
  1. 35
      examples/test_ip_connection.rs
  2. 65
      src/crypto.rs
  3. 17
      src/interface.rs
  4. 31
      src/ironforce.rs
  5. 184
      src/message.rs

35
examples/test_ip_connection.rs

@ -1,11 +1,17 @@
use std::net;
use ironforce::interfaces::ip::IPInterface;
#[cfg(feature = "std")]
use ironforce::interface::Interface;
#[cfg(feature = "std")]
use ironforce::interfaces::ip::IPInterface;
#[cfg(feature = "std")]
use std::net;
#[cfg(feature = "std")]
fn main() {
let mut listener = match net::TcpListener::bind("0.0.0.0:60000") {
Ok(tmp) => tmp,
Err(_) => { return; }
Err(_) => {
return;
}
};
let mut interface1 = IPInterface {
id: String::from("IP interface"),
@ -14,9 +20,11 @@ fn main() {
};
let option_listener = net::TcpListener::bind("0.0.0.0:50000");
let mut listener= match option_listener {
let mut listener = match option_listener {
Ok(tmp) => tmp,
Err(_) => { return; }
Err(_) => {
return;
}
};
let mut interface2 = IPInterface {
id: String::from("IP interface"),
@ -24,17 +32,26 @@ fn main() {
listener,
};
let t1 = std::thread::spawn(move || { interface1.send(&[0,0,1,1], Some(String::from("0.0.0.0:50000"))); interface1});
let t2 = std::thread::spawn(move || { interface2.main_loop_iteration(); interface2});
let t1 = std::thread::spawn(move || {
interface1.send(&[0, 0, 1, 1], Some(String::from("0.0.0.0:50000")));
interface1
});
let t2 = std::thread::spawn(move || {
interface2.main_loop_iteration();
interface2
});
let res1 = t1.join();
match res1 {
Ok(_) => println!("Ok"),
Err(e) => println!("{:?}", e)
Err(e) => println!("{:?}", e),
}
let res2 = t2.join();
match res2 {
Ok(_) => println!("Ok"),
Err(e) => println!("{:?}", e)
Err(e) => println!("{:?}", e),
}
// res1.unwrap();
}
#[cfg(not(feature = "std"))]
fn main() {}

65
src/crypto.rs

@ -1,12 +1,18 @@
/// This module has wrappers for cryptography with RSA algorithms.
/// Its main structs - `PublicKey` and `Keys` implement all functions for key generation, signatures and asymmetric encryption
use alloc::vec::Vec;
use alloc::string::String;
use serde::{Deserialize, Serialize};
use rsa::{RsaPublicKey, RsaPrivateKey, PaddingScheme, PublicKey as RPK};
use rsa::{RsaPublicKey, RsaPrivateKey, PaddingScheme, PublicKey as RPK, PublicKeyParts, BigUint};
use rsa::errors::Result as RsaRes;
use rand::rngs::OsRng;
use sha2::{Digest, Sha224};
use alloc::vec;
use crate::res::{IFError, IFResult};
static KEY_LENGTH: usize = 2048;
static ENCRYPTION_CHUNK_SIZE: usize = 240;
static ENCRYPTION_OUTPUT_CHUNK_SIZE: usize = 256;
/// Public key of a node
@ -18,26 +24,50 @@ pub struct PublicKey {
impl PublicKey {
/// Check if the sign is valid for given data and key
pub fn verify_sign(&self, data: &[u8], sign: &[u8]) -> bool {
self.key.verify(PaddingScheme::PKCS1v15Sign { hash: None }, data, sign).is_ok()
self.key.verify(PaddingScheme::PKCS1v15Sign { hash: None }, &Sha224::new().chain(data).result().to_vec(), sign).is_ok()
}
/// Encrypt some data for a user with this public key
pub fn encrypt_data(&self, data: &[u8]) -> RsaRes<Vec<u8>> {
if data.len() <= ENCRYPTION_CHUNK_SIZE {
self.key.encrypt(&mut OsRng {}, PaddingScheme::PKCS1v15Encrypt, data)
} else {
let mut res = self.key.encrypt(&mut OsRng {}, PaddingScheme::PKCS1v15Encrypt, &data[..ENCRYPTION_CHUNK_SIZE])?;
res.extend(self.encrypt_data(&data[ENCRYPTION_CHUNK_SIZE..])?);
Ok(res)
}
}
pub fn to_vec(&self) -> serde_cbor::Result<Vec<u8>> {
serde_cbor::to_vec(&self.key)
pub fn to_vec(&self) -> Vec<u8> {
let n_bytes = self.key.n().to_bytes_be();
let e_bytes = self.key.e().to_bytes_be();
let mut res = vec![
(n_bytes.len() / 256) as u8, (n_bytes.len() % 256) as u8,
(e_bytes.len() / 256) as u8, (e_bytes.len() % 256) as u8,
];
res.extend(n_bytes);
res.extend(e_bytes);
res
}
pub fn from_vec(data: Vec<u8>) -> serde_cbor::Result<Self> {
serde_cbor::from_slice(data.as_slice())
pub fn from_vec(data: Vec<u8>) -> IFResult<Self> {
if data.len() < 4 {
return Err(IFError::SerializationError(String::from("Not enough bytes in serialized PublicKey")))
}
let n_len = data[0] as usize * 256 + data[1] as usize;
let e_len = data[2] as usize * 256 + data[3] as usize;
if data.len() != e_len + n_len + 4 {
return Err(IFError::SerializationError(String::from("Not enough bytes in serialized PublicKey")))
}
let n_bytes = &data[4..n_len + 4];
let e_bytes = &data[4 + n_len..e_len + n_len + 4];
Ok(Self { key: RsaPublicKey::new(BigUint::from_bytes_be(n_bytes), BigUint::from_bytes_be(e_bytes))? })
}
}
impl PublicKey {
fn hash(&self) -> Vec<u8> {
self.to_vec().unwrap()
self.to_vec()
}
}
@ -64,12 +94,18 @@ impl Keys {
impl Keys {
/// Sign content using these keys
pub fn sign(&self, content: &[u8]) -> RsaRes<Vec<u8>> {
self.private_key.sign(PaddingScheme::PKCS1v15Sign { hash: None }, content)
self.private_key.sign(PaddingScheme::PKCS1v15Sign { hash: None }, &Sha224::new().chain(content).result().to_vec())
}
/// Decrypt data
pub fn decrypt_data(&self, data_encrypted: &[u8]) -> RsaRes<Vec<u8>> {
if data_encrypted.len() <= ENCRYPTION_OUTPUT_CHUNK_SIZE {
self.private_key.decrypt(PaddingScheme::PKCS1v15Encrypt, data_encrypted)
} else {
let mut res = self.private_key.decrypt(PaddingScheme::PKCS1v15Encrypt, &data_encrypted[..ENCRYPTION_OUTPUT_CHUNK_SIZE])?;
res.extend(self.decrypt_data(&data_encrypted[ENCRYPTION_OUTPUT_CHUNK_SIZE..])?);
Ok(res)
}
}
/// Get public key
@ -80,17 +116,19 @@ impl Keys {
#[test]
fn test_encrypt() {
let data = vec![0, 5, 8, 135, 67];
let data = vec![0, 5, 8, 135, 67, 45, 32, 5];
let keys = Keys::generate();
let data_encrypted = keys.get_public().encrypt_data(&data).unwrap();
assert_eq!(
keys.decrypt_data(&keys.get_public().encrypt_data(&data).unwrap()).unwrap(),
keys.decrypt_data(&data_encrypted).unwrap(),
data
);
assert_eq!(
keys.decrypt_data(&keys.get_public().encrypt_data(&data.repeat(300)).unwrap()).unwrap(),
data.repeat(300)
);
}
#[cfg(test)]
use alloc::vec;
#[test]
fn test_invalid_encrypt() {
let data = vec![0, 5, 8, 135, 67];
@ -104,6 +142,7 @@ fn test_signing() {
let data = vec![0, 5, 8, 135, 67];
let keys = Keys::generate();
assert!(keys.get_public().verify_sign(&data, &keys.sign(&data).unwrap()));
assert!(keys.get_public().verify_sign(&data.repeat(340), &keys.sign(&data.repeat(340)).unwrap()));
}
#[test]

17
src/interface.rs

@ -1,7 +1,6 @@
use alloc::string::String;
use crate::message::MessageBytes;
use crate::res::IFResult;
use alloc::string::String;
/// Some data that can be provided to the interface to send the message to a target.
///
@ -16,7 +15,6 @@ pub trait InterfaceRequirements {}
#[cfg(feature = "std")]
pub trait InterfaceRequirements: Send + Sync {}
/// An interface that can be used to
pub trait Interface: InterfaceRequirements {
/// Run one main loop iteration.
@ -34,7 +32,11 @@ pub trait Interface: InterfaceRequirements {
fn id(&self) -> &str;
/// Send a message. If no `interface_data` is provided, we should consider it to be a broadcast.
/// If, on the other hand, `interface_data` is not `None`, it should be used to send the message to the target.
fn send(&mut self, message: &[u8] /*MessageBytes*/, interface_data: Option<TargetingData>) -> IFResult<()>;
fn send(
&mut self,
message: &[u8], /*MessageBytes*/
interface_data: Option<TargetingData>,
) -> IFResult<()>;
/// Receive a message through this interface. Returns a result with an option of (message bytes, target).
/// `None` means there is no message available at the time.
/// The implementations of this function shouldn't wait for new messages, but
@ -65,14 +67,13 @@ pub mod test_interface {
}
fn send(&mut self, message: &[u8], interface_data: Option<TargetingData>) -> IFResult<()> {
self.messages.push((Vec::from(message), interface_data.unwrap_or_default()));
self.messages
.push((Vec::from(message), interface_data.unwrap_or_default()));
Ok(())
}
fn receive(&mut self) -> IFResult<Option<(MessageBytes, TargetingData)>> {
Ok(
self.messages.pop()
)
Ok(self.messages.pop())
}
}
}

31
src/ironforce.rs

@ -1,11 +1,10 @@
use alloc::vec::Vec;
use alloc::vec;
use crate::crypto::PublicKey;
use crate::message::{Message, MessageType, ServiceMessageType};
use crate::res::{IFError, IFResult};
use crate::transport::Transport;
use crate::tunnel::Tunnel;
use alloc::vec;
use alloc::vec::Vec;
/// Main worker
pub struct IronForce {
@ -43,16 +42,30 @@ impl IronForce {
}
/// Send a message through tunnel
fn send_through_tunnel(&mut self, _tunnel_id: u64, _message: Message, _direction: Option<bool>) -> IFResult<()> {
fn send_through_tunnel(
&mut self,
_tunnel_id: u64,
_message: Message,
_direction: Option<bool>,
) -> IFResult<()> {
todo!()
}
/// Send a message to another node,
/// creating a new tunnel if needed
pub fn send_message(&mut self, message: Message, destination: PublicKey) -> IFResult<()> {
if let Some(Some(tunnel_id)) = self.tunnels.iter()
.find(|t| t.target_node.as_ref() == Some(&destination) || t.nodes_in_tunnel.as_ref().map(|nodes| nodes.contains(&destination)) == Some(true))
.map(|tunnel| tunnel.id) {
if let Some(Some(tunnel_id)) = self
.tunnels
.iter()
.find(|t| {
t.target_node.as_ref() == Some(&destination)
|| t.nodes_in_tunnel
.as_ref()
.map(|nodes| nodes.contains(&destination))
== Some(true)
})
.map(|tunnel| tunnel.id)
{
self.send_through_tunnel(tunnel_id, message, None)
} else {
Err(IFError::TunnelNotFound)
@ -67,8 +80,8 @@ impl IronForce {
ServiceMessageType::TunnelBuilding(_tunnel) => {
todo!()
}
}
MessageType::SingleCast | MessageType::Broadcast => { self.messages.push(message) }
},
MessageType::SingleCast | MessageType::Broadcast => self.messages.push(message),
}
}

184
src/message.rs

@ -1,12 +1,11 @@
use alloc::string::String;
use alloc::vec::Vec;
use crate::crypto::{Keys, PublicKey};
use crate::res::IFResult;
use crate::tunnel::TunnelPublic;
use serde::{Serialize, Deserialize};
use alloc::string::String;
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use sha2::Digest;
/// A serialized message
pub(crate) type MessageBytes = Vec<u8>;
@ -27,6 +26,19 @@ pub enum Signature {
},
}
impl Signature {
/// Get sender's key or its encrypted version for hashing
pub(crate) fn sender_or_encrypted_sender(&self) -> Option<Vec<u8>> {
match &self {
Signature::NotSigned => None,
Signature::Signed { sender, .. } => Some(sender.to_vec()),
Signature::SignedPrivately {
sender_encrypted, ..
} => Some(sender_encrypted.clone()),
}
}
}
/// Network name and version
#[derive(Serialize, Deserialize, Clone)]
pub struct NetworkInfo {
@ -36,7 +48,10 @@ pub struct NetworkInfo {
impl Default for NetworkInfo {
fn default() -> Self {
Self { version: String::from("0.1.0"), network_name: String::from("test") }
Self {
version: String::from("0.1.0"),
network_name: String::from("test"),
}
}
}
@ -52,14 +67,16 @@ impl MessageType {
match self {
MessageType::SingleCast => Vec::from([0]),
MessageType::Broadcast => Vec::from([1]),
MessageType::Service(ServiceMessageType::TunnelBuilding(tunnel)) => [2, 0].iter().chain(tunnel.hash().iter()).copied().collect()
MessageType::Service(ServiceMessageType::TunnelBuilding(tunnel)) => {
[2, 0].iter().chain(tunnel.hash().iter()).copied().collect()
}
}
}
}
#[derive(Serialize, Deserialize, Clone)]
pub enum ServiceMessageType {
TunnelBuilding(TunnelPublic)
TunnelBuilding(TunnelPublic),
}
#[derive(Serialize, Deserialize, Clone)]
@ -78,12 +95,14 @@ impl MessageContent {
MessageContent::Plain(v) => sha2::Sha512::new()
.chain(&[0u8; 1])
.chain(v.as_slice())
.result().to_vec(),
.result()
.to_vec(),
MessageContent::Encrypted(v) => sha2::Sha512::new()
.chain(&[1; 1])
.chain(v.as_slice())
.result().to_vec(),
MessageContent::None => Vec::new()
.result()
.to_vec(),
MessageContent::None => Vec::new(),
}
}
}
@ -113,36 +132,106 @@ pub struct Message {
impl Message {
/// Verify message's hash
pub fn verify(&self) -> bool {
todo!()
pub fn verify_hash(&self) -> bool {
self.hash
== Self::calculate_hash(
&self.content,
self.message_type.clone(),
self.signature.sender_or_encrypted_sender(),
&self.network_info,
)
}
/// Verify sender's signature
pub fn verify_signature(&self, recipient_keys: Keys) -> bool {
match &self.signature {
Signature::NotSigned => true,
Signature::Signed { signature, sender } => {
sender.verify_sign(self.hash.as_slice(), signature.as_slice())
}
Signature::SignedPrivately { signature, .. } => {
if let Some(sender) = self.get_sender(&recipient_keys) {
sender.verify_sign(
self.hash.as_slice(),
&match recipient_keys.decrypt_data(signature.as_slice()) {
Ok(r) => r,
Err(_e) => return false,
},
)
} else {
false
}
}
}
}
/// Check if this message is for this set of keys
pub fn check_recipient(&self, _keys: Keys) -> bool {
todo!()
pub fn check_recipient(&self, keys: Keys) -> bool {
keys.decrypt_data(&self.recipient_verification.clone().unwrap_or_default())
.is_ok()
}
/// Get decrypted content of the message
pub fn get_decrypted(&self, _keys: Keys) -> IFResult<Vec<u8>> {
todo!()
pub fn get_decrypted(&self, keys: Keys) -> IFResult<Vec<u8>> {
Ok(match &self.content {
MessageContent::Plain(c) => c.clone(),
MessageContent::Encrypted(encrypted_content) => {
keys.decrypt_data(encrypted_content.as_slice())?
}
MessageContent::None => Vec::new(),
})
}
pub fn calculate_hash(content: &MessageContent, message_type: MessageType, sender_or_encrypted_sender: Option<Vec<u8>>, network_info: &NetworkInfo) -> Vec<u8> {
pub fn calculate_hash(
content: &MessageContent,
message_type: MessageType,
sender_or_encrypted_sender: Option<Vec<u8>>,
network_info: &NetworkInfo,
) -> Vec<u8> {
sha2::Sha512::new()
.chain(content.hash().as_slice())
.chain(message_type.hash().as_slice())
.chain(sender_or_encrypted_sender.unwrap_or_default().as_slice())
.chain(network_info.network_name.as_bytes())
.chain(network_info.version.as_bytes())
.result().to_vec()
.result()
.to_vec()
}
/// Encrypt hash of the message for the recipient
pub fn generate_recipient_verification(hash: Vec<u8>, recipient: PublicKey) -> rsa::errors::Result<Vec<u8>> {
pub fn generate_recipient_verification(
hash: Vec<u8>,
recipient: PublicKey,
) -> rsa::errors::Result<Vec<u8>> {
recipient.encrypt_data(&hash)
}
}
/// Try to get sender from the signature
fn get_sender(&self, keys: &Keys) -> Option<PublicKey> {
match &self.signature {
Signature::NotSigned => None,
Signature::Signed { sender, .. } => Some(sender.clone()),
Signature::SignedPrivately {
sender_encrypted, ..
} => {
if let Some(Some(res)) = keys
.decrypt_data(sender_encrypted.as_slice())
.ok()
.map(|k| PublicKey::from_vec(k).ok())
{
Some(res)
} else {
None
}
}
}
}
/// Create new MessageBuilder
pub fn build() -> MessageBuilder {
MessageBuilder::new()
}
}
/// Message builder to create a new message step-by-step, like `Message::build().message_type(...).sign(...)`
pub struct MessageBuilder {
@ -201,27 +290,37 @@ impl MessageBuilder {
/// Get the resulting message
pub fn build(self) -> IFResult<Message> {
let salt = rand::random();
let sender_encrypted = if let (Some(sender_keys), Some(recipient)) = (self.sender.as_ref(), self.recipient.as_ref()) {
Some(recipient.encrypt_data(&sender_keys.get_public().to_vec()?)?)
} else { None };
let sender_encrypted = if let (Some(sender_keys), Some(recipient)) =
(self.sender.as_ref(), self.recipient.as_ref())
{
Some(recipient.encrypt_data(&sender_keys.get_public().to_vec())?)
} else {
None
};
let network_info = NetworkInfo::default();
let hash = Message::calculate_hash(
&self.content,
self.message_type.clone().unwrap(),
sender_encrypted.clone()
.or_else(
|| self.sender.as_ref()
.map(|sender_keys| sender_keys.get_public().to_vec().unwrap())
),
&network_info
sender_encrypted.clone().or_else(|| {
self.sender
.as_ref()
.map(|sender_keys| sender_keys.get_public().to_vec())
}),
&network_info,
);
let recipient_verification = self.recipient.as_ref().map(|rec| rec.encrypt_data(&hash).unwrap());
let recipient_verification = self
.recipient
.as_ref()
.map(|rec| rec.encrypt_data(&hash).unwrap());
let signature = match (self.sender, self.recipient) {
(Some(sender_keys), Some(recipient_key)) => Signature::SignedPrivately {
sender_encrypted: sender_encrypted.unwrap(),
signature: recipient_key.encrypt_data(&sender_keys.sign(&hash)?)?,
},
(Some(sender_keys), None) => Signature::Signed { sender: sender_keys.get_public(), signature: sender_keys.sign(&hash)? },
(Some(sender_keys), None) => Signature::Signed {
sender: sender_keys.get_public(),
signature: sender_keys.sign(&hash)?,
},
(None, _) => Signature::NotSigned,
};
Ok(Message {
@ -239,11 +338,16 @@ impl MessageBuilder {
#[cfg(test)]
use alloc::vec;
#[cfg(feature = "std")]
#[cfg(test)]
use std::println;
#[test]
fn test_hashing_message_type() {
let msg_type_1 = MessageType::Broadcast;
let msg_type_2 = MessageType::Service(ServiceMessageType::TunnelBuilding(TunnelPublic::new_for_test()));
let msg_type_2 = MessageType::Service(ServiceMessageType::TunnelBuilding(
TunnelPublic::new_for_test(),
));
assert_eq!(msg_type_1.hash(), msg_type_1.hash());
assert_eq!(msg_type_2.hash(), msg_type_2.hash());
assert_ne!(msg_type_1.hash(), msg_type_2.hash())
@ -260,3 +364,19 @@ fn test_hash_message_content() {
assert_ne!(content_1.hash(), content_3.hash());
assert_ne!(content_3.hash(), content_2.hash());
}
#[test]
fn test_building_message() -> IFResult<()> {
let keys_1 = Keys::generate();
let keys_2 = Keys::generate();
let msg = Message::build()
.content(b"hello".to_vec())
.sign(&keys_1)
.recipient(keys_2.get_public())
.tunnel(1)
.message_type(MessageType::SingleCast)
.build()?;
assert!(msg.verify_hash());
assert!(msg.verify_signature(keys_2));
Ok(())
}

Loading…
Cancel
Save