trussed/
key.rs

1use heapless::Vec;
2use serde::{Deserialize, Serialize};
3use serde_indexed::{DeserializeIndexed, SerializeIndexed};
4use zeroize::Zeroize;
5
6pub use crate::Bytes;
7use crate::{
8    Error,
9    config::{MAX_KEY_MATERIAL_LENGTH, MAX_SERIALIZED_KEY_LENGTH},
10};
11
12pub type Material = Vec<u8, {MAX_KEY_MATERIAL_LENGTH}>;
13pub type SerializedKeyBytes = Vec<u8, {MAX_SERIALIZED_KEY_LENGTH}>;
14
15// We don't implement serde to make sure nobody inadvertently still uses it
16// Should we use references here only?
17// #[derive(Clone, Debug, DeserializeIndexed, Eq, PartialEq, SerializeIndexed)]
18/// A key object in Trussed.
19///
20/// Follows Sophie Schmieg's [dictum][dictum] that
21/// "A key should always be considered to be the raw key material alongside its parameter choices."
22///
23/// [dictum]: https://twitter.com/SchmiegSophie/status/1264567198091079681
24#[derive(Clone, Debug, /*DeserializeIndexed,*/ Eq, PartialEq, /*SerializeIndexed,*/ Zeroize)]
25pub struct Key {
26   pub flags: Flags,
27   pub kind: Kind,
28   pub material: Material,
29}
30
31#[derive(Clone, Debug, /*DeserializeIndexed,*/ Eq, PartialEq, /*SerializeIndexed,*/ Zeroize)]
32pub struct Info {
33   pub flags: Flags,
34   pub kind: Kind,
35}
36
37impl Info {
38    pub fn with_local_flag(mut self) -> Self {
39        self.flags |= Flags::LOCAL;
40        self
41    }
42}
43
44impl From<Kind> for Info {
45    fn from(kind: Kind) -> Self {
46        Self { flags: Default::default(), kind }
47    }
48}
49
50// TODO: How to store/check?
51// TODO: Fix variant indices to keep storage stable!!
52#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Zeroize)]
53#[repr(u16)]
54pub enum Kind {
55    /// some bytes of entropy, needs a KDF applied,
56    /// the parameter is the length of the key
57    Shared(usize),
58    /// entropic bytes, suitable for use as symmetric secret (e.g., AES),
59    /// the parameter is the length of the key (e.g. 16 for AES).
60    Symmetric(usize),
61    /// 32B symmetric key + nonce, the parameter is the length of the nonce in bytes
62    Symmetric32Nonce(usize),
63    Ed255,
64    P256,
65    X255,
66}
67
68bitflags::bitflags! {
69    #[derive(DeserializeIndexed, SerializeIndexed, Zeroize)]
70    /// All non-used bits are RFU.
71    ///
72    /// In particular, top bit is intended to be used to accomodate breaking format changes,
73    /// i.e., if `flags >> 32 != 0`, then the format is different.
74    pub struct Flags: u16 {
75        const LOCAL = 1 << 0;
76        const SENSITIVE = 1 << 1;
77    }
78}
79
80#[derive(Copy, Clone, Debug, Eq, PartialEq)]
81/// A key can either be public, of secret.
82///
83/// The secret case also applies to private keys for asymmetric algorithms.
84pub enum Secrecy {
85    // Private,
86    Public,
87    Secret,
88}
89
90impl Key {
91    pub fn serialize(&self) -> SerializedKeyBytes {
92        let mut buffer = SerializedKeyBytes::new();
93        // big-endian here to ensure the first bit is enough to check compatibility
94        // on breaking format change
95        buffer.extend_from_slice(&self.flags.bits().to_be_bytes()).unwrap();
96        buffer.extend_from_slice(&(self.kind.code()).to_be_bytes()).unwrap();
97        // can't fail, since MAX_SERIALIZED_KEY_LENGTH is defined as MAX_KEY_MATERIAL_LENGTH + 4
98        buffer.extend_from_slice(&self.material).unwrap();
99        buffer
100    }
101
102    pub fn try_deserialize(bytes: &[u8]) -> Result<Self, Error> {
103        if bytes.len() < 4 {
104            return Err(Error::InvalidSerializedKey);
105        }
106        let (info, material) = bytes.split_at(4);
107        let flags_bits = u16::from_be_bytes([info[0], info[1]]);
108        let flags = Flags::from_bits(flags_bits).ok_or(Error::InvalidSerializedKey)?;
109
110        let kind_bits = u16::from_be_bytes([info[2], info[3]]);
111        let kind = Kind::try_from(kind_bits, material.len()).map_err(|_| Error::InvalidSerializedKey)?;
112
113        Ok(Key {
114            flags,
115            kind,
116            material: Material::from_slice(material).map_err(|_| Error::InvalidSerializedKey)?,
117        })
118    }
119}
120
121impl Default for Flags {
122    /// This implements "safe" defaults
123    /// - no claim on local generation
124    /// - default sensitive
125    fn default() -> Self {
126        Flags::SENSITIVE
127    }
128}
129
130impl Kind {
131    pub fn code(self) -> u16 {
132        match self {
133            Kind::Shared(_) => 1,
134            Kind::Symmetric(_) => 2,
135            Kind::Symmetric32Nonce(_) => 3,
136            Kind::Ed255 => 4,
137            Kind::P256 => 5,
138            Kind::X255 => 6,
139        }
140    }
141
142    pub fn try_from(code: u16, length: usize) -> Result<Self, Error> {
143        Ok(match code {
144            1 => Self::Shared(length),
145            2 => Self::Symmetric(length),
146            3 => Self::Symmetric32Nonce(length - 32),
147            4 => Self::Ed255,
148            5 => Self::P256,
149            6 => Self::X255,
150            _ => return Err(Error::InvalidSerializedKey),
151        })
152    }
153}