use crate::error::CryptError;
use crate::key_control::*;
use std::path::PathBuf;
#[derive(PartialEq, Debug, Clone)]
pub struct Key {
key_type: KeyTypes,
content: Vec<u8>,
}
impl Key {
pub fn new(key_type: KeyTypes, content: Vec<u8>) -> Self {
let content = Self::validate_and_copy(&key_type, content);
Key { key_type, content }
}
fn validate_and_copy(key_type: &KeyTypes, content: Vec<u8>) -> Vec<u8> {
#[cfg(feature = "legacy-pqclean")]
{
use pqcrypto_kyber::kyber1024;
use pqcrypto_traits::kem::{Ciphertext, PublicKey, SecretKey, SharedSecret};
match key_type {
KeyTypes::PublicKey => {
if let Ok(k) = kyber1024::PublicKey::from_bytes(&content) {
return k.as_bytes().to_vec();
}
}
KeyTypes::SecretKey => {
if let Ok(k) = kyber1024::SecretKey::from_bytes(&content) {
return k.as_bytes().to_vec();
}
}
KeyTypes::Ciphertext => {
if let Ok(k) = kyber1024::Ciphertext::from_bytes(&content) {
return k.as_bytes().to_vec();
}
}
KeyTypes::SharedSecret => {
if let Ok(k) = kyber1024::SharedSecret::from_bytes(&content) {
return k.as_bytes().to_vec();
}
}
_ => {}
}
}
let _ = key_type; content
}
pub fn new_public_key(key: Vec<u8>) -> Self {
Key {
key_type: KeyTypes::PublicKey,
content: key,
}
}
pub fn new_secret_key(key: Vec<u8>) -> Self {
Key {
key_type: KeyTypes::SecretKey,
content: key,
}
}
pub fn new_ciphertext(key: Vec<u8>) -> Self {
Key {
key_type: KeyTypes::Ciphertext,
content: key,
}
}
pub fn new_shared_secret(key: Vec<u8>) -> Self {
Key {
key_type: KeyTypes::SharedSecret,
content: key,
}
}
pub fn get(&self) -> Result<&Key, CryptError> {
Ok(self)
}
pub fn key_type(&self) -> Result<&KeyTypes, CryptError> {
Ok(&self.key_type)
}
pub fn content(&self) -> Result<&[u8], CryptError> {
Ok(&self.content)
}
pub fn save(&self, base_path: PathBuf) -> Result<(), CryptError> {
let file_name = match self.key_type {
KeyTypes::PublicKey => "public_key.pub",
KeyTypes::SecretKey => "secret_key.sec",
KeyTypes::Ciphertext => "ciphertext.ct",
KeyTypes::SharedSecret => return Err(CryptError::UnsupportedOperation),
_ => return Err(CryptError::InvalidKeyType),
};
let path = base_path.join(file_name);
let file_metadata =
FileMetadata::from(path, self.file_type_from_key_type(), FileState::Encrypted);
file_metadata.save(&self.content)
}
fn file_type_from_key_type(&self) -> FileTypes {
match self.key_type {
KeyTypes::PublicKey => FileTypes::PublicKey,
KeyTypes::SecretKey => FileTypes::SecretKey,
KeyTypes::Ciphertext => FileTypes::Ciphertext,
_ => FileTypes::Other,
}
}
pub fn encap(&self) -> Result<(Key, Key), CryptError> {
match self.key_type {
KeyTypes::PublicKey => self.encap_inner(),
_ => Err(CryptError::EncapsulationError),
}
}
#[cfg(feature = "legacy-pqclean")]
fn encap_inner(&self) -> Result<(Key, Key), CryptError> {
use pqcrypto_kyber::kyber1024;
use pqcrypto_traits::kem::{Ciphertext as CT, PublicKey, SharedSecret as SST};
let pk = kyber1024::PublicKey::from_bytes(self.content()?)
.map_err(|_| CryptError::InvalidKemPublicKey)?;
let (ss, ct) = kyber1024::encapsulate(&pk);
Ok((
Key::new_ciphertext(ct.as_bytes().to_vec()),
Key::new_shared_secret(ss.as_bytes().to_vec()),
))
}
#[cfg(not(feature = "legacy-pqclean"))]
fn encap_inner(&self) -> Result<(Key, Key), CryptError> {
Err(CryptError::UnsupportedOperation)
}
pub fn decap(&self, ciphertext: Key) -> Result<Key, CryptError> {
match self.key_type {
KeyTypes::SecretKey => self.decap_inner(ciphertext),
_ => Err(CryptError::DecapsulationError),
}
}
#[cfg(feature = "legacy-pqclean")]
fn decap_inner(&self, ciphertext: Key) -> Result<Key, CryptError> {
use pqcrypto_kyber::kyber1024;
use pqcrypto_traits::kem::{Ciphertext as CT, SecretKey};
let ct = kyber1024::Ciphertext::from_bytes(ciphertext.content()?)
.map_err(|_| CryptError::InvalidKemCiphertext)?;
let sk = kyber1024::SecretKey::from_bytes(self.content()?)
.map_err(|_| CryptError::InvalidKemSecretKey)?;
let ss = kyber1024::decapsulate(&ct, &sk);
use pqcrypto_traits::kem::SharedSecret as SST;
Ok(Key::new_shared_secret(ss.as_bytes().to_vec()))
}
#[cfg(not(feature = "legacy-pqclean"))]
fn decap_inner(&self, _ciphertext: Key) -> Result<Key, CryptError> {
Err(CryptError::UnsupportedOperation)
}
}