ovunto_security/crypto/
message.rs1use std::fmt::{Debug, Formatter};
28
29use base64::Engine;
30use serde::{Deserialize, Deserializer, Serialize, Serializer};
31
32use crate::Error;
33
34use super::Nonce;
35
36#[derive(Clone)]
38pub struct CipherMessage {
39 pub cipher_text: Vec<u8>,
41 pub nonce: Nonce,
43}
44
45impl CipherMessage {
46 pub fn to_base64(&self) -> crate::Result<String> {
47 let nonce = self.nonce.to_base64();
48 let cipher_text =
49 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(&self.cipher_text);
50
51 Ok(format!("{nonce}.{cipher_text}"))
52 }
53
54 pub fn from_base64(base64: String) -> crate::Result<Self> {
55 let mut split = base64.split('.');
56 let base64_nonce = split
57 .next()
58 .ok_or(Error::from_string("Invalid CipherMessage format"))?;
59 let base64_cipher = split
60 .next()
61 .ok_or(Error::from_string("Invalid CipherMessage format"))?;
62
63 let nonce = Nonce::from_base64(base64_nonce.to_string())?;
64 let cipher_text = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(base64_cipher)?;
65
66 Ok(Self { nonce, cipher_text })
67 }
68}
69
70impl Debug for CipherMessage {
71 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
72 f.debug_struct("CipherMessage")
73 .field("cipher_text", &hex::encode(&self.cipher_text))
74 .field("nonce", &self.nonce)
75 .finish()
76 }
77}
78
79impl Serialize for CipherMessage {
80 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
81 where
82 S: Serializer,
83 {
84 let base64 = self.to_base64().map_err(|err| {
85 serde::ser::Error::custom(format!("Error serializing CipherMessage: {:?}", err))
86 })?;
87
88 serializer.serialize_str(&base64)
89 }
90}
91
92impl<'de> Deserialize<'de> for CipherMessage {
93 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94 where
95 D: Deserializer<'de>,
96 {
97 let base64 = String::deserialize(deserializer)?;
98
99 Self::from_base64(base64).map_err(|err| {
100 serde::de::Error::custom(format!("Error deserializing CipherMessage: {:?}", err))
101 })
102 }
103}