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 }