Lines
100 %
Functions
66.41 %
Branches
//! Implementations of Writeable and Readable for several items that
//! we use in Tor.
//!
//! These don't need to be in a separate module, but for convenience
//! this is where I'm putting them.
use super::*;
use generic_array::GenericArray;
// ----------------------------------------------------------------------
/// Vec<u8> is the main type that implements Writer.
impl Writer for Vec<u8> {
fn write_all(&mut self, bytes: &[u8]) {
self.extend_from_slice(bytes);
}
fn write_u8(&mut self, byte: u8) {
// specialize for performance
self.push(byte);
fn write_zeros(&mut self, n: usize) {
let new_len = self.len() + n;
self.resize(new_len, 0);
impl Writer for bytes::BytesMut {
impl<'a> Writeable for [u8] {
fn write_onto<B: Writer + ?Sized>(&self, b: &mut B) {
b.write_all(self);
impl Writeable for Vec<u8> {
b.write_all(&self[..]);
// The GenericArray type is defined to work around a limitation in Rust's
// type system. Ideally we can get rid of GenericArray entirely at some
// point down the line.
//
// For now, we only use GenericArray<u8>, so that's all we'll declare, since
// it permits a faster implementation.
impl<N> Readable for GenericArray<u8, N>
where
N: generic_array::ArrayLength<u8>,
{
fn take_from(b: &mut Reader<'_>) -> Result<Self> {
// safety -- "take" returns the requested bytes or error.
Ok(Self::clone_from_slice(b.take(N::to_usize())?))
impl<N> Writeable for GenericArray<u8, N>
b.write_all(self.as_slice());
/*
// We could add these as well as our implementations over GenericArray<u8>,
// except that we don't actually need them, and Rust doesn't support
// specialization.
impl<T, N> Readable for GenericArray<T, N>
T: Readable + Clone,
N: generic_array::ArrayLength<T>,
let mut v: Vec<T> = Vec::new();
for _ in 0..N::to_usize() {
v.push(T::take_from(b)?);
// TODO(nickm) I wish I didn't have to clone this.
Ok(Self::from_slice(v.as_slice()).clone())
impl<T, N> Writeable for GenericArray<T, N>
T: Writeable,
for item in self {
item.write_onto(b)
*/
/// Make Readable and Writeable implementations for a provided
/// unsigned type, delegating to the `read_uNN` and `write_uNN` functions.
macro_rules! impl_u {
( $t:ty, $wrfn:ident, $rdfn:ident ) => {
impl Writeable for $t {
b.$wrfn(*self)
impl Readable for $t {
b.$rdfn()
};
impl_u!(u8, write_u8, take_u8);
impl_u!(u16, write_u16, take_u16);
impl_u!(u32, write_u32, take_u32);
impl_u!(u64, write_u64, take_u64);
impl_u!(u128, write_u128, take_u128);
/// Implement Readable and Writeable for IPv4 and IPv6 addresses.
///
/// These are encoded as a sequence of octets, not as strings.
mod net_impls {
use std::net::{Ipv4Addr, Ipv6Addr};
impl Writeable for Ipv4Addr {
b.write_all(&self.octets()[..]);
impl Readable for Ipv4Addr {
fn take_from(r: &mut Reader<'_>) -> Result<Self> {
Ok(r.take_u32()?.into())
impl Writeable for Ipv6Addr {
impl Readable for Ipv6Addr {
Ok(r.take_u128()?.into())
/// Implement Readable and Writeable for Ed25519 types.
mod ed25519_impls {
#[allow(unused_imports)] // This `use` is needed with ed25519 < 1.3.0
use signature::Signature;
use tor_llcrypto::pk::ed25519;
impl Writeable for ed25519::PublicKey {
b.write_all(self.as_bytes());
impl Readable for ed25519::PublicKey {
let bytes = b.take(32)?;
Self::from_bytes(array_ref![bytes, 0, 32])
.map_err(|_| Error::BadMessage("Couldn't decode Ed25519 public key"))
impl Writeable for ed25519::Ed25519Identity {
impl Readable for ed25519::Ed25519Identity {
Ok(Self::new(*array_ref![bytes, 0, 32]))
impl Writeable for ed25519::Signature {
b.write_all(&self.to_bytes()[..]);
impl Readable for ed25519::Signature {
let bytes = b.take(64)?;
Self::from_bytes(array_ref![bytes, 0, 64])
.map_err(|_| Error::BadMessage("Couldn't decode Ed25519 signature."))
/// Implement Readable and Writeable for Curve25519 types.
mod curve25519_impls {
use tor_llcrypto::pk::curve25519::{PublicKey, SharedSecret};
impl Writeable for PublicKey {
impl Readable for PublicKey {
Ok((*array_ref![bytes, 0, 32]).into())
impl Writeable for SharedSecret {
/// Implement readable and writeable for the the RsaIdentity type.
mod rsa_impls {
use tor_llcrypto::pk::rsa::*;
impl Writeable for RsaIdentity {
impl Readable for RsaIdentity {
let m = b.take(RSA_ID_LEN)?;
RsaIdentity::from_bytes(m)
.ok_or_else(|| tor_error::internal!("wrong number of bytes from take").into())
/// Implement readable and writeable for the digest::CtOutput type.
mod digest_impls {
use digest::{CtOutput, OutputSizeUser};
impl<T: OutputSizeUser> WriteableOnce for CtOutput<T> {
fn write_into<B: Writer + ?Sized>(self, b: &mut B) {
let code = self.into_bytes();
b.write(&code[..]);
impl<T: OutputSizeUser> Readable for CtOutput<T> {
let array = GenericArray::take_from(b)?;
Ok(CtOutput::new(array))
/// Implement readable and writeable for u8 arrays.
mod u8_array_impls {
impl<const N: usize> Writeable for [u8; N] {
impl<const N: usize> Readable for [u8; N] {
// note: Conceivably this should use MaybeUninit, but let's
// avoid that unless there is some measurable benefit.
let mut array = [0_u8; N];
r.take_into(&mut array[..])?;
Ok(array)
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use crate::{Reader, Writer};
use hex_literal::hex;
macro_rules! check_encode {
($e:expr, $e2:expr) => {
let mut w = Vec::new();
w.write(&$e);
assert_eq!(&w[..], &$e2[..]);
macro_rules! check_decode {
($t:ty, $e:expr, $e2:expr) => {
let mut r = Reader::from_slice(&$e[..]);
let obj: $t = r.extract().unwrap();
assert_eq!(obj, $e2);
assert!(r.should_be_exhausted().is_ok());
macro_rules! check_roundtrip {
check_encode!($e, $e2);
check_decode!($t, $e2, $e);
macro_rules! check_bad {
($t:ty, $e:expr) => {
let len_orig = r.remaining();
let res: Result<$t, _> = r.extract();
assert!(res.is_err());
assert_eq!(r.remaining(), len_orig);
#[test]
fn vec_u8() {
let v: Vec<u8> = vec![1, 2, 3, 4];
check_encode!(v, b"\x01\x02\x03\x04");
fn genarray() {
use generic_array as ga;
let a: ga::GenericArray<u8, ga::typenum::U7> = [4, 5, 6, 7, 8, 9, 10].into();
check_roundtrip!(ga::GenericArray<u8, ga::typenum::U7>,
a,
[4, 5, 6, 7, 8, 9, 10]);
fn roundtrip_u64() {
check_roundtrip!(u64, 0x4040111_u64, [0, 0, 0, 0, 4, 4, 1, 17]);
fn u8_array() {
check_roundtrip!(
[u8; 16],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
);
fn ipv4addr() {
use std::net::Ipv4Addr;
check_roundtrip!(Ipv4Addr, Ipv4Addr::new(192, 168, 0, 1), [192, 168, 0, 1]);
fn ipv6addr() {
use std::net::Ipv6Addr;
Ipv6Addr,
Ipv6Addr::new(65535, 77, 1, 1, 1, 0, 0, 0),
[255, 255, 0, 77, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
fn ed25519() {
let b = &hex!(
"68a6cee11d2883661f5876f7aac748992cd140f
cfc36923aa957d04b5f8967ff"
ed25519::PublicKey,
ed25519::PublicKey::from_bytes(b).unwrap(),
b
cfc36923aa957d04b5f8967"
); // too short
check_bad!(ed25519::PublicKey, b);
cfc36923aa957d04b5f896700"
); // not a valid compressed Y
let sig = &hex!(
"b8842c083a56076fc27c8af21211f9fe57d1c32d9d
c804f76a8fa858b9ab43622b9e8335993c422eab15
6ebb5a047033f35256333a47a508b02699314d22550e"
ed25519::Signature,
ed25519::Signature::from_bytes(sig).unwrap(),
sig
6ebb5a047033f35256333a47a508b02699314d2255ff"
check_bad!(ed25519::Signature, sig);
fn curve25519() {
use tor_llcrypto::pk::curve25519;
let b = &hex!("5f6df7a2fe3bcf1c9323e9755250efd79b9db4ed8f3fd21c7515398b6662a365");
let pk: curve25519::PublicKey = (*b).into();
check_roundtrip!(curve25519::PublicKey, pk, b);
fn rsa_id() {
use tor_llcrypto::pk::rsa::RsaIdentity;
let b = &hex!("9432D4CEA2621ED09F5A8088BE0E31E0D271435C");
check_roundtrip!(RsaIdentity, RsaIdentity::from_bytes(b).unwrap(), b);