Skip to content

Commit

Permalink
Unify mechanism traits
Browse files Browse the repository at this point in the history
This patch combines the operation traits that were previously used to
call mechanism implementations into a single MechanismImpl trait.  This
has several advantages:
- We can use a macro to implement the dispatch from the Mechanism enum,
  removing boilerplate code from the reply_to implementation.
- To implement an operation for a mechanism, it is now sufficient to
  override the respective trait method.  It is no longer necessary to
  also update reply_to.
- The need to annotate all mechanism methods with #[inline(never)] to
  avoid producing a huge reply_to function (see the comment in
  mechanisms.rs) is reduced as we can just mark the methods generated by
  the macro as #[inline(never)].
- This reduces the binary size required in the stable
  nitrokey-3-firmware by some kB.
  • Loading branch information
robin-nitrokey committed Apr 10, 2024
1 parent 83cf940 commit 8624e88
Show file tree
Hide file tree
Showing 19 changed files with 400 additions and 602 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ littlefs2 = "0.4.0"
p256-cortex-m4 = { version = "0.1.0-alpha.6", features = ["prehash", "sec1-signatures"] }
salty = { version = "0.3.0", features = ["cose"] }
serde-indexed = "0.1.0"
paste = "1.0.14"

[dev-dependencies]
# Testing
Expand Down
56 changes: 17 additions & 39 deletions src/mechanisms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,73 +10,51 @@
// The question of breaking down `reply_to` into smaller, more globally understandable pieces,
// should be revisited.

// TODO: rename to aes256-cbc-zero-iv
pub struct Aes256Cbc {}
pub struct Aes256Cbc;
mod aes256cbc;

pub struct Chacha8Poly1305 {}
pub struct Chacha8Poly1305;
mod chacha8poly1305;

pub struct SharedSecret {}
pub struct SharedSecret;
mod shared_secret;

pub struct Ed255 {}
pub struct Ed255;
mod ed255;

pub struct HmacBlake2s {}
pub struct HmacBlake2s;
#[cfg(feature = "hmac-blake2s")]
mod hmacblake2s;
#[cfg(not(feature = "hmac-blake2s"))]
impl crate::service::DeriveKey for HmacBlake2s {}
#[cfg(not(feature = "hmac-blake2s"))]
impl crate::service::Sign for HmacBlake2s {}
impl crate::service::MechanismImpl for HmacBlake2s {}

pub struct HmacSha1 {}
pub struct HmacSha1;
mod hmacsha1;

pub struct HmacSha256 {}
pub struct HmacSha256;
mod hmacsha256;

pub struct HmacSha512 {}
pub struct HmacSha512;
#[cfg(feature = "hmac-sha512")]
mod hmacsha512;
#[cfg(not(feature = "hmac-sha512"))]
impl crate::service::DeriveKey for HmacSha512 {}
#[cfg(not(feature = "hmac-sha512"))]
impl crate::service::Sign for HmacSha512 {}
impl crate::service::MechanismImpl for HmacSha512 {}

pub struct P256 {}
pub struct P256Prehashed {}
pub struct P256;
pub struct P256Prehashed;
mod p256;

pub struct Sha256 {}
pub struct Sha256;
mod sha256;

pub struct Tdes {}
pub struct Tdes;
mod tdes;

pub struct Totp {}
pub struct Totp;
mod totp;

pub struct Trng {}
pub struct Trng;
mod trng;

pub struct X255 {}
pub struct X255;
mod x255;

// pub enum MechanismEnum {
// NotImplemented,
// Ed255(ed255::Ed255),
// P256(p256::P256),
// }

// use crate::types::Mechanism;
// pub fn enum_to_type(mechanism: Mechanism) -> MechanismEnum {
// match mechanism {
// #[cfg(feature = "ed255")]
// Mechanism::Ed255 => MechanismEnum::Ed255(ed255::Ed255 {} ),
// #[cfg(feature = "p256")]
// Mechanism::P256 => MechanismEnum::P256(p256::P256 {} ),
// _ => MechanismEnum::NotImplemented,
// }
// }
29 changes: 9 additions & 20 deletions src/mechanisms/aes256cbc.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use crate::api::{reply, request};
use crate::error::Error;
use crate::key;
use crate::service::{Decrypt, Encrypt, UnsafeInjectKey, WrapKey};
use crate::service::MechanismImpl;
use crate::store::keystore::Keystore;
use crate::types::{Mechanism, Message, ShortData};

const AES256_KEY_SIZE: usize = 32;

#[cfg(feature = "aes256-cbc")]
impl Encrypt for super::Aes256Cbc {
impl MechanismImpl for super::Aes256Cbc {
/// Encrypts the input *with zero IV*
fn encrypt(
&self,
keystore: &mut impl Keystore,
request: &request::Encrypt,
) -> Result<reply::Encrypt, Error> {
Expand Down Expand Up @@ -64,11 +65,9 @@ impl Encrypt for super::Aes256Cbc {
tag: ShortData::new(),
})
}
}

#[cfg(feature = "aes256-cbc")]
impl WrapKey for super::Aes256Cbc {
fn wrap_key(
&self,
keystore: &mut impl Keystore,
request: &request::WrapKey,
) -> Result<reply::WrapKey, Error> {
Expand All @@ -93,17 +92,15 @@ impl WrapKey for super::Aes256Cbc {
associated_data: request.associated_data.clone(),
nonce: request.nonce.clone(),
};
let encryption_reply = <super::Aes256Cbc>::encrypt(keystore, &encryption_request)?;
let encryption_reply = self.encrypt(keystore, &encryption_request)?;

let wrapped_key = encryption_reply.ciphertext;

Ok(reply::WrapKey { wrapped_key })
}
}

#[cfg(feature = "aes256-cbc")]
impl Decrypt for super::Aes256Cbc {
fn decrypt(
&self,
keystore: &mut impl Keystore,
request: &request::Decrypt,
) -> Result<reply::Decrypt, Error> {
Expand Down Expand Up @@ -158,11 +155,9 @@ impl Decrypt for super::Aes256Cbc {
plaintext: Some(plaintext),
})
}
}

#[cfg(feature = "aes256-cbc")]
impl UnsafeInjectKey for super::Aes256Cbc {
fn unsafe_inject_key(
&self,
keystore: &mut impl Keystore,
request: &request::UnsafeInjectKey,
) -> Result<reply::UnsafeInjectKey, Error> {
Expand All @@ -173,7 +168,7 @@ impl UnsafeInjectKey for super::Aes256Cbc {
let key_id = keystore.store_key(
request.attributes.persistence,
key::Secrecy::Secret,
key::Kind::Symmetric(request.raw_key.len()),
key::Kind::Symmetric(request.raw_key.len()).into(),
&request.raw_key,
)?;

Expand All @@ -182,10 +177,4 @@ impl UnsafeInjectKey for super::Aes256Cbc {
}

#[cfg(not(feature = "aes256-cbc"))]
impl UnsafeInjectKey for super::Aes256Cbc {}
#[cfg(not(feature = "aes256-cbc"))]
impl Decrypt for super::Aes256Cbc {}
#[cfg(not(feature = "aes256-cbc"))]
impl Encrypt for super::Aes256Cbc {}
#[cfg(not(feature = "aes256-cbc"))]
impl WrapKey for super::Aes256Cbc {}
impl MechanismImpl for super::Aes256Cbc {}
82 changes: 33 additions & 49 deletions src/mechanisms/chacha8poly1305.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use rand_core::RngCore;
use crate::api::{reply, request};
use crate::error::Error;
use crate::key;
use crate::service::{Decrypt, Encrypt, GenerateKey, UnwrapKey, WrapKey};
use crate::service::MechanismImpl;
use crate::store::keystore::Keystore;
use crate::types::{Mechanism, Message, ShortData};

Expand All @@ -19,10 +19,27 @@ const TAG_LEN: usize = 16;
const KIND: key::Kind = key::Kind::Symmetric(KEY_LEN);
const KIND_NONCE: key::Kind = key::Kind::Symmetric32Nonce(NONCE_LEN);

#[inline(never)]
fn increment_nonce(nonce: &mut [u8]) -> Result<(), Error> {
assert_eq!(nonce.len(), NONCE_LEN);
let mut carry: u16 = 1;
for digit in nonce.iter_mut() {
let x = (*digit as u16) + carry;
*digit = x as u8;
carry = x >> 8;
}
if carry == 0 {
Ok(())
} else {
Err(Error::NonceOverflow)
}
}

#[cfg(feature = "chacha8-poly1305")]
impl GenerateKey for super::Chacha8Poly1305 {
impl MechanismImpl for super::Chacha8Poly1305 {
#[inline(never)]
fn generate_key(
&self,
keystore: &mut impl Keystore,
request: &request::GenerateKey,
) -> Result<reply::GenerateKey, Error> {
Expand All @@ -39,34 +56,16 @@ impl GenerateKey for super::Chacha8Poly1305 {
let key_id = keystore.store_key(
request.attributes.persistence,
key::Secrecy::Secret,
KIND_NONCE,
KIND_NONCE.into(),
&serialized,
)?;

Ok(reply::GenerateKey { key: key_id })
}
}

#[inline(never)]
fn increment_nonce(nonce: &mut [u8]) -> Result<(), Error> {
assert_eq!(nonce.len(), NONCE_LEN);
let mut carry: u16 = 1;
for digit in nonce.iter_mut() {
let x = (*digit as u16) + carry;
*digit = x as u8;
carry = x >> 8;
}
if carry == 0 {
Ok(())
} else {
Err(Error::NonceOverflow)
}
}

#[cfg(feature = "chacha8-poly1305")]
impl Decrypt for super::Chacha8Poly1305 {
#[inline(never)]
fn decrypt(
&self,
keystore: &mut impl Keystore,
request: &request::Decrypt,
) -> Result<reply::Decrypt, Error> {
Expand Down Expand Up @@ -104,12 +103,10 @@ impl Decrypt for super::Chacha8Poly1305 {
},
})
}
}

#[cfg(feature = "chacha8-poly1305")]
impl Encrypt for super::Chacha8Poly1305 {
#[inline(never)]
fn encrypt(
&self,
keystore: &mut impl Keystore,
request: &request::Encrypt,
) -> Result<reply::Encrypt, Error> {
Expand Down Expand Up @@ -165,12 +162,10 @@ impl Encrypt for super::Chacha8Poly1305 {
tag,
})
}
}

#[cfg(feature = "chacha8-poly1305")]
impl WrapKey for super::Chacha8Poly1305 {
#[inline(never)]
fn wrap_key(
&self,
keystore: &mut impl Keystore,
request: &request::WrapKey,
) -> Result<reply::WrapKey, Error> {
Expand All @@ -188,19 +183,17 @@ impl WrapKey for super::Chacha8Poly1305 {
associated_data: request.associated_data.clone(),
nonce: request.nonce.clone(),
};
let encryption_reply = <super::Chacha8Poly1305>::encrypt(keystore, &encryption_request)?;
let encryption_reply = self.encrypt(keystore, &encryption_request)?;

let wrapped_key =
crate::postcard_serialize_bytes(&encryption_reply).map_err(|_| Error::CborError)?;

Ok(reply::WrapKey { wrapped_key })
}
}

#[cfg(feature = "chacha8-poly1305")]
impl UnwrapKey for super::Chacha8Poly1305 {
#[inline(never)]
fn unwrap_key(
&self,
keystore: &mut impl Keystore,
request: &request::UnwrapKey,
) -> Result<reply::UnwrapKey, Error> {
Expand All @@ -219,13 +212,12 @@ impl UnwrapKey for super::Chacha8Poly1305 {
tag,
};

let serialized_key = if let Some(serialized_key) =
<super::Chacha8Poly1305>::decrypt(keystore, &decryption_request)?.plaintext
{
serialized_key
} else {
return Ok(reply::UnwrapKey { key: None });
};
let serialized_key =
if let Some(serialized_key) = self.decrypt(keystore, &decryption_request)?.plaintext {
serialized_key
} else {
return Ok(reply::UnwrapKey { key: None });
};

// TODO: probably change this to returning Option<key> too
let key::Key {
Expand All @@ -239,7 +231,7 @@ impl UnwrapKey for super::Chacha8Poly1305 {
request.attributes.persistence,
// using for signing keys... we need to know
key::Secrecy::Secret,
kind,
kind.into(),
&material,
)?;

Expand All @@ -248,12 +240,4 @@ impl UnwrapKey for super::Chacha8Poly1305 {
}

#[cfg(not(feature = "chacha8-poly1305"))]
impl Decrypt for super::Chacha8Poly1305 {}
#[cfg(not(feature = "chacha8-poly1305"))]
impl Encrypt for super::Chacha8Poly1305 {}
#[cfg(not(feature = "chacha8-poly1305"))]
impl WrapKey for super::Chacha8Poly1305 {}
#[cfg(not(feature = "chacha8-poly1305"))]
impl UnwrapKey for super::Chacha8Poly1305 {}
#[cfg(not(feature = "chacha8-poly1305"))]
impl GenerateKey for super::Chacha8Poly1305 {}
impl MechanismImpl for super::Chacha8Poly1305 {}
Loading

0 comments on commit 8624e88

Please sign in to comment.