rns_core/destination_parts/
module_core.rs1pub use primitives::{
2 group_decrypt, group_encrypt, Direction, Group, Input, Output, Plain, Single, Type,
3};
4
5pub use ratchet::RATCHET_LENGTH;
6
7use ratchet::{try_decrypt_with_ratchets, RatchetState};
8
9pub const NAME_HASH_LENGTH: usize = 10;
10
11pub const RAND_HASH_LENGTH: usize = 10;
12
13pub const MIN_ANNOUNCE_DATA_LENGTH: usize =
14 PUBLIC_KEY_LENGTH * 2 + NAME_HASH_LENGTH + RAND_HASH_LENGTH + SIGNATURE_LENGTH;
15
16#[derive(Copy, Clone)]
17pub struct DestinationName {
18 pub hash: Hash,
19}
20
21impl DestinationName {
22 pub fn new(app_name: &str, aspects: &str) -> Self {
23 let hash = Hash::new(
24 Hash::generator()
25 .chain_update(app_name.as_bytes())
26 .chain_update(".".as_bytes())
27 .chain_update(aspects.as_bytes())
28 .finalize()
29 .into(),
30 );
31
32 Self { hash }
33 }
34
35 pub fn new_from_hash_slice(hash_slice: &[u8]) -> Self {
36 let mut hash = [0u8; 32];
37 hash[..hash_slice.len()].copy_from_slice(hash_slice);
38
39 Self { hash: Hash::new(hash) }
40 }
41
42 pub fn as_name_hash_slice(&self) -> &[u8] {
43 &self.hash.as_slice()[..NAME_HASH_LENGTH]
44 }
45}
46
47#[derive(Copy, Clone)]
48pub struct DestinationDesc {
49 pub identity: Identity,
50 pub address_hash: AddressHash,
51 pub name: DestinationName,
52}
53
54impl fmt::Display for DestinationDesc {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "{}", self.address_hash)?;
57
58 Ok(())
59 }
60}
61
62pub type DestinationAnnounce = Packet;
63
64pub struct AnnounceInfo<'a> {
65 pub destination: SingleOutputDestination,
66 pub app_data: &'a [u8],
67 pub ratchet: Option<[u8; RATCHET_LENGTH]>,
68}
69
70impl DestinationAnnounce {
71 pub fn validate(packet: &Packet) -> Result<AnnounceInfo<'_>, RnsError> {
72 let mut signed_data = [0u8; packet::PACKET_MDU];
73 Self::validate_with_buffer(packet, &mut signed_data)
74 }
75
76 pub fn validate_with_buffer<'a>(
77 packet: &'a Packet,
78 signed_data: &mut [u8],
79 ) -> Result<AnnounceInfo<'a>, RnsError> {
80 if packet.header.packet_type != PacketType::Announce {
81 return Err(RnsError::PacketError);
82 }
83
84 let announce_data = packet.data.as_slice();
85
86 if announce_data.len() < MIN_ANNOUNCE_DATA_LENGTH {
87 return Err(RnsError::OutOfMemory);
88 }
89
90 let mut offset = 0usize;
91
92 let public_key = {
93 let mut key_data = [0u8; PUBLIC_KEY_LENGTH];
94 key_data.copy_from_slice(&announce_data[offset..(offset + PUBLIC_KEY_LENGTH)]);
95 offset += PUBLIC_KEY_LENGTH;
96 PublicKey::from(key_data)
97 };
98
99 let verifying_key = {
100 let mut key_data = [0u8; PUBLIC_KEY_LENGTH];
101 key_data.copy_from_slice(&announce_data[offset..(offset + PUBLIC_KEY_LENGTH)]);
102 offset += PUBLIC_KEY_LENGTH;
103
104 VerifyingKey::from_bytes(&key_data).map_err(|_| RnsError::CryptoError)?
105 };
106
107 let identity = Identity::new(public_key, verifying_key);
108
109 let name_hash = &announce_data[offset..(offset + NAME_HASH_LENGTH)];
110 offset += NAME_HASH_LENGTH;
111 let rand_hash = &announce_data[offset..(offset + RAND_HASH_LENGTH)];
112 offset += RAND_HASH_LENGTH;
113 let destination = &packet.destination;
114 let expected_hash =
115 create_address_hash(&identity, &DestinationName::new_from_hash_slice(name_hash));
116 if expected_hash != *destination {
117 return Err(RnsError::IncorrectHash);
118 }
119
120 let remaining = announce_data.len().saturating_sub(offset);
121 if remaining < SIGNATURE_LENGTH {
122 return Err(RnsError::OutOfMemory);
123 }
124
125 let has_ratchet_flag = packet.header.context_flag == ContextFlag::Set;
126
127 if has_ratchet_flag {
128 if remaining < SIGNATURE_LENGTH + RATCHET_LENGTH {
129 return Err(RnsError::OutOfMemory);
130 }
131 let ratchet = &announce_data[offset..offset + RATCHET_LENGTH];
132 let sig_start = offset + RATCHET_LENGTH;
133 let sig_end = sig_start + SIGNATURE_LENGTH;
134 let signature = &announce_data[sig_start..sig_end];
135 let app_data = &announce_data[sig_end..];
136 verify_announce_with_buffer(
137 &identity,
138 destination.as_slice(),
139 public_key.as_bytes(),
140 verifying_key.as_bytes(),
141 name_hash,
142 rand_hash,
143 Some(ratchet),
144 signature,
145 app_data,
146 signed_data,
147 )?;
148 let mut ratchet_bytes = [0u8; RATCHET_LENGTH];
149 ratchet_bytes.copy_from_slice(ratchet);
150 return Ok(AnnounceInfo {
151 destination: SingleOutputDestination::new(
152 identity,
153 DestinationName::new_from_hash_slice(name_hash),
154 ),
155 app_data,
156 ratchet: Some(ratchet_bytes),
157 });
158 }
159
160 let signature = &announce_data[offset..(offset + SIGNATURE_LENGTH)];
161 let app_data = &announce_data[(offset + SIGNATURE_LENGTH)..];
162 verify_announce_with_buffer(
163 &identity,
164 destination.as_slice(),
165 public_key.as_bytes(),
166 verifying_key.as_bytes(),
167 name_hash,
168 rand_hash,
169 None,
170 signature,
171 app_data,
172 signed_data,
173 )?;
174
175 Ok(AnnounceInfo {
176 destination: SingleOutputDestination::new(
177 identity,
178 DestinationName::new_from_hash_slice(name_hash),
179 ),
180 app_data,
181 ratchet: None,
182 })
183 }
184}
185
186pub struct Destination<I: HashIdentity, D: Direction, T: Type> {
187 pub direction: PhantomData<D>,
188 pub r#type: PhantomData<T>,
189 pub identity: I,
190 pub desc: DestinationDesc,
191 ratchet_state: RatchetState,
192}
193
194impl<I: HashIdentity, D: Direction, T: Type> Destination<I, D, T> {
195 pub fn destination_type(&self) -> packet::DestinationType {
196 <T as Type>::destination_type()
197 }
198}
199
200pub enum DestinationHandleStatus {
228 None,
229 LinkProof,
230}
231
232impl Destination<PrivateIdentity, Input, Single> {
233 pub fn new(identity: PrivateIdentity, name: DestinationName) -> Self {
234 let address_hash = create_address_hash(&identity, &name);
235 let pub_identity = *identity.as_identity();
236
237 Self {
238 direction: PhantomData,
239 r#type: PhantomData,
240 identity,
241 desc: DestinationDesc { identity: pub_identity, name, address_hash },
242 ratchet_state: RatchetState::default(),
243 }
244 }
245
246 #[cfg(feature = "std")]
247 pub fn enable_ratchets<P: AsRef<Path>>(&mut self, path: P) -> Result<(), RnsError> {
248 let path = path.as_ref().to_path_buf();
249 self.ratchet_state.enable(&self.identity, path)
250 }
251
252 pub fn set_retained_ratchets(&mut self, retained: usize) -> Result<(), RnsError> {
253 if retained == 0 {
254 return Err(RnsError::InvalidArgument);
255 }
256 self.ratchet_state.retained_ratchets = retained;
257 if self.ratchet_state.ratchets.len() > retained {
258 self.ratchet_state.ratchets.truncate(retained);
259 }
260 Ok(())
261 }
262
263 pub fn set_ratchet_interval_secs(&mut self, secs: u64) -> Result<(), RnsError> {
264 if secs == 0 {
265 return Err(RnsError::InvalidArgument);
266 }
267 self.ratchet_state.ratchet_interval_secs = secs;
268 Ok(())
269 }
270
271 pub fn enforce_ratchets(&mut self, enforce: bool) {
272 self.ratchet_state.enforce_ratchets = enforce;
273 }
274
275 pub fn decrypt_with_ratchets(
276 &mut self,
277 ciphertext: &[u8],
278 ) -> Result<(Vec<u8>, bool), RnsError> {
279 let salt = self.identity.as_identity().address_hash.as_slice();
280 if self.ratchet_state.enabled && !self.ratchet_state.ratchets.is_empty() {
281 if let Some(plaintext) =
282 try_decrypt_with_ratchets(&self.ratchet_state, salt, ciphertext)
283 {
284 return Ok((plaintext, true));
285 }
286 #[cfg(feature = "std")]
287 if let Some(path) = self.ratchet_state.ratchets_path.clone() {
288 if self.ratchet_state.reload(&self.identity, &path).is_ok() {
289 if let Some(plaintext) =
290 try_decrypt_with_ratchets(&self.ratchet_state, salt, ciphertext)
291 {
292 return Ok((plaintext, true));
293 }
294 }
295 }
296 if self.ratchet_state.enforce_ratchets {
297 return Err(RnsError::CryptoError);
298 }
299 }
300
301 let plaintext = decrypt_with_identity(&self.identity, salt, ciphertext)?;
302 Ok((plaintext, false))
303 }
304
305 pub fn announce<R: CryptoRngCore + Copy>(
306 &mut self,
307 rng: R,
308 app_data: Option<&[u8]>,
309 ) -> Result<Packet, RnsError> {
310 let mut packet_data = PacketDataBuffer::new();
311
312 let mut rand_hash = [0u8; RAND_HASH_LENGTH];
316 let mut random_part = [0u8; RAND_HASH_LENGTH / 2];
317 let mut rng_mut = rng;
318 rng_mut.fill_bytes(&mut random_part);
319 rand_hash[..RAND_HASH_LENGTH / 2].copy_from_slice(&random_part);
320 let emitted_secs = now_secs().floor() as u64;
321 let emitted_be = emitted_secs.to_be_bytes();
322 rand_hash[RAND_HASH_LENGTH / 2..].copy_from_slice(&emitted_be[3..8]);
323
324 let pub_key = self.identity.as_identity().public_key_bytes();
325 let verifying_key = self.identity.as_identity().verifying_key_bytes();
326
327 let ratchet = if self.ratchet_state.enabled {
328 let now = now_secs();
329 self.ratchet_state.rotate_if_needed(&self.identity, now)?;
330 self.ratchet_state.current_ratchet_public()
331 } else {
332 None
333 };
334
335 packet_data
336 .chain_safe_write(self.desc.address_hash.as_slice())
337 .chain_safe_write(pub_key)
338 .chain_safe_write(verifying_key)
339 .chain_safe_write(self.desc.name.as_name_hash_slice())
340 .chain_safe_write(&rand_hash);
341
342 if let Some(ratchet) = ratchet {
343 packet_data.chain_safe_write(&ratchet);
344 }
345
346 if let Some(data) = app_data {
347 packet_data.chain_safe_write(data);
348 }
349
350 let signature = self.identity.sign(packet_data.as_slice());
351
352 packet_data.reset();
353
354 packet_data
355 .chain_safe_write(pub_key)
356 .chain_safe_write(verifying_key)
357 .chain_safe_write(self.desc.name.as_name_hash_slice())
358 .chain_safe_write(&rand_hash);
359
360 if let Some(ratchet) = ratchet {
361 packet_data.chain_safe_write(&ratchet);
362 }
363
364 packet_data.chain_safe_write(&signature.to_bytes());
365
366 if let Some(data) = app_data {
367 packet_data.write(data)?;
368 }
369
370 Ok(Packet {
371 header: Header {
372 ifac_flag: IfacFlag::Open,
373 header_type: HeaderType::Type1,
374 context_flag: if ratchet.is_some() { ContextFlag::Set } else { ContextFlag::Unset },
375 propagation_type: PropagationType::Broadcast,
376 destination_type: DestinationType::Single,
377 packet_type: PacketType::Announce,
378 hops: 0,
379 },
380 ifac: None,
381 destination: self.desc.address_hash,
382 transport: None,
383 context: PacketContext::None,
384 data: packet_data,
385 })
386 }
387
388 pub fn path_response<R: CryptoRngCore + Copy>(
389 &mut self,
390 rng: R,
391 app_data: Option<&[u8]>,
392 ) -> Result<Packet, RnsError> {
393 let mut announce = self.announce(rng, app_data)?;
394 announce.context = PacketContext::PathResponse;
395
396 Ok(announce)
397 }
398
399 pub fn handle_packet(&mut self, packet: &Packet) -> DestinationHandleStatus {
400 if self.desc.address_hash != packet.destination {
401 return DestinationHandleStatus::None;
402 }
403
404 if packet.header.packet_type == PacketType::LinkRequest {
405 return DestinationHandleStatus::LinkProof;
407 }
408
409 DestinationHandleStatus::None
410 }
411
412 pub fn sign_key(&self) -> &SigningKey {
413 self.identity.sign_key()
414 }
415}
416
417impl Destination<Identity, Output, Single> {
418 pub fn new(identity: Identity, name: DestinationName) -> Self {
419 let address_hash = create_address_hash(&identity, &name);
420 Self {
421 direction: PhantomData,
422 r#type: PhantomData,
423 identity,
424 desc: DestinationDesc { identity, name, address_hash },
425 ratchet_state: RatchetState::default(),
426 }
427 }
428}
429
430impl<D: Direction> Destination<EmptyIdentity, D, Plain> {
431 pub fn new(identity: EmptyIdentity, name: DestinationName) -> Self {
432 let address_hash = create_address_hash(&identity, &name);
433 Self {
434 direction: PhantomData,
435 r#type: PhantomData,
436 identity,
437 desc: DestinationDesc { identity: Default::default(), name, address_hash },
438 ratchet_state: RatchetState::default(),
439 }
440 }
441}