Skip to content

wrap: implement encryption/decryption of messages #494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@ edition = "2021"
rust-version = "1.67"

[dependencies]
aes = "0.8"
aes = { version = "0.8", features = ["zeroize"] }
bitflags = "2"
cmac = "0.7"
cbc = "0.1"
ccm = { version = "0.5", features = ["std"] }
ecdsa = { version = "0.16", default-features = false }
ed25519 = "2"
log = "0.4"
num-bigint = { version = "0.8.2", features = ["i128", "prime", "zeroize"], default-features = false, package = "num-bigint-dig" }
num-traits = "0.2"
p256 = { version = "0.13", default-features = false, features = ["ecdsa"] }
p384 = { version = "0.13", default-features = false, features = ["ecdsa"] }
serde = { version = "1", features = ["serde_derive"] }
rand_core = { version = "0.6", features = ["std"] }
rsa = "0.9"
signature = { version = "2", features = ["derive"] }
subtle = "2"
thiserror = "1"
Expand All @@ -36,7 +40,6 @@ uuid = { version = "1", default-features = false }
zeroize = { version = "1", features = ["zeroize_derive"] }

# optional dependencies
ccm = { version = "0.5", optional = true, features = ["std"] }
digest = { version = "0.10", optional = true, default-features = false }
ed25519-dalek = { version = "2", optional = true, features = ["rand_core"] }
hmac = { version = "0.12", optional = true }
Expand All @@ -51,13 +54,12 @@ tiny_http = { version = "0.12", optional = true }
ed25519-dalek = "2"
once_cell = "1"
p256 = { version = "0.13", features = ["ecdsa"] }
rsa = "0.9"

[features]
default = ["http", "passwords", "setup"]
http-server = ["tiny_http"]
http = []
mockhsm = ["ccm", "digest", "ecdsa/arithmetic", "ed25519-dalek", "p256/ecdsa", "secp256k1"]
mockhsm = ["digest", "ecdsa/arithmetic", "ed25519-dalek", "p256/ecdsa", "secp256k1"]
passwords = ["hmac", "pbkdf2", "sha2"]
secp256k1 = ["k256"]
setup = ["passwords", "serde_json", "uuid/serde"]
Expand Down
4 changes: 0 additions & 4 deletions src/mockhsm/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ pub enum ErrorKind {
/// Object does not exist
#[error("object not found")]
ObjectNotFound,

/// Unsupported algorithm
#[error("unsupported algorithm")]
UnsupportedAlgorithm,
}

impl ErrorKind {
Expand Down
8 changes: 5 additions & 3 deletions src/mockhsm/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod objects;
mod payload;

pub(crate) use self::{objects::Objects, payload::Payload};
use crate::{object, Algorithm};
use crate::{object, wrap, Algorithm};
use serde::{Deserialize, Serialize};

/// Label for the default auth key
Expand Down Expand Up @@ -34,14 +34,16 @@ impl Object {
/// A serialized object which can be exported/imported
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct WrappedObject {
pub object_info: object::Info,
pub alg_id: Algorithm,
pub object_info: wrap::Info,
pub data: Vec<u8>,
}

impl<'a> From<&'a Object> for WrappedObject {
fn from(obj: &'a Object) -> Self {
Self {
object_info: obj.object_info.clone(),
alg_id: Algorithm::Wrap(wrap::Algorithm::Aes128Ccm),
object_info: obj.object_info.clone().into(),
data: obj.payload.to_bytes(),
}
}
Expand Down
55 changes: 37 additions & 18 deletions src/mockhsm/object/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,30 @@ use crate::{
serialization::{deserialize, serialize},
wrap, Algorithm, Capability, Domain,
};
use aes::cipher::consts::{U13, U8};
use aes::cipher::consts::{U13, U16};
use ccm::aead::{AeadInPlace, KeyInit};
use std::collections::{btree_map::Iter as MapIter, BTreeMap as Map};

/// AES-CCM with a 128-bit key
pub(crate) type Aes128Ccm = ccm::Ccm<aes::Aes128, U8, U13>;
pub(crate) type Aes128Ccm = ccm::Ccm<aes::Aes128, U16, U13>;

/// AES-CCM with a 192-bit key
pub(crate) type Aes192Ccm = ccm::Ccm<aes::Aes192, U16, U13>;

/// AES-CCM with a 256-bit key
pub(crate) type Aes256Ccm = ccm::Ccm<aes::Aes256, U8, U13>;
pub(crate) type Aes256Ccm = ccm::Ccm<aes::Aes256, U16, U13>;

/// AES-CCM key
#[allow(clippy::large_enum_variant)]
pub(crate) enum AesCcmKey {
/// AES-CCM with a 128-bit key
Aes128Ccm(Aes128Ccm),
Aes128(Aes128Ccm),

/// AES-CCM with a 192-bit key
Aes192(Aes192Ccm),

/// AES-CCM with a 256-bit key
Aes256Ccm(Aes256Ccm),
Aes256(Aes256Ccm),
}

impl AesCcmKey {
Expand All @@ -38,10 +44,13 @@ impl AesCcmKey {
buffer: &mut Vec<u8>,
) -> Result<(), Error> {
match self {
AesCcmKey::Aes128Ccm(ccm) => {
AesCcmKey::Aes128(ccm) => {
ccm.encrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
AesCcmKey::Aes192(ccm) => {
ccm.encrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
AesCcmKey::Aes256Ccm(ccm) => {
AesCcmKey::Aes256(ccm) => {
ccm.encrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
}
Expand All @@ -57,15 +66,26 @@ impl AesCcmKey {
buffer: &mut Vec<u8>,
) -> Result<(), Error> {
match self {
AesCcmKey::Aes128Ccm(ccm) => {
AesCcmKey::Aes128(ccm) => {
ccm.decrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
AesCcmKey::Aes256Ccm(ccm) => {
AesCcmKey::Aes192(ccm) => {
ccm.decrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
AesCcmKey::Aes256(ccm) => {
ccm.decrypt_in_place(&nonce.0.into(), associated_data, buffer)
}
}
.map_err(|_| format_err!(ErrorKind::CryptoError, "error decrypting wrapped object!").into())
}

fn algorithm(&self) -> Algorithm {
match self {
AesCcmKey::Aes128(_) => Algorithm::Wrap(wrap::Algorithm::Aes128Ccm),
AesCcmKey::Aes192(_) => Algorithm::Wrap(wrap::Algorithm::Aes192Ccm),
AesCcmKey::Aes256(_) => Algorithm::Wrap(wrap::Algorithm::Aes256Ccm),
}
}
}

/// Objects stored in the `MockHsm`
Expand Down Expand Up @@ -235,7 +255,8 @@ impl Objects {
}

let mut wrapped_object = serialize(&WrappedObject {
object_info,
alg_id: wrap_key.algorithm(),
object_info: object_info.into(),
data: object_to_wrap.payload.to_bytes(),
})
.unwrap();
Expand Down Expand Up @@ -271,7 +292,7 @@ impl Objects {
);

let object = Object {
object_info: unwrapped_object.object_info,
object_info: unwrapped_object.object_info.into(),
payload,
};

Expand All @@ -297,17 +318,15 @@ impl Objects {
};

match wrap_key.algorithm().wrap().unwrap() {
wrap::Algorithm::Aes128Ccm => Ok(AesCcmKey::Aes128Ccm(
wrap::Algorithm::Aes128Ccm => Ok(AesCcmKey::Aes128(
Aes128Ccm::new_from_slice(&wrap_key.payload.to_bytes()).unwrap(),
)),
wrap::Algorithm::Aes256Ccm => Ok(AesCcmKey::Aes256Ccm(
wrap::Algorithm::Aes192Ccm => Ok(AesCcmKey::Aes192(
Aes192Ccm::new_from_slice(&wrap_key.payload.to_bytes()).unwrap(),
)),
wrap::Algorithm::Aes256Ccm => Ok(AesCcmKey::Aes256(
Aes256Ccm::new_from_slice(&wrap_key.payload.to_bytes()).unwrap(),
)),
unsupported => fail!(
ErrorKind::UnsupportedAlgorithm,
"unsupported wrap key algorithm: {:?}",
unsupported
),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
mod algorithm;
pub(crate) mod commands;
mod error;
mod info;
mod key;
mod message;
mod nonce;

pub use self::{
algorithm::Algorithm,
error::{Error, ErrorKind},
info::Info,
key::Key,
message::Message,
nonce::Nonce,
Expand Down
76 changes: 76 additions & 0 deletions src/wrap/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::{
algorithm,
object::{self, SequenceId},
Capability, Domain,
};
use serde::{Deserialize, Serialize};

/// Information about an object
///
/// This is a wrap-specific version of [`object::Info']. It does not carry any
/// delegated_capabilities.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Info {
/// Capabilities (bitfield)
pub capabilities: Capability,

/// Object identifier
pub object_id: object::Id,

/// Length of object in bytes
pub length: u16,

/// Domains from which object is accessible
pub domains: Domain,

/// Object type
pub object_type: object::Type,

/// Algorithm this object is intended to be used with
pub algorithm: algorithm::Algorithm,

/// Sequence: number of times an object with this key ID and type has
/// previously existed
pub sequence: SequenceId,

/// How did this object originate? (generated, imported, etc)
pub origin: object::Origin,

/// Label of object
pub label: object::Label,
}

impl From<object::Info> for Info {
fn from(i: object::Info) -> Self {
Self {
capabilities: i.capabilities,
object_id: i.object_id,
length: i.length,
domains: i.domains,
object_type: i.object_type,
algorithm: i.algorithm,
sequence: i.sequence,
origin: i.origin,
label: i.label,
}
}
}

impl From<Info> for object::Info {
fn from(i: Info) -> Self {
Self {
capabilities: i.capabilities,
object_id: i.object_id,
length: i.length,
domains: i.domains,
object_type: i.object_type,
algorithm: i.algorithm,
sequence: i.sequence,
origin: i.origin,
label: i.label,
// This is a wrapped object, delegate capabilities applies to wrap keys themselves.
// (and authentication keys).
delegated_capabilities: Capability::empty(),
}
}
}
Loading