use sframe::{
CipherSuite,
crypto::{AeadDecrypt, AeadEncrypt, DecryptionBufferView, EncryptionBufferView, KeyDerivation},
error::{Result, SframeError},
frame::{MediaFrame, MonotonicCounter},
header::{Counter, KeyId},
key::crypto_key::{DecryptionKey, EncryptionKey},
};
#[derive(Clone, Debug)]
pub struct CaesarSecret {
shift: u8,
}
#[derive(Clone, Debug)]
pub struct CaesarAead {
cipher_suite: CipherSuite,
}
impl TryFrom<CipherSuite> for CaesarAead {
type Error = SframeError;
fn try_from(cipher_suite: CipherSuite) -> Result<Self> {
Ok(Self { cipher_suite })
}
}
impl AeadEncrypt for CaesarAead {
type Secret = CaesarSecret;
fn encrypt<'a, B>(&self, secret: &CaesarSecret, buffer: B, _counter: Counter) -> Result<()>
where
B: Into<EncryptionBufferView<'a>>,
{
let buffer_view: EncryptionBufferView = buffer.into();
for byte in buffer_view.data.iter_mut() {
*byte = byte.wrapping_add(secret.shift);
}
let checksum = buffer_view
.data
.iter()
.fold(0u8, |acc, &b| acc.wrapping_add(b));
for tag_byte in buffer_view.tag.iter_mut() {
*tag_byte = checksum;
}
Ok(())
}
}
impl AeadDecrypt for CaesarAead {
type Secret = CaesarSecret;
fn decrypt<'a, B>(&self, secret: &CaesarSecret, buffer: B, _counter: Counter) -> Result<()>
where
B: Into<DecryptionBufferView<'a>>,
{
let buffer_view: DecryptionBufferView = buffer.into();
let tag_len = self.cipher_suite.auth_tag_len();
let cipher_len = buffer_view.data.len().saturating_sub(tag_len);
let checksum = buffer_view.data[..cipher_len]
.iter()
.fold(0u8, |acc, &b| acc.wrapping_add(b));
let tag = &buffer_view.data[cipher_len..];
if !tag.iter().all(|&b| b == checksum) {
return Err(SframeError::DecryptionFailure);
}
for byte in buffer_view.data[..cipher_len].iter_mut() {
*byte = byte.wrapping_sub(secret.shift);
}
Ok(())
}
}
pub struct CaesarKdf;
impl KeyDerivation for CaesarKdf {
type Secret = CaesarSecret;
fn expand_from<M, K>(
_cipher_suite: CipherSuite,
key_material: M,
_key_id: K,
) -> Result<CaesarSecret>
where
M: AsRef<[u8]>,
K: Into<KeyId>,
{
let shift = key_material
.as_ref()
.iter()
.fold(0u8, |acc, &b| acc.wrapping_add(b));
Ok(CaesarSecret { shift })
}
}
fn main() -> Result<()> {
println!("Caesar Cipher Custom Backend Example");
println!("=====================================\n");
let cipher_suite = CipherSuite::AesGcm128Sha256;
let key_id = 42u64;
let key_material = b"my-secret-key-material";
let enc_key: EncryptionKey<CaesarAead, CaesarKdf> =
EncryptionKey::derive_from(cipher_suite, key_id, key_material)?;
let dec_key: DecryptionKey<CaesarAead, CaesarKdf> =
DecryptionKey::derive_from(cipher_suite, key_id, key_material)?;
println!("Key ID: {}", enc_key.key_id());
println!("Cipher Suite: {:?}\n", enc_key.cipher_suite());
let original_data = "Hello, SFrame with custom crypto!";
println!("Original: {:?}", original_data);
let mut counter = MonotonicCounter::default();
let media_frame = MediaFrame::new(&mut counter, original_data);
let encrypted_frame = media_frame.encrypt(&enc_key)?;
println!(
"Encrypted Frame Payload: {:?}",
encrypted_frame.cipher_text()
);
let decrypted_frame = encrypted_frame.decrypt(&dec_key)?;
println!("Decrypted: {:?}", decrypted_frame.payload());
assert_eq!(original_data.as_bytes(), decrypted_frame.payload());
println!("Success! Encryption and decryption with custom backend worked.");
Ok(())
}