spideroak_crypto/
import.rs

1//! Importing and exporting data.
2
3use core::{
4    fmt::{self, Display},
5    ops::Range,
6    result::Result,
7};
8
9use buggy::Bug;
10use generic_array::{ArrayLength, GenericArray};
11
12use crate::signer::PkError;
13
14/// A slice could not be converted to a fixed-size buffer.
15#[derive(Debug, Eq, PartialEq)]
16pub struct InvalidSizeError {
17    /// The incorrect data size.
18    pub got: usize,
19    /// The expected data size.
20    pub want: Range<usize>,
21}
22
23impl Display for InvalidSizeError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        write!(
26            f,
27            "invalid size data: got {}, want {}..{}",
28            self.got, self.want.start, self.want.end
29        )
30    }
31}
32
33impl core::error::Error for InvalidSizeError {}
34
35/// An error that occured while importing data.
36#[derive(Debug, Eq, PartialEq)]
37pub enum ImportError {
38    /// An unknown or internal error has occurred.
39    Other(&'static str),
40    /// The data is an incorrect size.
41    InvalidSize(InvalidSizeError),
42    /// The data is syntactically invalid.
43    InvalidSyntax,
44    /// The data came from a different context (e.g., a different
45    /// `Engine`).
46    InvalidContext,
47    /// An internal bug was discovered.
48    Bug(Bug),
49    /// The Public Key is invalid.
50    PkError(PkError),
51}
52
53impl Display for ImportError {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match self {
56            Self::Other(msg) => write!(f, "{}", msg),
57            Self::InvalidSize(err) => write!(f, "{}", err),
58            Self::InvalidSyntax => write!(f, "data is syntactically invalid"),
59            Self::InvalidContext => write!(f, "data came from a different context"),
60            Self::Bug(err) => write!(f, "{}", err),
61            Self::PkError(err) => write!(f, "{}", err),
62        }
63    }
64}
65
66impl core::error::Error for ImportError {
67    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
68        match self {
69            Self::InvalidSize(err) => Some(err),
70            Self::Bug(err) => Some(err),
71            _ => None,
72        }
73    }
74}
75
76impl From<InvalidSizeError> for ImportError {
77    fn from(err: InvalidSizeError) -> Self {
78        Self::InvalidSize(err)
79    }
80}
81
82impl From<Bug> for ImportError {
83    fn from(err: Bug) -> Self {
84        Self::Bug(err)
85    }
86}
87
88impl From<PkError> for ImportError {
89    fn from(err: PkError) -> Self {
90        Self::PkError(err)
91    }
92}
93
94/// Shorthand for creating an [`InvalidSizeError`] when importing
95/// a `&[u8]` to `[u8; N]`.
96pub fn try_from_slice<const N: usize>(data: &[u8]) -> Result<&[u8; N], InvalidSizeError> {
97    data.try_into().map_err(|_| InvalidSizeError {
98        got: data.len(),
99        want: N..N,
100    })
101}
102
103/// Shorthand for creating [`ImportError::InvalidSize`] when
104/// importing a `&[u8]` to some type that imports `[u8; N]`.
105pub fn try_import<T, const N: usize>(data: &[u8]) -> Result<T, ImportError>
106where
107    T: Import<[u8; N]>,
108{
109    T::import(*try_from_slice(data)?)
110}
111
112impl<'a, const N: usize> Import<&'a [u8]> for &'a [u8; N] {
113    fn import(data: &[u8]) -> Result<&[u8; N], ImportError> {
114        data.try_into().map_err(|_| {
115            ImportError::InvalidSize(InvalidSizeError {
116                got: data.len(),
117                want: N..N,
118            })
119        })
120    }
121}
122
123impl<const N: usize> Import<&[u8]> for [u8; N] {
124    fn import(data: &[u8]) -> Result<Self, ImportError> {
125        let data: &[u8; N] = Import::<_>::import(data)?;
126        Ok(*data)
127    }
128}
129
130impl<const N: usize> Import<[u8; N]> for [u8; N] {
131    #[inline]
132    fn import(data: [u8; N]) -> Result<Self, ImportError> {
133        Ok(data)
134    }
135}
136
137impl<'a, N: ArrayLength> Import<&'a [u8]> for &'a GenericArray<u8, N> {
138    fn import(data: &'a [u8]) -> Result<Self, ImportError> {
139        GenericArray::try_from_slice(data).map_err(|_| {
140            ImportError::InvalidSize(InvalidSizeError {
141                got: data.len(),
142                want: N::USIZE..N::USIZE,
143            })
144        })
145    }
146}
147
148impl<N: ArrayLength> Import<&[u8]> for GenericArray<u8, N> {
149    fn import(data: &[u8]) -> Result<Self, ImportError> {
150        let data: &GenericArray<u8, N> = Import::<_>::import(data)?;
151        Ok(data.clone())
152    }
153}
154
155impl<N: ArrayLength> Import<GenericArray<u8, N>> for GenericArray<u8, N> {
156    #[inline]
157    fn import(data: GenericArray<u8, N>) -> Result<Self, ImportError> {
158        Ok(data)
159    }
160}
161
162/// Implemented by types that can be imported from its encoding.
163pub trait Import<T>: Sized {
164    /// Creates itself from its encoding.
165    fn import(data: T) -> Result<Self, ImportError>;
166}
167
168/// An error that occurs while exporting secret key material.
169#[derive(Debug, Eq, PartialEq)]
170pub enum ExportError {
171    /// An unknown or internal error has occurred.
172    Other(&'static str),
173    /// The key is opaque and does not expose its key material.
174    Opaque,
175}
176
177impl Display for ExportError {
178    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179        match self {
180            Self::Other(msg) => write!(f, "{}", msg),
181            Self::Opaque => write!(f, "the key is opaque and cannot be exported"),
182        }
183    }
184}
185
186impl core::error::Error for ExportError {}