Skip to content
This repository has been archived by the owner on May 9, 2022. It is now read-only.

Commit

Permalink
refactor(rtc_tenclave,protected_channel): factor out DeterministicAes…
Browse files Browse the repository at this point in the history
…GcmIvConstructor

Also add additional documentation and context around the IV
construction.
  • Loading branch information
PiDelport committed May 28, 2021
1 parent 5b6f3d5 commit 2741ebe
Showing 1 changed file with 53 additions and 22 deletions.
75 changes: 53 additions & 22 deletions rtc_tenclave/src/dh/protected_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,37 @@
use secrecy::{ExposeSecret, Secret};
use sgx_tcrypto::{rsgx_rijndael128GCM_decrypt, rsgx_rijndael128GCM_encrypt};
use sgx_types::*;
use std::{convert::TryInto, u32};

use super::types::AlignedKey;
use crate::util::concat_u8;

#[cfg(test)]
use super::enclave;
#[cfg(not(test))]
use sgx_tstd::enclave;

// NIST AES-GCM recommended IV size
type GcmNonce = [u8; 12];
type RecommendedAesGcmIv = [u8; 12];

pub struct ProtectedChannel {
counter: u32,
iv_constructor: DeterministicAesGcmIvConstructor,
key: Secret<AlignedKey>,
}

impl ProtectedChannel {
pub fn init(key: Secret<AlignedKey>) -> Self {
Self { counter: 1, key }
Self {
iv_constructor: DeterministicAesGcmIvConstructor::for_current_enclave(),
key,
}
}

pub fn encrypt_message<const MESSAGE_SIZE: usize, const AAD_SIZE: usize>(
&mut self,
plaintext: [u8; MESSAGE_SIZE],
aad: [u8; AAD_SIZE],
) -> Result<EncryptedEnclaveMessage<MESSAGE_SIZE, AAD_SIZE>, sgx_status_t> {
let nonce = self.gen_nonce();
let nonce = self.iv_constructor.next();
let mut dst = [0_u8; MESSAGE_SIZE];
let mut mac = sgx_aes_gcm_128bit_tag_t::default();
rsgx_rijndael128GCM_encrypt(
Expand Down Expand Up @@ -65,27 +68,55 @@ impl ProtectedChannel {
)?;
Ok(dst)
}

fn gen_nonce(&mut self) -> GcmNonce {
self.counter = self.counter + 1;
let counter_bytes = self.counter.to_ne_bytes();
// TODO: Verify all parameters used here is valid for the local attestation context
// Constructing the iv (nonce) using a counter and value unique to the running
// enclave (for the purposes of local attestation).
// See: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[
enclave::get_enclave_id().to_ne_bytes().as_ref(), // 8 bytes unique to this enclave
counter_bytes.as_ref(), // 4 bytes incrementing on access
]
.concat()
.try_into()
.unwrap()
}
}

pub struct EncryptedEnclaveMessage<const MESSAGE_SIZE: usize, const AAD_SIZE: usize> {
tag: sgx_aes_gcm_128bit_tag_t,
ciphertext: [u8; MESSAGE_SIZE],
aad: [u8; AAD_SIZE],
nonce: GcmNonce,
nonce: RecommendedAesGcmIv,
}

/// Implement the deterministic construction of AES-GCM IVs, as described in section 8.2.1 of [NIST SP 800-38D],
/// "Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC".
///
/// In this construction, the IV is the concatenation of two fields:
///
/// 1. The **fixed** field, unique between each device using a given secret key.
/// This implementation uses a 64-bit enclave identifier.
///
/// 2. The **invocation** field, unique for each device message.
/// This implementation uses a 32-bit counter.
///
/// Note that _NIST SP 800-38D_ recommends a 32-bit fixed field and 64-bit invocation field,
/// but this implementation swaps the sizes around, to match the enclave identifier size.
///
/// [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
struct DeterministicAesGcmIvConstructor {
fixed: [u8; 8],
invocation_counter: u32,
}

impl DeterministicAesGcmIvConstructor {
/// Initialise a new instance based on [`sgx_tstd::enclave::get_enclave_id`].
fn for_current_enclave() -> Self {
DeterministicAesGcmIvConstructor {
fixed: enclave::get_enclave_id().to_ne_bytes(),
invocation_counter: Default::default(),
}
}

/// Return the next constructed IV.
///
/// # Panics
///
/// This will panic if the 32-bit invocation counter overflows.
/// This should not happen during normal use, as a given secret key should not be used for more than 2^32 invocations.
fn next(&mut self) -> RecommendedAesGcmIv {
self.invocation_counter = self.invocation_counter.checked_add(1).expect(
"DeterministicAesGcmIvConstructor: invocation counter overflow, unsafe to proceed",
);

concat_u8(&self.fixed, &self.invocation_counter.to_ne_bytes())
}
}

0 comments on commit 2741ebe

Please sign in to comment.