From 5acb6038932dda2714f4b8bace7e84f648f8aa4f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 14 Nov 2023 02:53:52 -0500 Subject: [PATCH] Improve documentation and add constant time partialeq to keys --- Cargo.toml | 3 --- src/jose.rs | 2 ++ src/key_exchange.rs | 23 ++++++++++++++++++----- src/lib.rs | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b59ef84..15d4467 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,14 +24,11 @@ sha2 = "0.10.8" serde_json = { version = "1.0.108", features = ["preserve_order"] } ureq = { version = "2.8.0", features = ["json"] } sha1 = "0.10.6" -hex = "0.4.3" -k256 = { version = "0.13.1", features = ["ecdh", "ecdsa", "jwk"] } p256 = { version = "0.13.2", features = ["ecdh", "ecdsa", "jwk"] } p384 = { version = "0.13.0", features = ["ecdh", "ecdsa", "jwk"] } p521 = { version = ">=0.13.3", features = ["ecdh", "ecdsa", "jwk"] } base64ct = { version = "1.6.0", features = ["alloc"] } elliptic-curve = { version = "0.13.6", features = ["jwk"] } -primeorder = "0.13.3" aead = "0.5.2" concat-kdf = "0.1.0" ecdsa = "0.16.8" diff --git a/src/jose.rs b/src/jose.rs index 067d556..9c1810e 100644 --- a/src/jose.rs +++ b/src/jose.rs @@ -435,9 +435,11 @@ pub struct GeneratedKey { /// Both this metadata and a connection to the Tang server are needed to regenerate the /// key for use with encryption. This data can be stored in JSON form. /// + ///
/// Note that while this data does not contain the encryption key, it should still not /// be exposed. Any device that can read this metadata could potentially decrypt /// the ciphertext if it has access to the Tang server. + ///
pub meta: KeyMeta, } diff --git a/src/key_exchange.rs b/src/key_exchange.rs index 31088fe..2dd0259 100644 --- a/src/key_exchange.rs +++ b/src/key_exchange.rs @@ -8,6 +8,7 @@ use elliptic_curve::rand_core::OsRng; use elliptic_curve::sec1::FromEncodedPoint; use elliptic_curve::sec1::ModulusSize; use elliptic_curve::sec1::ToEncodedPoint; +use elliptic_curve::subtle::ConstantTimeEq; use elliptic_curve::zeroize::Zeroizing; use elliptic_curve::AffinePoint; use elliptic_curve::Curve; @@ -19,17 +20,29 @@ use elliptic_curve::PublicKey; use elliptic_curve::SecretKey; /// A zeroizing wrapper around a generated encryption key -#[derive(Clone, Debug, PartialEq)] -pub struct EncryptionKey(Zeroizing<[u8; N]>); +#[derive(Clone, Debug)] +pub struct EncryptionKey(Zeroizing<[u8; KEYBYTES]>); -impl EncryptionKey { - /// Return the secret key +impl EncryptionKey { + /// Return a reference to the secret key. Treat this data with respect! #[must_use] - pub fn as_bytes(&self) -> &[u8; N] { + pub fn as_bytes(&self) -> &[u8; KEYBYTES] { &self.0 } } +impl ConstantTimeEq for EncryptionKey { + fn ct_eq(&self, other: &Self) -> elliptic_curve::subtle::Choice { + self.0.ct_eq(other.0.as_ref()) + } +} + +impl PartialEq for EncryptionKey { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + /// Perform key generation in accordance with tang protocol /// /// Rough description, capitals are public: diff --git a/src/lib.rs b/src/lib.rs index a7a969f..0109e80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,40 @@ +//! A Rust implementation of the Tang portion of Clevis, specified in +//! . +//! +//! ``` +//! # #[cfg(not(feature = "_backend"))] fn main() {} +//! # #[cfg(feature = "_backend")] +//! # fn main() { +//! use clevis::{KeyMeta, TangClient}; +//! +//! /// 32-byte (256 bit) key +//! const KEY_BYTES: usize = 32; +//! +//! /* key provisioning */ +//! +//! let client = TangClient::new("localhost:11697", None); +//! +//! // create a key suitible for encryption (i.e. has gone through a KDF) +//! let out = client.create_secure_key::().expect("failed to generate key"); +//! +//! // use this key to encrypt data +//! let original_key = out.encryption_key; +//! +//! // this must be stored to get the encryption key back for decryption +//! // WARNING: this information should be considered secret, since any device that can +//! // access this and the tang server can retrieve the encryption key. Treat it with +//! // respect! +//! let meta_str = out.meta.to_json(); +//! +//! /* key recovery */ +//! +//! let new_meta = KeyMeta::from_json(&meta_str).expect("invalid metadata"); +//! let new_key = client.recover_secure_key::(&new_meta).expect("failed to retrieve key"); +//! +//! assert_eq!(original_key, new_key); +//! # } +//! ``` + #![warn(clippy::pedantic)] #![allow(clippy::missing_panics_doc)] #![allow(clippy::missing_errors_doc)]