tor_bytes/
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
7use super::*;
8
9// ----------------------------------------------------------------------
10
11/// `Vec<u8>` is the main type that implements [`Writer`].
12impl 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
27impl Writer for bytes::BytesMut {
28    fn write_all(&mut self, bytes: &[u8]) {
29        self.extend_from_slice(bytes);
30    }
31}
32
33// ----------------------------------------------------------------------
34
35impl 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
42impl 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.)
51impl<N> Readable for digest::generic_array::GenericArray<u8, N>
52where
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
61impl<N> Writeable for digest::generic_array::GenericArray<u8, N>
62where
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
76impl<T, N> Readable for GenericArray<T, N>
77where
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
91impl<T, N> Writeable for GenericArray<T, N>
92where
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.
106macro_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
122impl_u!(u8, write_u8, take_u8);
123impl_u!(u16, write_u16, take_u16);
124impl_u!(u32, write_u32, take_u32);
125impl_u!(u64, write_u64, take_u64);
126impl_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.
133mod 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")]
165mod 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")]
211mod 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")]
237mod 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.
257mod 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.
276mod 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")]
298mod 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)]
316mod 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}