Isabelle's Lazy Message Protocol
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

212 рядки
6.6 KiB

  1. //! # Isabelle's Lazy Message Protocol
  2. //!
  3. //! ### network packet protocol
  4. //!
  5. //! I don't know whether or not this is a super practical way of doing things
  6. //! but i'm lazy and it seems to work so gonna roll with it lol
  7. //!
  8. //! | segment size | usage |
  9. //! |--------------|--------------------------------------------|
  10. //! | 1 byte | u8 packet kind |
  11. //! | 1 byte | u8 encrypt kind |
  12. //! | 8 byte | u64 length of the packet contents |
  13. //! | 4 byte | CRC32 packet contents checksum |
  14. //! | 32 byte | SHA256 packet contents integrity check |
  15. //! | `u64::MAX` | packet contents |
  16. //!
  17. mod message;
  18. pub use message::Message;
  19. mod agreement;
  20. pub use agreement::Agreement;
  21. /// encryption types and functions
  22. pub mod encrypt;
  23. use encrypt::{EncryptKind, Encryption};
  24. use futures_util::io::{AsyncReadExt, AsyncWriteExt};
  25. use orion::aead;
  26. use ring::digest;
  27. use std::convert::TryInto;
  28. use std::marker::Unpin;
  29. use thiserror::Error;
  30. pub type Result<T> = std::result::Result<T, IlmpError>;
  31. struct NetworkPacket(Vec<u8>);
  32. /// a type of data that can be sent
  33. pub trait Sendable: Sized {
  34. fn to_packet(&self, encrypt_kind: EncryptKind) -> Result<Packet>;
  35. fn from_packet(packet: Packet) -> Result<Self>;
  36. }
  37. /// data to be sent
  38. pub struct Packet {
  39. pub kind: PacketKind,
  40. pub encrypt_kind: EncryptKind,
  41. pub integrity_hash: Vec<u8>,
  42. pub contents: Vec<u8>,
  43. }
  44. impl Packet {
  45. /// create a new `Packet`
  46. pub fn new(kind: PacketKind, contents: Vec<u8>, encrypt_kind: EncryptKind) -> Packet {
  47. let integrity_hash = digest::digest(&digest::SHA256, &contents).as_ref().to_vec();
  48. Packet { kind, integrity_hash, contents, encrypt_kind }
  49. }
  50. // generate a checksum from the packet
  51. fn generate_checksum(&self) -> u32 {
  52. // combine integrity hash and contents
  53. let mut hash_and_contents = self.integrity_hash.clone();
  54. hash_and_contents.extend_from_slice(&self.contents);
  55. // generate checksum
  56. let mut hasher = crc32fast::Hasher::new();
  57. hasher.update(hash_and_contents.as_ref());
  58. hasher.finalize()
  59. }
  60. fn to_network_packet(&self) -> NetworkPacket {
  61. let mut contents: Vec<u8> = Vec::new();
  62. // write packet kind byte
  63. contents.push(self.kind as u8);
  64. // write encrypt kind byte
  65. contents.push(self.encrypt_kind as u8);
  66. // write the packet length
  67. let contents_length = self.contents.len() as u64;
  68. contents.extend_from_slice(&contents_length.to_le_bytes());
  69. // write checksum
  70. let checksum = self.generate_checksum();
  71. contents.extend_from_slice(&checksum.to_le_bytes());
  72. // write hash and contents
  73. contents.extend_from_slice(&self.integrity_hash);
  74. contents.extend_from_slice(&self.contents);
  75. NetworkPacket(contents)
  76. }
  77. /// verifies SHA256 integrity
  78. pub fn verify_integrity(&self) -> Result<()> {
  79. let expected = digest::digest(&digest::SHA256, &self.contents).as_ref().to_vec();
  80. if expected == self.integrity_hash {
  81. Ok(())
  82. } else {
  83. println!("bad integrity");
  84. Err(IlmpError::BadHashIntegrity { found: self.integrity_hash.clone(), expected }.into())
  85. }
  86. }
  87. /// verifies CRC32 checksum
  88. pub fn verify_checksum(&self, expected: u32) -> Result<()> {
  89. let found = self.generate_checksum();
  90. if found == expected {
  91. Ok(())
  92. } else {
  93. println!("bad checksum");
  94. Err(IlmpError::BadChecksumIntegrity { expected, found })
  95. }
  96. }
  97. }
  98. /// kinds of packets that can be sent
  99. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  100. #[repr(u8)]
  101. pub enum PacketKind {
  102. Message = 0x00,
  103. Agreement = 0xff,
  104. }
  105. impl PacketKind {
  106. /// returns `Option<PacketKind> given valid matching variant
  107. pub fn from_u8(kind: u8) -> Option<PacketKind> {
  108. match kind {
  109. 0x00 => Some(PacketKind::Message),
  110. 0xff => Some(PacketKind::Agreement),
  111. _ => None,
  112. }
  113. }
  114. }
  115. /// ilmp's error type
  116. #[derive(Error, Debug)]
  117. pub enum IlmpError {
  118. #[error("checksum integrity check failed: (expected {expected:?} found {found:?})")]
  119. BadChecksumIntegrity { expected: u32, found: u32 },
  120. #[error("hash integrity check failed: (expected {expected:?} found {found:?})")]
  121. BadHashIntegrity { expected: Vec<u8>, found: Vec<u8> },
  122. // external error conversions
  123. #[error("std::io error")]
  124. StdIo(#[from] std::io::Error),
  125. #[error("serde_json error")]
  126. SerdeJson(#[from] serde_json::error::Error),
  127. #[error("string parsing error")]
  128. StringParse(#[from] std::string::FromUtf8Error),
  129. #[error("orion error")]
  130. Orion(#[from] orion::errors::UnknownCryptoError),
  131. }
  132. /// reads a `Packet` from a stream
  133. ///
  134. /// if `Ok(None)` is returned the stream has been disconnected.
  135. pub async fn read<S>(stream: &mut S) -> Result<Option<Packet>>
  136. where
  137. S: AsyncReadExt + Unpin,
  138. {
  139. let mut info_buf = [0u8; 14];
  140. let check = stream.read(&mut info_buf).await?;
  141. if check == 0 {
  142. return Ok(None);
  143. }
  144. let kind = PacketKind::from_u8(info_buf[0]).unwrap();
  145. let encrypt_kind = EncryptKind::from_u8(info_buf[1]).unwrap();
  146. let length = u64::from_le_bytes(info_buf[2..10].try_into().unwrap()) as usize;
  147. let checksum = u32::from_le_bytes(info_buf[10..14].try_into().unwrap());
  148. let mut integrity_hash: Vec<u8> = vec![0; 32];
  149. stream.read(&mut integrity_hash).await?;
  150. let mut contents: Vec<u8> = vec![0; length];
  151. stream.read(&mut contents).await?;
  152. let packet = Packet { kind, contents, integrity_hash, encrypt_kind };
  153. packet.verify_checksum(checksum)?;
  154. packet.verify_integrity()?;
  155. Ok(Some(packet))
  156. }
  157. /// writes a `Sendable` packet to a stream
  158. pub async fn write<S, P, E>(stream: &mut S, packet: P, encryption: &E) -> Result<()>
  159. where
  160. S: AsyncWriteExt + Unpin,
  161. P: Sendable,
  162. E: Encryption,
  163. {
  164. match encryption.kind() {
  165. EncryptKind::None => {
  166. let network_packet = packet.to_packet(encryption.kind())?.to_network_packet();
  167. stream.write(&network_packet.0).await?;
  168. Ok(())
  169. }
  170. EncryptKind::Symmetric => {
  171. let mut packet = packet.to_packet(encryption.kind())?;
  172. packet.contents = aead::seal(encryption.key().unwrap(), &packet.contents)?;
  173. packet.integrity_hash =
  174. digest::digest(&digest::SHA256, &packet.contents).as_ref().to_vec();
  175. let network_packet = packet.to_network_packet();
  176. stream.write(&network_packet.0).await?;
  177. Ok(())
  178. }
  179. }
  180. }