Files
opaque-vx/src/serialization/mod.rs
T

197 lines
5.8 KiB
Rust
Raw Normal View History

// Copyright (c) Facebook, Inc. and its affiliates.
//
2021-12-03 14:38:11 -08:00
// This source code is licensed under both the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree and the Apache
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
// of this source tree.
2022-01-04 00:50:40 +01:00
use core::marker::PhantomData;
2022-01-06 06:19:02 +01:00
2022-01-04 00:50:40 +01:00
use digest::Update;
2022-01-06 06:19:02 +01:00
use generic_array::typenum::{U0, U2};
use generic_array::{ArrayLength, GenericArray};
2022-01-04 00:50:40 +01:00
use hmac::Mac;
2022-02-25 07:13:22 +01:00
use crate::errors::{InternalError, ProtocolError};
2022-01-06 06:19:02 +01:00
// Corresponds to the I2OSP() function from RFC8017
2022-01-04 00:50:40 +01:00
pub(crate) fn i2osp<L: ArrayLength<u8>>(
input: usize,
) -> Result<GenericArray<u8, L>, ProtocolError> {
const SIZEOF_USIZE: usize = core::mem::size_of::<usize>();
2021-07-08 11:04:32 -07:00
2022-01-06 00:10:57 +01:00
// Make sure input fits in output.
2022-01-04 00:50:40 +01:00
if (SIZEOF_USIZE as u32 - input.leading_zeros() / 8) > L::U32 {
2021-08-22 12:28:19 -07:00
return Err(ProtocolError::SerializationError);
2021-07-08 11:04:32 -07:00
}
2022-01-04 00:50:40 +01:00
let mut output = GenericArray::default();
2022-01-06 00:10:57 +01:00
output[L::USIZE.saturating_sub(SIZEOF_USIZE)..]
.copy_from_slice(&input.to_be_bytes()[SIZEOF_USIZE.saturating_sub(L::USIZE)..]);
2021-07-08 11:04:32 -07:00
Ok(output)
}
// Corresponds to the OS2IP() function from RFC8017
2022-01-06 00:10:57 +01:00
#[cfg(test)]
2021-08-22 12:28:19 -07:00
pub(crate) fn os2ip(input: &[u8]) -> Result<usize, ProtocolError> {
2021-08-12 06:25:07 +02:00
if input.len() > core::mem::size_of::<usize>() {
2021-08-22 12:28:19 -07:00
return Err(ProtocolError::SerializationError);
}
2021-08-12 06:25:07 +02:00
let mut output_array = [0u8; core::mem::size_of::<usize>()];
output_array[core::mem::size_of::<usize>() - input.len()..].copy_from_slice(input);
Ok(usize::from_be_bytes(output_array))
}
2020-11-12 09:56:06 -05:00
2022-01-06 06:19:02 +01:00
/// Computes `I2OSP(len(input), max_bytes) || input` and helps hold output
/// without allocation.
2022-01-04 00:50:40 +01:00
pub(crate) struct Serialize<
'a,
L1: ArrayLength<u8>,
L2: ArrayLength<u8> = U0,
L3: ArrayLength<u8> = U0,
> {
octet: GenericArray<u8, L1>,
input: Input<'a, L2, L3>,
}
enum Input<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> {
Owned(GenericArray<u8, L1>),
Borrowed(&'a [u8]),
Label(([&'a [u8]; 2], PhantomData<L2>)),
}
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>, L3: ArrayLength<u8>> Serialize<'a, L1, L2, L3> {
// Variation of `serialize` that takes a borrowed `input
pub(crate) fn from(input: &'a [u8]) -> Result<Serialize<'a, L1, L2>, ProtocolError> {
Ok(Serialize {
octet: i2osp::<L1>(input.len())?,
input: Input::Borrowed(input),
})
}
// Variation of `serialize` that takes an owned `input`
pub(crate) fn from_owned(
input: GenericArray<u8, L2>,
) -> Result<Serialize<'a, L1, L2>, ProtocolError> {
Ok(Serialize {
octet: i2osp::<L1>(input.len())?,
input: Input::Owned(input),
})
}
// Variation of `serialize` that takes a label
pub(crate) fn from_label(
opaque: &'a [u8],
label: &'a [u8],
) -> Result<Serialize<'a, L1, U0, U2>, ProtocolError> {
Ok(Serialize {
octet: i2osp::<L1>(opaque.len() + label.len())?,
input: Input::Label(([opaque, label], PhantomData)),
})
}
pub(crate) fn iter(&self) -> impl Iterator<Item = &[u8]> {
// Some magic to make it output the same type in all branches.
2022-01-06 00:10:57 +01:00
[self.octet.as_slice()]
2022-01-04 00:50:40 +01:00
.into_iter()
.chain(match &self.input {
2022-01-06 00:10:57 +01:00
Input::Owned(bytes) => [bytes.as_slice()],
Input::Borrowed(bytes) => [*bytes],
Input::Label((iter, _)) => [iter[0]],
2022-01-04 00:50:40 +01:00
})
.chain(if let Input::Label((iter, _)) = &self.input {
2022-01-06 00:10:57 +01:00
Some(iter[1])
2022-01-04 00:50:40 +01:00
} else {
2022-01-06 00:10:57 +01:00
None
2022-01-04 00:50:40 +01:00
})
}
}
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Serialize<'a, L1, L2, U0> {
pub(crate) fn to_array_2(&self) -> [&[u8]; 2] {
let input = match &self.input {
Input::Borrowed(value) => value,
Input::Owned(value) => value.as_slice(),
_ => unreachable!("unexpected `Serialize` constructed with wrong generics"),
};
[self.octet.as_slice(), input]
}
}
impl<'a, L1: ArrayLength<u8>, L2: ArrayLength<u8>> Serialize<'a, L1, L2, U2> {
pub(crate) fn to_array_3(&self) -> [&[u8]; 3] {
match self.input {
Input::Label((label, _)) => [self.octet.as_slice(), label[0], label[1]],
_ => unreachable!("unexpected `Serialize` constructed with wrong generics"),
}
}
}
2020-11-12 09:56:06 -05:00
2022-01-04 00:50:40 +01:00
pub(crate) trait UpdateExt {
fn chain_iter<'a>(self, iter: impl Iterator<Item = &'a [u8]>) -> Self;
}
impl<T: Update> UpdateExt for T {
fn chain_iter<'a>(self, iter: impl Iterator<Item = &'a [u8]>) -> Self {
let mut self_ = self;
for bytes in iter {
self_ = self_.chain(bytes);
}
self_
}
}
pub(crate) trait MacExt {
fn update_iter<'a>(&mut self, iter: impl Iterator<Item = &'a [u8]>);
}
impl<T: Mac> MacExt for T {
fn update_iter<'a>(&mut self, iter: impl Iterator<Item = &'a [u8]>) {
for bytes in iter {
self.update(bytes);
}
}
}
2022-02-25 07:13:22 +01:00
pub(crate) trait GenericArrayExt {
fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError>;
}
impl<L: ArrayLength<u8>> GenericArrayExt for GenericArray<u8, L> {
fn try_from_slice(slice: &[u8]) -> Result<&Self, InternalError> {
if slice.len() == L::USIZE {
Ok(Self::from_slice(slice))
} else {
Err(InternalError::InvalidByteSequence)
}
}
}
#[cfg(test)]
mod tests;
2021-07-08 11:04:32 -07:00
#[cfg(test)]
mod unit_tests {
2022-01-04 00:50:40 +01:00
use generic_array::typenum::{U1, U2};
2021-07-08 11:04:32 -07:00
2022-01-06 06:19:02 +01:00
use super::*;
2021-07-08 11:04:32 -07:00
// Test the error condition for I2OSP
#[test]
fn test_i2osp_err_check() {
2022-01-04 00:50:40 +01:00
assert!(i2osp::<U1>(0).is_ok());
2021-07-08 11:04:32 -07:00
2022-01-04 00:50:40 +01:00
assert!(i2osp::<U1>(255).is_ok());
assert!(i2osp::<U1>(256).is_err());
assert!(i2osp::<U1>(257).is_err());
2021-07-08 11:04:32 -07:00
2022-01-04 00:50:40 +01:00
assert!(i2osp::<U2>(256 * 256 - 1).is_ok());
assert!(i2osp::<U2>(256 * 256).is_err());
assert!(i2osp::<U2>(256 * 256 + 1).is_err());
2021-07-08 11:04:32 -07:00
}
}