use std::fmt::Debug;
use std::sync::LazyLock;
use crate::attribute::Attribute;
use crate::error::Result;
use crate::mechanism::*;
use crate::object::*;
use crate::ossl::chacha20::*;
use crate::pkcs11::*;
pub const CHACHA20_KEY_SIZE: usize = 32;
pub(crate) static CHACHA20_MECHS: LazyLock<[Box<dyn Mechanism>; 3]> =
LazyLock::new(|| {
[
Box::new(ChaCha20Mechanism::new(CKF_ENCRYPT | CKF_DECRYPT)),
Box::new(ChaCha20Mechanism::new(
CKF_ENCRYPT
| CKF_DECRYPT
| CKF_MESSAGE_ENCRYPT
| CKF_MESSAGE_DECRYPT
| CKF_MULTI_MESSAGE,
)),
Box::new(ChaCha20Mechanism::new(CKF_GENERATE)),
]
});
static CHACHA20_KEY_FACTORY: LazyLock<Box<dyn ObjectFactory>> =
LazyLock::new(|| Box::new(ChaCha20KeyFactory::new()));
pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) {
ChaChaOperation::register_mechanisms(mechs);
ot.add_factory(
ObjectType::new(CKO_SECRET_KEY, CKK_CHACHA20),
&(*CHACHA20_KEY_FACTORY),
);
}
#[derive(Debug)]
pub struct ChaCha20KeyFactory {
data: ObjectFactoryData,
}
impl ChaCha20KeyFactory {
fn new() -> ChaCha20KeyFactory {
let mut factory: ChaCha20KeyFactory = ChaCha20KeyFactory {
data: ObjectFactoryData::new(CKO_SECRET_KEY),
};
factory.add_common_secret_key_attrs();
let attributes = factory.data.get_attributes_mut();
attributes.push(attr_element!(
CKA_VALUE; OAFlags::Defval | OAFlags::Sensitive
| OAFlags::RequiredOnCreate | OAFlags::SettableOnlyOnCreate;
Attribute::from_bytes; val Vec::new()));
attributes.push(attr_element!(
CKA_VALUE_LEN; OAFlags::RequiredOnGenerate;
Attribute::from_ulong; val 0));
factory.data.finalize();
factory
}
}
impl ObjectFactory for ChaCha20KeyFactory {
fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
let mut obj = self.key_create(template)?;
let len = self.get_key_buffer_len(&obj)?;
if len != CHACHA20_KEY_SIZE {
return Err(CKR_KEY_SIZE_RANGE)?;
}
obj.ensure_ulong(CKA_VALUE_LEN, CK_ULONG::try_from(len)?)?;
Ok(obj)
}
fn get_data(&self) -> &ObjectFactoryData {
&self.data
}
fn get_data_mut(&mut self) -> &mut ObjectFactoryData {
&mut self.data
}
fn as_key_factory(&self) -> Result<&dyn KeyFactory> {
Ok(self)
}
fn as_secret_key_factory(&self) -> Result<&dyn SecretKeyFactory> {
Ok(self)
}
}
impl KeyFactory for ChaCha20KeyFactory {
fn export_for_wrapping(&self, key: &Object) -> Result<Vec<u8>> {
SecretKeyFactory::default_export_for_wrapping(self, key)
}
fn import_from_wrapped(
&self,
data: Vec<u8>,
template: &[CK_ATTRIBUTE],
) -> Result<Object> {
if data.len() != CHACHA20_KEY_SIZE {
return Err(CKR_KEY_SIZE_RANGE)?;
}
SecretKeyFactory::default_import_from_wrapped(self, data, template)
}
}
impl SecretKeyFactory for ChaCha20KeyFactory {
fn set_key(&self, obj: &mut Object, key: Vec<u8>) -> Result<()> {
if key.len() != CHACHA20_KEY_SIZE {
return Err(CKR_KEY_SIZE_RANGE)?;
}
obj.set_attr(Attribute::from_bytes(CKA_VALUE, key))?;
self.set_key_len(obj, CHACHA20_KEY_SIZE)?;
Ok(())
}
fn recommend_key_size(&self, max: usize) -> Result<usize> {
if max >= CHACHA20_KEY_SIZE {
Ok(CHACHA20_KEY_SIZE)
} else {
Err(CKR_KEY_SIZE_RANGE)?
}
}
}
#[derive(Debug)]
pub(crate) struct ChaCha20Mechanism {
info: CK_MECHANISM_INFO,
}
impl ChaCha20Mechanism {
pub fn new(flags: CK_FLAGS) -> ChaCha20Mechanism {
ChaCha20Mechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: CK_ULONG::try_from(CHACHA20_KEY_SIZE).unwrap(),
ulMaxKeySize: CK_ULONG::try_from(CHACHA20_KEY_SIZE).unwrap(),
flags: flags,
},
}
}
}
impl Mechanism for ChaCha20Mechanism {
fn info(&self) -> &CK_MECHANISM_INFO {
&self.info
}
fn encryption_new(
&self,
mech: &CK_MECHANISM,
key: &Object,
) -> Result<Box<dyn Encryption>> {
if self.info.flags & CKF_ENCRYPT != CKF_ENCRYPT {
return Err(CKR_MECHANISM_INVALID)?;
}
key.check_key_ops(CKO_SECRET_KEY, CKK_CHACHA20, CKA_ENCRYPT)?;
Ok(Box::new(ChaChaOperation::encrypt_new(mech, key)?))
}
fn decryption_new(
&self,
mech: &CK_MECHANISM,
key: &Object,
) -> Result<Box<dyn Decryption>> {
if self.info.flags & CKF_DECRYPT != CKF_DECRYPT {
return Err(CKR_MECHANISM_INVALID)?;
}
key.check_key_ops(CKO_SECRET_KEY, CKK_CHACHA20, CKA_DECRYPT)?;
Ok(Box::new(ChaChaOperation::decrypt_new(mech, key)?))
}
fn generate_key(
&self,
mech: &CK_MECHANISM,
template: &[CK_ATTRIBUTE],
_: &Mechanisms,
_: &ObjectFactories,
) -> Result<Object> {
if mech.mechanism != CKM_CHACHA20_KEY_GEN {
return Err(CKR_MECHANISM_INVALID)?;
}
let mut key = CHACHA20_KEY_FACTORY
.as_key_factory()?
.key_generate(template)?;
key.ensure_ulong(CKA_CLASS, CKO_SECRET_KEY)
.map_err(|_| CKR_TEMPLATE_INCONSISTENT)?;
key.ensure_ulong(CKA_KEY_TYPE, CKK_CHACHA20)
.map_err(|_| CKR_TEMPLATE_INCONSISTENT)?;
default_secret_key_generate(&mut key)?;
default_key_attributes(&mut key, mech.mechanism)?;
Ok(key)
}
fn msg_encryption_op(
&self,
mech: &CK_MECHANISM,
key: &Object,
) -> Result<Box<dyn MsgEncryption>> {
if self.info.flags & CKF_MESSAGE_ENCRYPT == 0 {
return Err(CKR_MECHANISM_INVALID)?;
}
key.check_key_ops(CKO_SECRET_KEY, CKK_CHACHA20, CKA_ENCRYPT)?;
Ok(Box::new(ChaChaOperation::msg_encrypt_init(mech, key)?))
}
fn msg_decryption_op(
&self,
mech: &CK_MECHANISM,
key: &Object,
) -> Result<Box<dyn MsgDecryption>> {
if self.info.flags & CKF_MESSAGE_DECRYPT == 0 {
return Err(CKR_MECHANISM_INVALID)?;
}
key.check_key_ops(CKO_SECRET_KEY, CKK_CHACHA20, CKA_DECRYPT)?;
Ok(Box::new(ChaChaOperation::msg_decrypt_init(mech, key)?))
}
}