copernica_packets/
response_data.rs1use {
2 crate::{
3 Data, PublicIdentity, PublicIdentityInterface, PrivateIdentityInterface, Tag, Nonce
4 },
5 copernica_common::constants::*,
6 std::fmt,
7 anyhow::{anyhow, Result},
8 rand::Rng,
9 cryptoxide::{chacha20poly1305::{ChaCha20Poly1305}},
10 log::{error},
11};
12#[derive(Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
13pub enum ResponseData {
14 ClearText {
15 data: Box<Data>,
16 },
17 CypherText {
18 data: Box<Data>,
19 tag: Tag,
20 },
21}
22impl fmt::Display for ResponseData {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 match &*self {
25 ResponseData::ClearText { data } => write!(f, "RD::ClearText: {}", data),
26 ResponseData::CypherText { data, tag } => write!(f, "RD::CypherText: {:?} Tag: {:?}", data, tag),
27 }
28 }
29}
30impl fmt::Debug for ResponseData {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 match &*self {
33 ResponseData::ClearText { data } => write!(f, "RD::ClearText: {:?}", data),
34 ResponseData::CypherText { data, tag } => write!(f, "RD::CypherText: {:?} Tag: {:?}", data, tag),
35 }
36 }
37}
38impl ResponseData {
39 pub fn as_bytes(&self) -> Vec<u8> {
40 let mut buf: Vec<u8> = vec![];
41 match self {
42 ResponseData::ClearText { data } => {
43 buf.extend_from_slice(&data.as_bytes());
44 buf
45 },
46 ResponseData::CypherText { data, tag } => {
47 buf.extend_from_slice(&tag.as_bytes());
48 buf.extend_from_slice(&data.as_bytes());
49 buf
50 },
51 }
52 }
53 pub fn from_bytes(data: &[u8]) -> Result<Self> {
54 match data.len() {
55 CYPHERTEXT_RESPONSE_DATA_SIZE => {
56 let mut tag = Tag([0u8; TAG_SIZE]);
57 tag.0.clone_from_slice(&data[..TAG_SIZE]);
58 let data = Data::new(&data[TAG_SIZE..])?;
59 Ok(ResponseData::CypherText { tag, data: Box::new(data) })
60 },
61 CLEARTEXT_RESPONSE_DATA_SIZE => {
62 let data = Data::new(&data[..])?;
63 Ok(ResponseData::ClearText { data: Box::new(data) })
64 }
65 _ => {
66 Err(anyhow!("Length of data used to reconstruct a ResponseData is unrecognised"))
67 }
68 }
69 }
70 pub fn insert(response_sid: PrivateIdentityInterface, request_pid: PublicIdentityInterface, data: Vec<u8>, nonce: Nonce) -> Result<Self> {
71 match request_pid {
72 PublicIdentityInterface::Present { public_identity } => {
73 if data.len() > DATA_SIZE {
74 return Err(anyhow!("Ensure data.len() passed into ResponseData::cypher_text() is not greater than {}", DATA_SIZE))
75 }
76 let mut rng = rand::thread_rng();
77 let length = data.len();
78 let padding: Vec<u8> = (0..(DATA_SIZE - length)).map(|_| rng.gen()).collect();
79 let b1 = length as u8;
81 let b2 = (length >> 8) as u8;
82 let u8_nonce: u8 = rng.gen();
83 let metadata = vec![u8_nonce, b2, b1];
84 let data = vec![data, padding, metadata];
85 let flattened = data.into_iter().flatten().collect::<Vec<u8>>();
86 let mut data: [u8; FRAGMENT_SIZE] = [0; FRAGMENT_SIZE];
87 data.copy_from_slice(&flattened[0..FRAGMENT_SIZE]);
88 let mut nonce_reverse = nonce.clone();
89 nonce_reverse.0.reverse();
90 let shared_secret = response_sid.shared_secret(nonce_reverse, public_identity);
91 let mut ctx = ChaCha20Poly1305::new(&shared_secret.as_ref(), &nonce.0, &[]);
92 let mut encrypted: Vec<u8> = vec![0; data.len()];
93 let mut tag = Tag([0; TAG_SIZE]);
94 ctx.encrypt(&data, &mut encrypted[..], &mut tag.0);
95 let data = Data::new(&encrypted[..])?;
96 Ok(ResponseData::CypherText { data: Box::new(data), tag })
97 },
98 PublicIdentityInterface::Absent => {
99 if data.len() > DATA_SIZE {
100 return Err(anyhow!("Ensure data.len()({}) passed into ResponseData::clear_text() is not greater than {}", data.len(), DATA_SIZE))
101 }
102 let mut rng = rand::thread_rng();
103 let length = data.len();
104 let padding: Vec<u8> = (0..(DATA_SIZE - length)).map(|_| 0).collect();
106 let b1 = length as u8;
107 let b2 = (length >> 8) as u8;
108 let u8_nonce: u8 = rng.gen();
109 let metadata = vec![u8_nonce, b2, b1];
110 let data = vec![data, padding, metadata];
111 let data = Data::new(&data.into_iter().flatten().collect::<Vec<u8>>()[..])?;
112 Ok(ResponseData::ClearText { data: Box::new(data) })
113 },
114 }
115 }
116 pub fn extract(&self, request_sid: PrivateIdentityInterface, request_pid: PublicIdentityInterface, response_pid: PublicIdentity, nonce: Nonce) -> Result<Vec<u8>> {
117 match self {
118 ResponseData::ClearText { data } => {
119 data.data()
120 },
121 ResponseData::CypherText { data, tag } => {
122 match request_pid {
123 PublicIdentityInterface::Present { public_identity } => {
124 if public_identity != request_sid.public_id() {
125 let err_msg = "The Response's Request_PublicIdentity doesn't match the Public Identity used to sign or decypt the Response";
126 error!("{}", err_msg);
127 return Err(anyhow!(err_msg));
128 }
129 let mut nonce_reverse = nonce.clone();
130 nonce_reverse.0.reverse();
131 let shared_secret = request_sid.shared_secret(nonce_reverse, response_pid);
132 let mut ctx = ChaCha20Poly1305::new(&shared_secret.as_ref(), &nonce.0, &[]);
133 let mut decrypted = [0u8; FRAGMENT_SIZE];
134 if ctx.decrypt(&data.as_bytes(), &mut decrypted[..], &tag.0[..]) {
135 let data: Data = Data::new(&decrypted[..])?;
136 Ok(data.data()?)
137 } else {
138 Err(anyhow!("Couldn't decrypt the data"))
139 }
140 },
141 PublicIdentityInterface::Absent => Err(anyhow!("Cannot determine if the Request's PublicIdentity matches the PublicIdentity used to sign or decrypt the encrypted Response"))
142 }
143 },
144 }
145 }
146}
147