Isabelle's Lazy Message Protocol
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

230 строки
6.9 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. #[derive(Debug)]
  39. pub struct Packet {
  40. pub kind: PacketKind,
  41. pub encrypt_kind: EncryptKind,
  42. pub integrity_hash: Vec<u8>,
  43. pub contents: Vec<u8>,
  44. }
  45. impl Packet {
  46. /// create a new `Packet`
  47. pub fn new(kind: PacketKind, contents: Vec<u8>, encrypt_kind: EncryptKind) -> Packet {
  48. let integrity_hash = digest::digest(&digest::SHA256, &contents).as_ref().to_vec();
  49. Packet {
  50. kind,
  51. integrity_hash,
  52. contents,
  53. encrypt_kind,
  54. }
  55. }
  56. // generate a checksum from the packet
  57. fn generate_checksum(&self) -> u32 {
  58. // combine integrity hash and contents
  59. let mut hash_and_contents = self.integrity_hash.clone();
  60. hash_and_contents.extend_from_slice(&self.contents);
  61. // generate checksum
  62. let mut hasher = crc32fast::Hasher::new();
  63. hasher.update(hash_and_contents.as_ref());
  64. hasher.finalize()
  65. }
  66. fn to_network_packet(&self) -> NetworkPacket {
  67. let mut contents: Vec<u8> = Vec::new();
  68. // write packet kind byte
  69. contents.push(self.kind as u8);
  70. // write encrypt kind byte
  71. contents.push(self.encrypt_kind as u8);
  72. // write the packet length
  73. let contents_length = self.contents.len() as u64;
  74. contents.extend_from_slice(&contents_length.to_le_bytes());
  75. // write checksum
  76. let checksum = self.generate_checksum();
  77. contents.extend_from_slice(&checksum.to_le_bytes());
  78. // write hash and contents
  79. contents.extend_from_slice(&self.integrity_hash);
  80. contents.extend_from_slice(&self.contents);
  81. NetworkPacket(contents)
  82. }
  83. /// verifies SHA256 integrity
  84. pub fn verify_integrity(&self) -> Result<()> {
  85. let expected = digest::digest(&digest::SHA256, &self.contents)
  86. .as_ref()
  87. .to_vec();
  88. if expected == self.integrity_hash {
  89. Ok(())
  90. } else {
  91. println!("bad integrity");
  92. Err(IlmpError::BadHashIntegrity {
  93. found: self.integrity_hash.clone(),
  94. expected,
  95. }
  96. .into())
  97. }
  98. }
  99. /// verifies CRC32 checksum
  100. pub fn verify_checksum(&self, expected: u32) -> Result<()> {
  101. let found = self.generate_checksum();
  102. if found == expected {
  103. Ok(())
  104. } else {
  105. println!("bad checksum");
  106. Err(IlmpError::BadChecksumIntegrity { expected, found })
  107. }
  108. }
  109. }
  110. /// kinds of packets that can be sent
  111. #[derive(Debug, Clone, Copy, PartialEq, Eq)]
  112. #[repr(u8)]
  113. pub enum PacketKind {
  114. Message = 0x00,
  115. Agreement = 0xff,
  116. }
  117. impl PacketKind {
  118. /// returns `Option<PacketKind> given valid matching variant
  119. pub fn from_u8(kind: u8) -> Option<PacketKind> {
  120. match kind {
  121. 0x00 => Some(PacketKind::Message),
  122. 0xff => Some(PacketKind::Agreement),
  123. _ => None,
  124. }
  125. }
  126. }
  127. /// ilmp's error type
  128. #[derive(Error, Debug)]
  129. pub enum IlmpError {
  130. #[error("checksum integrity check failed: (expected {expected:?} found {found:?})")]
  131. BadChecksumIntegrity { expected: u32, found: u32 },
  132. #[error("hash integrity check failed: (expected {expected:?} found {found:?})")]
  133. BadHashIntegrity { expected: Vec<u8>, found: Vec<u8> },
  134. // external error conversions
  135. #[error("std::io error")]
  136. StdIo(#[from] std::io::Error),
  137. #[error("serde_json error")]
  138. SerdeJson(#[from] serde_json::error::Error),
  139. #[error("string parsing error")]
  140. StringParse(#[from] std::string::FromUtf8Error),
  141. #[error("orion error")]
  142. Orion(#[from] orion::errors::UnknownCryptoError),
  143. }
  144. /// reads a `Packet` from a stream
  145. ///
  146. /// if `Ok(None)` is returned the stream has been disconnected.
  147. pub async fn read<S>(stream: &mut S) -> Result<Option<Packet>>
  148. where
  149. S: AsyncReadExt + Unpin,
  150. {
  151. let mut info_buf = [0u8; 14];
  152. let check = stream.read(&mut info_buf).await?;
  153. if check == 0 {
  154. return Ok(None);
  155. }
  156. let kind = PacketKind::from_u8(info_buf[0]).unwrap();
  157. let encrypt_kind = EncryptKind::from_u8(info_buf[1]).unwrap();
  158. let length = u64::from_le_bytes(info_buf[2..10].try_into().unwrap()) as usize;
  159. let checksum = u32::from_le_bytes(info_buf[10..14].try_into().unwrap());
  160. let mut integrity_hash: Vec<u8> = vec![0; 32];
  161. stream.read(&mut integrity_hash).await?;
  162. let mut contents: Vec<u8> = vec![0; length];
  163. stream.read(&mut contents).await?;
  164. let packet = Packet {
  165. kind,
  166. contents,
  167. integrity_hash,
  168. encrypt_kind,
  169. };
  170. packet.verify_checksum(checksum)?;
  171. packet.verify_integrity()?;
  172. Ok(Some(packet))
  173. }
  174. /// writes a `Sendable` packet to a stream
  175. pub async fn write<S, P, E>(stream: &mut S, packet: P, encryption: &E) -> Result<()>
  176. where
  177. S: AsyncWriteExt + Unpin,
  178. P: Sendable,
  179. E: Encryption,
  180. {
  181. match encryption.kind() {
  182. EncryptKind::None => {
  183. let network_packet = packet.to_packet(encryption.kind())?.to_network_packet();
  184. stream.write(&network_packet.0).await?;
  185. Ok(())
  186. }
  187. EncryptKind::Symmetric => {
  188. let mut packet = packet.to_packet(encryption.kind())?;
  189. packet.contents = aead::seal(encryption.key().unwrap(), &packet.contents)?;
  190. packet.integrity_hash = digest::digest(&digest::SHA256, &packet.contents)
  191. .as_ref()
  192. .to_vec();
  193. let network_packet = packet.to_network_packet();
  194. stream.write(&network_packet.0).await?;
  195. Ok(())
  196. }
  197. }
  198. }