use hpke::{Deserializable, Kem as KemTrait, Serializable};
use p256::ecdsa::{signature::Signer, Signature, SigningKey};
use rand_core::OsRng;
use crate::{
compress_p256_public, decrypt, encrypt, errors::EnclaveEncryptError, ClientSendMsg, Kem,
P256Public, ServerSendData, ServerSendMsgV1, ServerTargetData, ServerTargetMsgV1, DATA_VERSION,
TURNKEY_HPKE_INFO,
};
pub struct EnclaveEncryptServer {
enclave_auth_key: SigningKey,
target_public: <Kem as KemTrait>::PublicKey,
target_private: <Kem as KemTrait>::PrivateKey,
organization_id: String,
user_id: Option<String>,
}
impl EnclaveEncryptServer {
#[must_use]
pub fn from_enclave_auth_key(
enclave_auth_key: SigningKey,
organization_id: String,
user_id: Option<String>,
) -> Self {
let (target_private, target_public) = Kem::gen_keypair(&mut OsRng);
Self {
enclave_auth_key,
target_public,
target_private,
organization_id,
user_id,
}
}
#[must_use]
pub fn from_enclave_auth_key_and_target_key(
enclave_auth_key: SigningKey,
target_public_key: <Kem as KemTrait>::PublicKey,
target_private_key: <Kem as KemTrait>::PrivateKey,
organization_id: String,
user_id: Option<String>,
) -> Self {
Self {
enclave_auth_key,
target_public: target_public_key,
target_private: target_private_key,
organization_id,
user_id,
}
}
pub fn encrypt(
&self,
client_target: &P256Public,
plaintext: &[u8],
) -> Result<ServerSendMsgV1, EnclaveEncryptError> {
let client_target = <Kem as KemTrait>::PublicKey::from_bytes(&**client_target)
.map_err(EnclaveEncryptError::InvalidClientTarget)?;
let (ciphertext, encapped_public) = encrypt(&client_target, plaintext, TURNKEY_HPKE_INFO)?;
let data = ServerSendData {
encapped_public: encapped_public.to_bytes().to_vec().try_into()?,
ciphertext,
organization_id: self.organization_id.clone(),
};
let data_bytes = serde_json::to_string(&data)
.map_err(|_| EnclaveEncryptError::FailedToSerializeData)?
.into_bytes();
let data_signature: Signature = self.enclave_auth_key.sign(&data_bytes);
let enclave_quorum_public_bytes = self
.enclave_auth_key
.verifying_key()
.to_encoded_point(false)
.to_bytes()
.to_vec();
Ok(ServerSendMsgV1 {
version: DATA_VERSION.to_string(),
data: data_bytes,
data_signature: data_signature.to_der().to_bytes().to_vec().into(),
enclave_quorum_public: enclave_quorum_public_bytes.try_into()?,
})
}
pub fn auth_encrypt(
client_target: &P256Public,
plaintext: &[u8],
) -> Result<String, EnclaveEncryptError> {
let client_target = <Kem as KemTrait>::PublicKey::from_bytes(&**client_target)
.map_err(EnclaveEncryptError::InvalidClientTarget)?;
let (ciphertext, encapped_public) = encrypt(&client_target, plaintext, TURNKEY_HPKE_INFO)?;
let encapped_public_bytes = encapped_public.to_bytes().to_vec();
let compressed_encapped_public = compress_p256_public(&encapped_public_bytes)?;
let payload_bytes: Vec<_> = compressed_encapped_public
.iter()
.copied()
.chain(ciphertext)
.collect();
Ok(bs58::encode(&payload_bytes).with_check().into_string())
}
pub fn publish_target(&self) -> Result<ServerTargetMsgV1, EnclaveEncryptError> {
let user_id = self
.user_id
.as_ref()
.ok_or(EnclaveEncryptError::InvalidUser)?
.to_string();
let data = ServerTargetData {
target_public: self.target_public.to_bytes().to_vec().try_into()?,
organization_id: self.organization_id.clone(),
user_id,
};
let data_bytes = serde_json::to_string(&data)
.map_err(|_| EnclaveEncryptError::FailedToSerializeData)?
.into_bytes();
let data_signature: Signature = self.enclave_auth_key.sign(&data_bytes);
let enclave_quorum_public_bytes = self
.enclave_auth_key
.verifying_key()
.to_encoded_point(false)
.to_bytes()
.to_vec();
Ok(ServerTargetMsgV1 {
version: DATA_VERSION.to_string(),
data: data_bytes,
data_signature: data_signature.to_der().to_bytes().to_vec().into(),
enclave_quorum_public: enclave_quorum_public_bytes.try_into()?,
})
}
#[must_use]
pub fn into_recv(self) -> EnclaveEncryptServerRecv {
EnclaveEncryptServerRecv {
target_private: Some(self.target_private),
target_public: Some(self.target_public),
}
}
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct EnclaveEncryptServerRecv {
target_private: Option<<Kem as KemTrait>::PrivateKey>,
target_public: Option<<Kem as KemTrait>::PublicKey>,
}
impl EnclaveEncryptServerRecv {
pub fn decrypt(&mut self, msg: &ClientSendMsg) -> Result<Vec<u8>, EnclaveEncryptError> {
let encapped_public = <Kem as KemTrait>::EncappedKey::from_bytes(&*msg.encapped_public)
.map_err(EnclaveEncryptError::InvalidEncappedKey)?;
if let (Some(target_private), Some(target_public)) =
(self.target_private.as_ref(), self.target_public.as_ref())
{
let result = decrypt(
&encapped_public,
target_private,
target_public,
&msg.ciphertext,
TURNKEY_HPKE_INFO,
);
self.target_public = None;
self.target_private = None;
result
} else {
Err(EnclaveEncryptError::ServerAlreadyUsedToDecrypt)
}
}
}