/ crates / tor-bytes / src / impls.rs
impls.rs
  1  //! Implementations of Writeable and Readable for several items that
  2  //! we use in Tor.
  3  //!
  4  //! These don't need to be in a separate module, but for convenience
  5  //! this is where I'm putting them.
  6  
  7  use super::*;
  8  
  9  // ----------------------------------------------------------------------
 10  
 11  /// `Vec<u8>` is the main type that implements [`Writer`].
 12  impl Writer for Vec<u8> {
 13      fn write_all(&mut self, bytes: &[u8]) {
 14          self.extend_from_slice(bytes);
 15      }
 16      fn write_u8(&mut self, byte: u8) {
 17          // specialize for performance
 18          self.push(byte);
 19      }
 20      fn write_zeros(&mut self, n: usize) {
 21          // specialize for performance
 22          let new_len = self.len().saturating_add(n);
 23          self.resize(new_len, 0);
 24      }
 25  }
 26  
 27  impl Writer for bytes::BytesMut {
 28      fn write_all(&mut self, bytes: &[u8]) {
 29          self.extend_from_slice(bytes);
 30      }
 31  }
 32  
 33  // ----------------------------------------------------------------------
 34  
 35  impl Writeable for [u8] {
 36      fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
 37          b.write_all(self);
 38          Ok(())
 39      }
 40  }
 41  
 42  impl Writeable for Vec<u8> {
 43      fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
 44          b.write_all(&self[..]);
 45          Ok(())
 46      }
 47  }
 48  
 49  // We also need to implement our traits for an older version (0.14) of
 50  // generic_array, since that's what the digest crate uses (as of digest 0.10.)
 51  impl<N> Readable for digest::generic_array::GenericArray<u8, N>
 52  where
 53      N: digest::generic_array::ArrayLength<u8>,
 54  {
 55      fn take_from(b: &mut Reader<'_>) -> Result<Self> {
 56          // safety -- "take" returns the requested bytes or error.
 57          Ok(Self::clone_from_slice(b.take(N::to_usize())?))
 58      }
 59  }
 60  
 61  impl<N> Writeable for digest::generic_array::GenericArray<u8, N>
 62  where
 63      N: digest::generic_array::ArrayLength<u8>,
 64  {
 65      fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
 66          b.write_all(self.as_slice());
 67          Ok(())
 68      }
 69  }
 70  
 71  /*
 72  // We could add these as well as our implementations over GenericArray<u8>,
 73  // except that we don't actually need them, and Rust doesn't support
 74  // specialization.
 75  
 76  impl<T, N> Readable for GenericArray<T, N>
 77  where
 78      T: Readable + Clone,
 79      N: generic_array::ArrayLength<T>,
 80  {
 81      fn take_from(b: &mut Reader<'_>) -> Result<Self> {
 82          let mut v: Vec<T> = Vec::new();
 83          for _ in 0..N::to_usize() {
 84              v.push(T::take_from(b)?);
 85          }
 86          // TODO(nickm) I wish I didn't have to clone this.
 87          Ok(Self::from_slice(v.as_slice()).clone())
 88      }
 89  }
 90  
 91  impl<T, N> Writeable for GenericArray<T, N>
 92  where
 93      T: Writeable,
 94      N: generic_array::ArrayLength<T>,
 95  {
 96      fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) {
 97          for item in self {
 98              item.write_onto(b)
 99          }
100      }
101  }
102  */
103  
104  /// Make Readable and Writeable implementations for a provided
105  /// unsigned type, delegating to the `read_uNN` and `write_uNN` functions.
106  macro_rules! impl_u {
107      ( $t:ty, $wrfn:ident, $rdfn:ident ) => {
108          impl Writeable for $t {
109              fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
110                  b.$wrfn(*self);
111                  Ok(())
112              }
113          }
114          impl Readable for $t {
115              fn take_from(b: &mut Reader<'_>) -> Result<Self> {
116                  b.$rdfn()
117              }
118          }
119      };
120  }
121  
122  impl_u!(u8, write_u8, take_u8);
123  impl_u!(u16, write_u16, take_u16);
124  impl_u!(u32, write_u32, take_u32);
125  impl_u!(u64, write_u64, take_u64);
126  impl_u!(u128, write_u128, take_u128);
127  
128  // ----------------------------------------------------------------------
129  
130  /// Implement [`Readable`] and [`Writeable`] for IPv4 and IPv6 addresses.
131  ///
132  /// These are encoded as a sequence of octets, not as strings.
133  mod net_impls {
134      use super::*;
135      use std::net::{Ipv4Addr, Ipv6Addr};
136  
137      impl Writeable for Ipv4Addr {
138          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
139              b.write_all(&self.octets()[..]);
140              Ok(())
141          }
142      }
143  
144      impl Readable for Ipv4Addr {
145          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
146              Ok(b.take_u32()?.into())
147          }
148      }
149  
150      impl Writeable for Ipv6Addr {
151          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
152              b.write_all(&self.octets()[..]);
153              Ok(())
154          }
155      }
156      impl Readable for Ipv6Addr {
157          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
158              Ok(b.take_u128()?.into())
159          }
160      }
161  }
162  
163  /// Implement [`Readable`] and [`Writeable`] for Ed25519 types.
164  #[cfg(feature = "tor-llcrypto")]
165  mod ed25519_impls {
166      use super::*;
167      use tor_llcrypto::pk::ed25519;
168  
169      impl Writeable for ed25519::PublicKey {
170          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
171              b.write_all(self.as_bytes());
172              Ok(())
173          }
174      }
175      impl Readable for ed25519::PublicKey {
176          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
177              let bytes: [u8; 32] = b.extract()?;
178              Self::from_bytes(&bytes)
179                  .map_err(|_| Error::InvalidMessage("Couldn't decode Ed25519 public key".into()))
180          }
181      }
182  
183      impl Writeable for ed25519::Ed25519Identity {
184          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
185              b.write_all(self.as_bytes());
186              Ok(())
187          }
188      }
189      impl Readable for ed25519::Ed25519Identity {
190          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
191              let bytes: [u8; 32] = b.extract()?;
192              Ok(Self::new(bytes))
193          }
194      }
195      impl Writeable for ed25519::Signature {
196          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
197              b.write_all(&self.to_bytes()[..]);
198              Ok(())
199          }
200      }
201      impl Readable for ed25519::Signature {
202          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
203              let bytes: [u8; 64] = b.extract()?;
204              Ok(Self::from_bytes(&bytes))
205          }
206      }
207  }
208  
209  /// Implement Readable and Writeable for Curve25519 types.
210  #[cfg(feature = "tor-llcrypto")]
211  mod curve25519_impls {
212      use super::*;
213      use tor_llcrypto::pk::curve25519::{PublicKey, SharedSecret};
214  
215      impl Writeable for PublicKey {
216          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
217              b.write_all(self.as_bytes());
218              Ok(())
219          }
220      }
221      impl Readable for PublicKey {
222          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
223              let bytes: [u8; 32] = b.extract()?;
224              Ok(bytes.into())
225          }
226      }
227      impl Writeable for SharedSecret {
228          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
229              b.write_all(self.as_bytes());
230              Ok(())
231          }
232      }
233  }
234  
235  /// Implement readable and writeable for the RsaIdentity type.
236  #[cfg(feature = "tor-llcrypto")]
237  mod rsa_impls {
238      use super::*;
239      use tor_llcrypto::pk::rsa::*;
240  
241      impl Writeable for RsaIdentity {
242          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
243              b.write_all(self.as_bytes());
244              Ok(())
245          }
246      }
247      impl Readable for RsaIdentity {
248          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
249              let m = b.take(RSA_ID_LEN)?;
250              RsaIdentity::from_bytes(m)
251                  .ok_or_else(|| tor_error::internal!("wrong number of bytes from take").into())
252          }
253      }
254  }
255  
256  /// Implement readable and writeable for the digest::CtOutput type.
257  mod digest_impls {
258      use super::*;
259      use digest::{CtOutput, OutputSizeUser};
260      impl<T: OutputSizeUser> WriteableOnce for CtOutput<T> {
261          fn write_into<B: Writer + ?Sized>(self, b: &mut B) -> EncodeResult<()> {
262              let code = self.into_bytes();
263              b.write_all(&code[..]);
264              Ok(())
265          }
266      }
267      impl<T: OutputSizeUser> Readable for CtOutput<T> {
268          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
269              let array = digest::generic_array::GenericArray::take_from(b)?;
270              Ok(CtOutput::new(array))
271          }
272      }
273  }
274  
275  /// Implement readable and writeable for u8 arrays.
276  mod u8_array_impls {
277      use super::*;
278      impl<const N: usize> Writeable for [u8; N] {
279          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
280              b.write_all(&self[..]);
281              Ok(())
282          }
283      }
284  
285      impl<const N: usize> Readable for [u8; N] {
286          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
287              // note: Conceivably this should use MaybeUninit, but let's
288              // avoid that unless there is some measurable benefit.
289              let mut array = [0_u8; N];
290              b.take_into(&mut array[..])?;
291              Ok(array)
292          }
293      }
294  }
295  
296  /// Implement Readable and Writeable for `CtByteArray`
297  #[cfg(feature = "tor-llcrypto")]
298  mod ctbytearray_impls {
299      use super::*;
300      use tor_llcrypto::util::ct::CtByteArray;
301      impl<const N: usize> Writeable for CtByteArray<N> {
302          fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) -> EncodeResult<()> {
303              b.write_all(&self.as_ref()[..]);
304              Ok(())
305          }
306      }
307  
308      impl<const N: usize> Readable for CtByteArray<N> {
309          fn take_from(b: &mut Reader<'_>) -> Result<Self> {
310              Ok(CtByteArray::from(b.extract::<[u8; N]>()?))
311          }
312      }
313  }
314  
315  #[cfg(test)]
316  mod tests {
317      #![allow(clippy::unwrap_used)]
318      use crate::{Reader, Writer};
319      #[cfg(feature = "tor-llcrypto")]
320      use hex_literal::hex;
321  
322      macro_rules! check_encode {
323          ($e:expr, $e2:expr) => {
324              let mut w = Vec::new();
325              w.write(&$e).expect("encoding failed");
326              assert_eq!(&w[..], &$e2[..]);
327          };
328      }
329      macro_rules! check_decode {
330          ($t:ty, $e:expr, $e2:expr) => {
331              let mut b = Reader::from_slice_for_test(&$e[..]);
332              let obj: $t = b.extract().unwrap();
333              assert_eq!(obj, $e2);
334              assert!(b.should_be_exhausted().is_ok());
335          };
336      }
337      macro_rules! check_roundtrip {
338          ($t:ty, $e:expr, $e2:expr) => {
339              check_encode!($e, $e2);
340              check_decode!($t, $e2, $e);
341          };
342      }
343      #[cfg(feature = "tor-llcrypto")]
344      macro_rules! check_bad {
345          ($t:ty, $e:expr) => {
346              let mut b = Reader::from_slice_for_test(&$e[..]);
347              let len_orig = b.remaining();
348              let res: Result<$t, _> = b.extract();
349              assert!(res.is_err());
350              assert_eq!(b.remaining(), len_orig);
351          };
352      }
353      #[test]
354      fn vec_u8() {
355          let v: Vec<u8> = vec![1, 2, 3, 4];
356          check_encode!(v, b"\x01\x02\x03\x04");
357      }
358  
359      #[test]
360      fn genarray() {
361          use digest::generic_array as ga;
362          let a: ga::GenericArray<u8, ga::typenum::U7> = [4, 5, 6, 7, 8, 9, 10].into();
363          check_roundtrip!(ga::GenericArray<u8, ga::typenum::U7>,
364                           a,
365                           [4, 5, 6, 7, 8, 9, 10]);
366      }
367  
368      #[test]
369      fn roundtrip_u64() {
370          check_roundtrip!(u64, 0x4040111_u64, [0, 0, 0, 0, 4, 4, 1, 17]);
371      }
372  
373      #[test]
374      fn u8_array() {
375          check_roundtrip!(
376              [u8; 16],
377              [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
378              [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
379          );
380      }
381  
382      #[test]
383      fn ipv4addr() {
384          use std::net::Ipv4Addr;
385          check_roundtrip!(Ipv4Addr, Ipv4Addr::new(192, 168, 0, 1), [192, 168, 0, 1]);
386      }
387  
388      #[test]
389      fn ipv6addr() {
390          use std::net::Ipv6Addr;
391          check_roundtrip!(
392              Ipv6Addr,
393              Ipv6Addr::new(65535, 77, 1, 1, 1, 0, 0, 0),
394              [255, 255, 0, 77, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
395          );
396      }
397  
398      #[cfg(feature = "tor-llcrypto")]
399      #[test]
400      fn ed25519() {
401          use tor_llcrypto::pk::ed25519;
402          let b = &hex!(
403              "68a6cee11d2883661f5876f7aac748992cd140f
404               cfc36923aa957d04b5f8967ff"
405          );
406          check_roundtrip!(
407              ed25519::PublicKey,
408              ed25519::PublicKey::from_bytes(b).unwrap(),
409              b
410          );
411          let b = &hex!(
412              "68a6cee11d2883661f5876f7aac748992cd140f
413               cfc36923aa957d04b5f8967"
414          ); // too short
415          check_bad!(ed25519::PublicKey, b);
416          let b = &hex!(
417              "68a6cee11d2883661f5876f7aac748992cd140f
418               cfc36923aa957d04b5f896700"
419          ); // not a valid compressed Y
420          check_bad!(ed25519::PublicKey, b);
421  
422          let sig = &hex!(
423              "b8842c083a56076fc27c8af21211f9fe57d1c32d9d
424               c804f76a8fa858b9ab43622b9e8335993c422eab15
425               6ebb5a047033f35256333a47a508b02699314d22550e"
426          );
427          check_roundtrip!(ed25519::Signature, ed25519::Signature::from_bytes(sig), sig);
428  
429          // Test removed: The ed25519::Signature type is now happy to hold any
430          // 64-byte sequence.
431          //
432          // let sig = &hex!(
433          //   "b8842c083a56076fc27c8af21211f9fe57d1c32d9d
434          //     c804f76a8fa858b9ab43622b9e8335993c422eab15
435          //     6ebb5a047033f35256333a47a508b02699314d2255ff"
436          // );
437          // check_bad!(ed25519::Signature, sig);
438      }
439  
440      #[cfg(feature = "tor-llcrypto")]
441      #[test]
442      fn curve25519() {
443          use tor_llcrypto::pk::curve25519;
444          let b = &hex!("5f6df7a2fe3bcf1c9323e9755250efd79b9db4ed8f3fd21c7515398b6662a365");
445          let pk: curve25519::PublicKey = (*b).into();
446          check_roundtrip!(curve25519::PublicKey, pk, b);
447      }
448  
449      #[cfg(feature = "tor-llcrypto")]
450      #[test]
451      fn rsa_id() {
452          use tor_llcrypto::pk::rsa::RsaIdentity;
453          let b = &hex!("9432D4CEA2621ED09F5A8088BE0E31E0D271435C");
454          check_roundtrip!(RsaIdentity, RsaIdentity::from_bytes(b).unwrap(), b);
455      }
456  }