Skip to main content

islet_sdk/
sealing.rs

1use crate::error::Error;
2
3use openssl::rand::rand_bytes;
4use openssl::symm::{decrypt_aead, encrypt_aead, Cipher};
5use serde::{Deserialize, Serialize};
6use zeroize::Zeroizing;
7
8// These seal and unseal functions are implemented similarly as in the VMWare's Certifier Framework.
9// Here are the main assumptions:
10// - The requested symmetric Sealing Key is bound to the platform, firmware and the Realm Initial Measurement (RIM).
11//   Thus, any change of the platform, firmware, or a realm image will result in a different key.
12// - AES-256-GCM is used as an encryption algorithm; the AAD is not set
13// - The plaintext is encrypted and put into a sealed data structure. This strucure is comprised of
14//   the header and the ciphertext, the header contains the IV and the authentication TAG.
15//   The whole structure is serialized using serde and bincode crates to produce binary object, that then can
16//   be saved in a file on the host side.
17
18// We take VHUK_M (Measurement based Virtual Hardware Unique Key) and RIM
19// as a key material during the sealing key derivation process
20#[cfg(target_arch = "aarch64")]
21const UNIQUE_SEALING_KEY: u64 =
22    rust_rsi::RSI_SEALING_KEY_FLAGS_KEY | rust_rsi::RSI_SEALING_KEY_FLAGS_RIM;
23
24const AES_GCM_256_IV_LEN: usize = 12;
25const AES_GCM_256_TAG_LEN: usize = 16;
26const SEALING_KEY_LEN: usize = 32;
27
28// An embedded sealing key used on the simulated platform
29#[cfg(target_arch = "x86_64")]
30const SEALING_KEY: [u8; SEALING_KEY_LEN] = [
31    0x63, 0x10, 0xc1, 0xf0, 0x53, 0xd5, 0x52, 0x40, 0x29, 0xfa, 0x7f, 0x7d, 0xcd, 0x9e, 0x28, 0x2c,
32    0x4a, 0x93, 0x9d, 0x55, 0xb9, 0x89, 0x15, 0x44, 0x45, 0xa3, 0x86, 0x1e, 0x1f, 0xa1, 0xe2, 0xce,
33];
34
35#[derive(Serialize, Deserialize)]
36struct Header {
37    tag: [u8; AES_GCM_256_TAG_LEN],
38    iv: [u8; AES_GCM_256_IV_LEN],
39}
40
41impl Header {
42    fn new() -> Result<Self, Error> {
43        let mut instance = Self {
44            tag: [0u8; AES_GCM_256_TAG_LEN],
45            iv: [0u8; AES_GCM_256_IV_LEN],
46        };
47        rand_bytes(&mut instance.iv).map_err(|_| Error::Sealing)?;
48        Ok(instance)
49    }
50}
51
52#[derive(Serialize, Deserialize)]
53struct SealedData {
54    header: Header,
55    ciphertext: Vec<u8>,
56}
57
58fn sealing_key() -> Result<[u8; SEALING_KEY_LEN], Error> {
59    cfg_if::cfg_if! {
60        // Return the embedded sealing key for simulated platform
61        if #[cfg(target_arch="x86_64")] {
62            Ok(SEALING_KEY)
63        } else {
64            rust_rsi::sealing_key(UNIQUE_SEALING_KEY, 0).or(Err(Error::SealingKey))
65        }
66    }
67}
68
69pub fn seal(plaintext: &[u8]) -> Result<Vec<u8>, Error> {
70    let mut header = Header::new()?;
71    let cipher = Cipher::aes_256_gcm();
72    let sealing_key = Zeroizing::new(sealing_key().map_err(|_| Error::SealingKey)?);
73
74    let enc_res = encrypt_aead(
75        cipher,
76        sealing_key.as_ref(),
77        Some(&header.iv),
78        &[],
79        plaintext,
80        &mut header.tag,
81    );
82
83    let sealed_data = SealedData {
84        header: header,
85        ciphertext: enc_res.map_err(|_| Error::Sealing)?,
86    };
87
88    bincode::serialize(&sealed_data).map_err(|_| Error::Sealing)
89}
90
91pub fn unseal(sealed: &[u8]) -> Result<Vec<u8>, Error> {
92    let sealed_data: SealedData = bincode::deserialize(sealed).map_err(|_| Error::Sealing)?;
93    let cipher = Cipher::aes_256_gcm();
94    let sealing_key = Zeroizing::new(sealing_key().map_err(|_| Error::SealingKey)?);
95
96    let dec_res = decrypt_aead(
97        cipher,
98        sealing_key.as_ref(),
99        Some(&sealed_data.header.iv),
100        &[],
101        &sealed_data.ciphertext,
102        &sealed_data.header.tag,
103    );
104
105    dec_res.map_err(|_| Error::Sealing)
106}