refactor(net): box ecies error (#337)

This commit is contained in:
Matthias Seitz
2022-12-05 22:39:46 +01:00
committed by Georgios Konstantopoulos
parent b40546b999
commit 0b8d50127c
4 changed files with 88 additions and 22 deletions

View File

@ -1,5 +1,6 @@
#![allow(missing_docs)]
use crate::{
error::ECIESErrorImpl,
mac::{HeaderBytes, MAC},
util::{hmac_sha256, id2pk, pk2id, sha256},
ECIESError,
@ -80,7 +81,7 @@ pub struct ECIES {
fn split_at_mut<T>(arr: &mut [T], idx: usize) -> Result<(&mut [T], &mut [T]), ECIESError> {
if idx > arr.len() {
return Err(ECIESError::OutOfBounds { idx, len: arr.len() })
return Err(ECIESErrorImpl::OutOfBounds { idx, len: arr.len() }.into())
}
Ok(arr.split_at_mut(idx))
}
@ -224,7 +225,7 @@ impl ECIES {
let check_tag = hmac_sha256(mac_key.as_ref(), &[iv, encrypted_data], auth_data);
if check_tag != tag {
return Err(ECIESError::TagCheckFailed)
return Err(ECIESErrorImpl::TagCheckFailed.into())
}
let decrypted_data = encrypted_data;
@ -302,15 +303,15 @@ impl ECIES {
fn parse_auth_unencrypted(&mut self, data: &[u8]) -> Result<(), ECIESError> {
let mut data = Rlp::new(data)?;
let sigdata = data.get_next::<[u8; 65]>()?.ok_or(ECIESError::InvalidAuthData)?;
let sigdata = data.get_next::<[u8; 65]>()?.ok_or(ECIESErrorImpl::InvalidAuthData)?;
let signature = RecoverableSignature::from_compact(
&sigdata[0..64],
RecoveryId::from_i32(sigdata[64] as i32)?,
)?;
let remote_id = data.get_next()?.ok_or(ECIESError::InvalidAuthData)?;
let remote_id = data.get_next()?.ok_or(ECIESErrorImpl::InvalidAuthData)?;
self.remote_id = Some(remote_id);
self.remote_public_key = Some(id2pk(remote_id)?);
self.remote_nonce = Some(data.get_next()?.ok_or(ECIESError::InvalidAuthData)?);
self.remote_nonce = Some(data.get_next()?.ok_or(ECIESErrorImpl::InvalidAuthData)?);
let x = ecdh_x(&self.remote_public_key.unwrap(), &self.secret_key);
self.remote_ephemeral_public_key = Some(SECP256K1.recover_ecdsa(
@ -379,8 +380,8 @@ impl ECIES {
fn parse_ack_unencrypted(&mut self, data: &[u8]) -> Result<(), ECIESError> {
let mut data = Rlp::new(data)?;
self.remote_ephemeral_public_key =
Some(id2pk(data.get_next()?.ok_or(ECIESError::InvalidAckData)?)?);
self.remote_nonce = Some(data.get_next()?.ok_or(ECIESError::InvalidAckData)?);
Some(id2pk(data.get_next()?.ok_or(ECIESErrorImpl::InvalidAckData)?)?);
self.remote_nonce = Some(data.get_next()?.ok_or(ECIESErrorImpl::InvalidAckData)?);
self.ephemeral_shared_secret =
Some(ecdh_x(&self.remote_ephemeral_public_key.unwrap(), &self.ephemeral_secret_key));
@ -475,12 +476,12 @@ impl ECIES {
self.ingress_mac.as_mut().unwrap().update_header(header);
let check_mac = self.ingress_mac.as_mut().unwrap().digest();
if check_mac != mac {
return Err(ECIESError::TagCheckFailed)
return Err(ECIESErrorImpl::TagCheckFailed.into())
}
self.ingress_aes.as_mut().unwrap().apply_keystream(header);
if header.as_slice().len() < 3 {
return Err(ECIESError::InvalidHeader)
return Err(ECIESErrorImpl::InvalidHeader.into())
}
let body_size = usize::try_from(header.as_slice().read_uint::<BigEndian>(3)?)?;
@ -527,7 +528,7 @@ impl ECIES {
self.ingress_mac.as_mut().unwrap().update_body(body);
let check_mac = self.ingress_mac.as_mut().unwrap().digest();
if check_mac != mac {
return Err(ECIESError::TagCheckFailed)
return Err(ECIESErrorImpl::TagCheckFailed.into())
}
let size = self.body_size.unwrap();

View File

@ -1,12 +1,45 @@
use crate::IngressECIESValue;
use std::fmt;
use thiserror::Error;
/// An error that occurs while reading or writing to an ECIES stream.
pub struct ECIESError {
inner: Box<ECIESErrorImpl>,
}
// === impl ===
impl ECIESError {
/// Consumes the type and returns the error enum
pub fn into_inner(self) -> ECIESErrorImpl {
*self.inner
}
}
impl fmt::Debug for ECIESError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.inner, f)
}
}
impl fmt::Display for ECIESError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&*self.inner, f)
}
}
impl std::error::Error for ECIESError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.inner.source()
}
}
/// An error that occurs while reading or writing to an ECIES stream.
#[derive(Debug, Error)]
pub enum ECIESError {
pub enum ECIESErrorImpl {
/// Error during IO
#[error("IO error")]
IO(#[from] std::io::Error),
IO(std::io::Error),
/// Error when checking the HMAC tag against the tag on the data
#[error("tag check failure")]
TagCheckFailed,
@ -21,13 +54,13 @@ pub enum ECIESError {
InvalidHeader,
/// Error when interacting with secp256k1
#[error(transparent)]
Secp256k1(#[from] secp256k1::Error),
Secp256k1(secp256k1::Error),
/// Error when decoding RLP data
#[error(transparent)]
RLPDecoding(#[from] reth_rlp::DecodeError),
RLPDecoding(reth_rlp::DecodeError),
/// Error when convering to integer
#[error(transparent)]
FromInt(#[from] std::num::TryFromIntError),
FromInt(std::num::TryFromIntError),
/// Error when trying to split an array beyond its length
#[error("requested {idx} but array len is {len}")]
OutOfBounds {
@ -45,3 +78,33 @@ pub enum ECIESError {
msg: Option<IngressECIESValue>,
},
}
impl From<ECIESErrorImpl> for ECIESError {
fn from(source: ECIESErrorImpl) -> Self {
ECIESError { inner: Box::new(source) }
}
}
impl From<std::io::Error> for ECIESError {
fn from(source: std::io::Error) -> Self {
ECIESErrorImpl::IO(source).into()
}
}
impl From<secp256k1::Error> for ECIESError {
fn from(source: secp256k1::Error) -> Self {
ECIESErrorImpl::Secp256k1(source).into()
}
}
impl From<reth_rlp::DecodeError> for ECIESError {
fn from(source: reth_rlp::DecodeError) -> Self {
ECIESErrorImpl::RLPDecoding(source).into()
}
}
impl From<std::num::TryFromIntError> for ECIESError {
fn from(source: std::num::TryFromIntError) -> Self {
ECIESErrorImpl::FromInt(source).into()
}
}

View File

@ -1,4 +1,3 @@
#![allow(clippy::result_large_err)]
#![warn(missing_docs, unreachable_pub)]
#![deny(unused_must_use, rust_2018_idioms)]
#![doc(test(
@ -20,8 +19,8 @@ mod codec;
use reth_primitives::H512 as PeerId;
#[derive(Clone, Debug, PartialEq, Eq)]
/// Raw egress values for an ECIES protocol
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EgressECIESValue {
/// The AUTH message being sent out
Auth,
@ -31,8 +30,8 @@ pub enum EgressECIESValue {
Message(bytes::Bytes),
}
#[derive(Clone, Debug, PartialEq, Eq)]
/// Raw ingress values for an ECIES protocol
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IngressECIESValue {
/// Receiving a message from a [`PeerId`]
AuthReceive(PeerId),

View File

@ -1,5 +1,7 @@
//! The ECIES Stream implementation which wraps over [`AsyncRead`] and [`AsyncWrite`].
use crate::{codec::ECIESCodec, ECIESError, EgressECIESValue, IngressECIESValue};
use crate::{
codec::ECIESCodec, error::ECIESErrorImpl, ECIESError, EgressECIESValue, IngressECIESValue,
};
use bytes::Bytes;
use futures::{ready, Sink, SinkExt};
use reth_primitives::H512 as PeerId;
@ -64,7 +66,7 @@ where
if matches!(msg, Some(IngressECIESValue::Ack)) {
Ok(Self { stream: transport, remote_id })
} else {
Err(ECIESError::InvalidHandshake { expected: IngressECIESValue::Ack, msg })
Err(ECIESErrorImpl::InvalidHandshake { expected: IngressECIESValue::Ack, msg }.into())
}
}
@ -81,10 +83,11 @@ where
let remote_id = match &msg {
Some(IngressECIESValue::AuthReceive(remote_id)) => *remote_id,
_ => {
return Err(ECIESError::InvalidHandshake {
return Err(ECIESErrorImpl::InvalidHandshake {
expected: IngressECIESValue::AuthReceive(Default::default()),
msg,
})
}
.into())
}
};