#![cfg_attr(feature = "sgx", no_std)]
#[cfg(feature = "sgx")]
extern crate sgx_tstd as std;
#[cfg(feature = "sgx")]
use sgx_tcrypto::*;
#[cfg(feature = "sgx")]
use sgx_types::*;
use super::SgxError;
#[cfg(not(feature = "sgx"))]
use k256::ecdsa::{Signature, SigningKey, VerifyingKey};
#[cfg(not(feature = "sgx"))]
use k256::{EncodedPoint, PublicKey};
#[cfg(not(feature = "sgx"))]
use sha2::{Digest, Sha256};
pub struct SgxCrypto {
#[cfg(feature = "sgx")]
context: SgxCryptoContext,
}
#[cfg(feature = "sgx")]
struct SgxCryptoContext {
sealed_keys: Vec<SgxSealedKey>,
}
#[cfg(feature = "sgx")]
struct SgxSealedKey {
key_id: [u8; 16],
sealed_data: Vec<u8>,
}
impl SgxCrypto {
pub fn compute_shared_secret(
&self,
private_key: &[u8; 32],
public_key: &[u8; 64],
) -> Result<[u8; 32], SgxError> {
#[cfg(feature = "sgx")]
{
Err(SgxError::CryptoError("SGX ECDH not fully implemented yet".to_string()))
}
#[cfg(not(feature = "sgx"))]
{
use k256::elliptic_curve::sec1::FromEncodedPoint;
let mut encoded_pub = vec![0x04];
encoded_pub.extend_from_slice(public_key);
let point = EncodedPoint::from_bytes(&encoded_pub)
.map_err(|_| SgxError::CryptoError("Invalid public key".to_string()))?;
let verifying_key = PublicKey::from_encoded_point(&point)
.ok_or_else(|| SgxError::CryptoError("Invalid public key point".to_string()))?;
let signing_key = SigningKey::from_slice(private_key)
.map_err(|_| SgxError::CryptoError("Invalid private key".to_string()))?;
let shared_secret = k256::elliptic_curve::ecdh::diffie_hellman(
signing_key.as_nonzero_scalar(),
verifying_key.as_affine()
);
let bytes = shared_secret.raw_secret_bytes();
let mut result = [0u8; 32];
result.copy_from_slice(bytes.as_slice());
Ok(result)
}
}
pub fn new() -> Result<Self, SgxError> {
#[cfg(feature = "sgx")]
{
Ok(Self { context: SgxCryptoContext { sealed_keys: Vec::new() } })
}
#[cfg(not(feature = "sgx"))]
{
Ok(Self {})
}
}
pub fn sha256(&self, data: &[u8]) -> Result<[u8; 32], SgxError> {
#[cfg(feature = "sgx")]
{
let mut hash = [0u8; 32];
let result = unsafe {
sgx_sha256_msg(
data.as_ptr(),
data.len() as u32,
&mut hash as *mut _ as *mut sgx_sha256_hash_t,
)
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("SHA256 computation failed".into()));
}
Ok(hash)
}
#[cfg(not(feature = "sgx"))]
{
let mut hasher = Sha256::new();
hasher.update(data);
let result = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&result);
Ok(hash)
}
}
pub fn sign_ecdsa(&self, message: &[u8], private_key: &[u8; 32]) -> Result<Vec<u8>, SgxError> {
#[cfg(feature = "sgx")]
{
let mut signature = vec![0u8; 64];
let hash = self.sha256(message)?;
let result = unsafe {
let ecc_handle = sgx_ecc256_open_context();
if ecc_handle.is_null() {
return Err(SgxError::CryptoError("Failed to open ECC context".into()));
}
let mut ecc_signature = sgx_ec256_signature_t::default();
let private = sgx_ec256_private_t { r: *private_key };
let status = sgx_ecdsa_sign(
&hash as *const _ as *const u8,
32,
&private as *const _,
&mut ecc_signature as *mut _,
ecc_handle,
);
sgx_ecc256_close_context(ecc_handle);
if status != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("ECDSA signing failed".into()));
}
signature[..32].copy_from_slice(&ecc_signature.x);
signature[32..].copy_from_slice(&ecc_signature.y);
status
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("ECDSA signing failed".into()));
}
Ok(signature)
}
#[cfg(not(feature = "sgx"))]
{
use k256::ecdsa::signature::Signer;
let signing_key = SigningKey::from_bytes(private_key.into())
.map_err(|e| SgxError::CryptoError(format!("Invalid private key: {}", e)))?;
let signature: Signature = signing_key.sign(message);
Ok(signature.to_bytes().to_vec())
}
}
pub fn verify_ecdsa(
&self,
message: &[u8],
signature: &[u8],
public_key: &[u8],
) -> Result<bool, SgxError> {
#[cfg(feature = "sgx")]
{
let hash = self.sha256(message)?;
let result = unsafe {
let ecc_handle = sgx_ecc256_open_context();
if ecc_handle.is_null() {
return Err(SgxError::CryptoError("Failed to open ECC context".into()));
}
let mut ecc_signature = sgx_ec256_signature_t::default();
ecc_signature.x.copy_from_slice(&signature[..32]);
ecc_signature.y.copy_from_slice(&signature[32..64]);
let mut public = sgx_ec256_public_t::default();
public.gx.copy_from_slice(&public_key[..32]);
public.gy.copy_from_slice(&public_key[32..64]);
let mut valid: u8 = 0;
let status = sgx_ecdsa_verify(
&hash as *const _ as *const u8,
32,
&public as *const _,
&ecc_signature as *const _,
&mut valid as *mut _,
ecc_handle,
);
sgx_ecc256_close_context(ecc_handle);
if status != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("ECDSA verification failed".into()));
}
Ok(valid == 1)
};
result
}
#[cfg(not(feature = "sgx"))]
{
use k256::ecdsa::signature::Verifier;
let verifying_key = VerifyingKey::from_sec1_bytes(public_key)
.map_err(|e| SgxError::CryptoError(format!("Invalid public key: {}", e)))?;
let signature = Signature::from_slice(signature)
.map_err(|e| SgxError::CryptoError(format!("Invalid signature: {}", e)))?;
Ok(verifying_key.verify(message, &signature).is_ok())
}
}
pub fn random_bytes(&self, size: usize) -> Result<Vec<u8>, SgxError> {
let mut buffer = vec![0u8; size];
#[cfg(feature = "sgx")]
{
let result = unsafe { sgx_read_rand(buffer.as_mut_ptr(), size) };
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("Random generation failed".into()));
}
}
#[cfg(not(feature = "sgx"))]
{
use rand::RngCore;
rand::rng().fill_bytes(&mut buffer);
}
Ok(buffer)
}
pub fn generate_keypair(&self) -> Result<([u8; 32], [u8; 64]), SgxError> {
#[cfg(feature = "sgx")]
{
let ecc_handle = unsafe { sgx_ecc256_open_context() };
if ecc_handle.is_null() {
return Err(SgxError::CryptoError("Failed to open ECC context".into()));
}
let mut private = sgx_ec256_private_t::default();
let mut public = sgx_ec256_public_t::default();
let status =
unsafe { sgx_ecc256_create_key_pair(&mut private, &mut public, ecc_handle) };
unsafe {
sgx_ecc256_close_context(ecc_handle);
}
if status != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("Failed to generate keypair".into()));
}
let mut priv_bytes = [0u8; 32];
priv_bytes.copy_from_slice(&private.r);
let mut pub_bytes = [0u8; 64];
pub_bytes[..32].copy_from_slice(&public.gx);
pub_bytes[32..].copy_from_slice(&public.gy);
Ok((priv_bytes, pub_bytes))
}
#[cfg(not(feature = "sgx"))]
{
use rand_core::OsRng;
let signing_key = SigningKey::random(&mut OsRng);
let verify_key: VerifyingKey = signing_key.verifying_key();
let encoded: EncodedPoint = PublicKey::from(&verify_key).to_encoded_point(false);
let bytes = encoded.as_bytes();
if bytes.len() != 65 || bytes[0] != 0x04 {
return Err(SgxError::CryptoError("Unexpected public key encoding".into()));
}
let mut pub_bytes = [0u8; 64];
pub_bytes.copy_from_slice(&bytes[1..]);
let priv_bytes: [u8; 32] = signing_key.to_bytes().into();
Ok((priv_bytes, pub_bytes))
}
}
}
pub struct SgxKeyManager {
#[cfg(feature = "sgx")]
sealed_keys: Vec<SealedKey>,
}
#[cfg(feature = "sgx")]
struct SealedKey {
key_id: [u8; 16],
sealed_data: Vec<u8>,
key_policy: sgx_attributes_t,
}
impl SgxKeyManager {
pub fn new() -> Self {
Self {
#[cfg(feature = "sgx")]
sealed_keys: Vec::new(),
}
}
#[cfg(feature = "sgx")]
pub fn seal_key(&mut self, key_id: &[u8; 16], key_data: &[u8]) -> Result<(), SgxError> {
let sealed_size = unsafe { sgx_calc_sealed_data_size(0, key_data.len() as u32) };
if sealed_size == u32::MAX {
return Err(SgxError::CryptoError("Failed to calculate sealed size".into()));
}
let mut sealed_data = vec![0u8; sealed_size as usize];
let result = unsafe {
sgx_seal_data(
0,
core::ptr::null(),
key_data.len() as u32,
key_data.as_ptr(),
sealed_size,
sealed_data.as_mut_ptr() as *mut sgx_sealed_data_t,
)
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("Failed to seal key".into()));
}
self.sealed_keys.push(SealedKey {
key_id: *key_id,
sealed_data,
key_policy: sgx_attributes_t::default(),
});
Ok(())
}
#[cfg(feature = "sgx")]
pub fn unseal_key(&self, key_id: &[u8; 16]) -> Result<Vec<u8>, SgxError> {
let sealed_key = self
.sealed_keys
.iter()
.find(|k| k.key_id == *key_id)
.ok_or_else(|| SgxError::CryptoError("Key not found".into()))?;
let unsealed_size = unsafe {
sgx_get_encrypt_txt_len(sealed_key.sealed_data.as_ptr() as *const sgx_sealed_data_t)
};
let mut unsealed_data = vec![0u8; unsealed_size as usize];
let mut mac_len = 0u32;
let result = unsafe {
sgx_unseal_data(
sealed_key.sealed_data.as_ptr() as *const sgx_sealed_data_t,
core::ptr::null_mut(),
&mut mac_len,
unsealed_data.as_mut_ptr(),
&mut (unsealed_size as u32),
)
};
if result != sgx_status_t::SGX_SUCCESS {
return Err(SgxError::CryptoError("Failed to unseal key".into()));
}
Ok(unsealed_data)
}
#[cfg(not(feature = "sgx"))]
pub fn seal_key(&mut self, _key_id: &[u8; 16], _key_data: &[u8]) -> Result<(), SgxError> {
Ok(())
}
#[cfg(not(feature = "sgx"))]
pub fn unseal_key(&self, _key_id: &[u8; 16]) -> Result<Vec<u8>, SgxError> {
Err(SgxError::CryptoError("SGX not enabled".into()))
}
}
pub fn init_crypto() -> Result<(), SgxError> {
Ok(())
}