use base64::{engine::general_purpose::STANDARD as b64, Engine};
use aead::{generic_array::GenericArray, Aead, AeadCore, KeyInit};
use aes_gcm::aes;
use aes_gcm::aes::cipher::{BlockDecrypt, BlockEncrypt};
use ed25519_dalek::{Signer, Verifier};
pub fn str_to_32_bytes(val: &str) -> [u8; 32] {
let result = blake3::hash(val.as_bytes());
*result.as_bytes()
}
pub fn encode_32_bytes_to_string(val: &[u8; 32]) -> String {
b64.encode(val)
}
pub fn decode_32_bytes_from_string(val: &str) -> Result<[u8; 32], &'static str> {
let decoded_val = match b64.decode(val) {
Ok(val) => val,
Err(_) => return Err("failed to decode val"),
};
let decoded_val_as_bytes: [u8; 32] = match decoded_val.try_into() {
Ok(val) => val,
Err(_) => return Err("failed to convert decoded val into fixed bytes"),
};
Ok(decoded_val_as_bytes)
}
pub fn block_encrypt_32_bytes(
key: &[u8; 32],
content: &[u8; 32],
) -> Result<[u8; 32], &'static str> {
let cipher = aes::Aes256Enc::new(GenericArray::from_slice(key));
let block_one: [u8; 16] = match content[0..16].try_into() {
Ok(block) => block,
Err(_) => return Err("failed to convert block one to fixed bytes"),
};
let block_two: [u8; 16] = match content[16..32].try_into() {
Ok(block) => block,
Err(_) => return Err("failed to convert block two to fixed bytes"),
};
let mut block_one_as_generic_array = GenericArray::from(block_one);
let mut block_two_as_generic_array = GenericArray::from(block_two);
cipher.encrypt_block(&mut block_one_as_generic_array);
cipher.encrypt_block(&mut block_two_as_generic_array);
let mut combined_array: [u8; 32] = [0u8; 32];
combined_array[0..16].copy_from_slice(block_one_as_generic_array.as_slice());
combined_array[16..32].copy_from_slice(block_two_as_generic_array.as_slice());
Ok(combined_array)
}
pub fn block_decrypt_32_bytes(
key: &[u8; 32],
encrypted_content: &[u8; 32],
) -> Result<[u8; 32], &'static str> {
let cipher = aes::Aes256Dec::new(GenericArray::from_slice(key));
let block_one: [u8; 16] = match encrypted_content[0..16].try_into() {
Ok(block) => block,
Err(_) => return Err("failed to convert block one to fixed bytes"),
};
let block_two: [u8; 16] = match encrypted_content[16..32].try_into() {
Ok(block) => block,
Err(_) => return Err("failed to convert block two to fixed bytes"),
};
let mut block_one_as_generic_array = GenericArray::from(block_one);
let mut block_two_as_generic_array = GenericArray::from(block_two);
cipher.decrypt_block(&mut block_one_as_generic_array);
cipher.decrypt_block(&mut block_two_as_generic_array);
let mut combined_array: [u8; 32] = [0; 32];
combined_array[0..16].copy_from_slice(block_one_as_generic_array.as_slice());
combined_array[16..32].copy_from_slice(block_two_as_generic_array.as_slice());
Ok(combined_array)
}
pub fn aead_block_encrypt(key: &[u8; 32], content: &[u8]) -> Result<Vec<u8>, &'static str> {
let cipher = aes_gcm::Aes256Gcm::new(key.into());
let nonce = aes_gcm::Aes256Gcm::generate_nonce(&mut rand_core::OsRng);
let ciphertext = match cipher.encrypt(&nonce, content) {
Ok(ct) => ct,
Err(_) => return Err("failed to encrypt"),
};
let mut out = vec![];
out.extend(nonce);
out.extend(ciphertext);
Ok(out)
}
pub fn aead_block_decrypt(
key: &[u8; 32],
encrypted_content: &[u8],
) -> Result<Vec<u8>, &'static str> {
let cipher = aes_gcm::Aes256Gcm::new(key.into());
let nonce_as_bytes: [u8; 12] = match encrypted_content[0..12].try_into() {
Ok(v) => v,
Err(_) => return Err("failed to convert block one to fixed bytes"),
};
let nonce = aes_gcm::Nonce::from(nonce_as_bytes);
match cipher.decrypt(&nonce, &encrypted_content[12..]) {
Ok(out) => Ok(out),
Err(_) => Err("failed to decrypt"),
}
}
pub fn generate_fingerprint() -> ([u8; 32], [u8; 32]) {
let fingerprint = ed25519_dalek::SigningKey::generate(&mut rand_core::OsRng);
(
fingerprint.to_bytes(),
fingerprint.verifying_key().to_bytes(),
)
}
pub fn sign_content(content: &[u8], fingerprint: &[u8; 32]) -> [u8; 64] {
let fingerprint = ed25519_dalek::SigningKey::from_bytes(fingerprint);
let signature = fingerprint.sign(content);
signature.to_bytes()
}
pub fn verify_signature(
signature: &[u8; 64],
verifying_key: &[u8; 32],
content: &[u8],
) -> Result<(), &'static str> {
let signature = ed25519_dalek::Signature::from_bytes(signature);
let verifying_key = match ed25519_dalek::VerifyingKey::from_bytes(verifying_key) {
Ok(vk) => vk,
Err(_) => return Err("failed to generate verifying key from pub signing key"),
};
match verifying_key.verify(content, &signature) {
Ok(_) => Ok(()),
Err(_) => return Err("failed to verify signature for content"),
}
}
pub fn generate_exchange_keys() -> ([u8; 32], [u8; 32]) {
let priv_key = x25519_dalek::StaticSecret::random_from_rng(rand_core::OsRng);
let pub_key = x25519_dalek::PublicKey::from(&priv_key);
(*priv_key.as_bytes(), *pub_key.as_bytes())
}
pub fn encrypt_content(
fingerprint: &[u8; 32],
content: &[u8],
pub_keys: &[u8],
) -> Result<(Vec<u8>, Vec<u8>), &'static str> {
let fingerprint = ed25519_dalek::SigningKey::from_bytes(fingerprint);
let mut content_signature = fingerprint.sign(content).to_vec();
content_signature.extend(content);
let nonce = chacha20poly1305::XChaCha20Poly1305::generate_nonce(&mut rand_core::OsRng);
let content_key = chacha20poly1305::XChaCha20Poly1305::generate_key(&mut rand_core::OsRng);
let content_cipher = chacha20poly1305::XChaCha20Poly1305::new(&content_key);
let encrypted_content = match content_cipher.encrypt(&nonce, content_signature.as_ref()) {
Ok(ec) => ec,
Err(_) => return Err("failed to encrypt content"),
};
let mut key_sets: Vec<u8> = vec![];
let (ot_priv_key, ot_pub_key) = generate_exchange_keys();
let ot_priv_key = x25519_dalek::StaticSecret::from(ot_priv_key);
for pub_key in pub_keys.chunks(32) {
let pub_key_as_bytes: [u8; 32] = match pub_key.try_into() {
Ok(v) => v,
Err(_) => return Err("failed to convert pub key to fixed bytes"),
};
let shared_secret = ot_priv_key
.diffie_hellman(&x25519_dalek::PublicKey::from(pub_key_as_bytes))
.to_bytes();
let content_key_as_bytes: [u8; 32] = match content_key.try_into() {
Ok(v) => v,
Err(_) => return Err("failed to convert content key to fixed bytes"),
};
match block_encrypt_32_bytes(&shared_secret, &content_key_as_bytes) {
Ok(encrypted_content_key) => {
key_sets.extend(pub_key_as_bytes);
key_sets.extend(encrypted_content_key);
}
Err(err) => return Err(err),
};
}
let mut out = ot_pub_key.to_vec();
out.extend(nonce);
out.extend(encrypted_content);
Ok((key_sets, out))
}
pub fn decrypt_content(
verifying_key: Option<&[u8; 32]>,
priv_key: [u8; 32],
content_key: &[u8; 32],
encrypted_content: &[u8],
) -> Result<Vec<u8>, &'static str> {
let pub_key: [u8; 32] = match encrypted_content[0..32].try_into() {
Ok(key) => key,
Err(_) => return Err("failed to convert pub key to fixed bytes bytes"),
};
let nonce: [u8; 24] = match encrypted_content[32..56].try_into() {
Ok(key) => key,
Err(_) => return Err("failed to convert nonce to fixed bytes bytes"),
};
let priv_key = x25519_dalek::StaticSecret::from(priv_key);
let ot_pub_key = x25519_dalek::PublicKey::from(pub_key);
let shared_secret = priv_key.diffie_hellman(&ot_pub_key).to_bytes();
let content_key = match block_decrypt_32_bytes(&shared_secret, content_key) {
Ok(key) => key,
Err(err) => return Err(err),
};
let content_cipher =
chacha20poly1305::XChaCha20Poly1305::new(GenericArray::from_slice(&content_key));
match content_cipher.decrypt(
&chacha20poly1305::XNonce::from(nonce),
&encrypted_content[56..],
) {
Ok(content) => {
let signature_as_bytes: [u8; 64] = match content[0..64].try_into() {
Ok(v) => v,
Err(_) => return Err("failed to convert signature to fixed bytes"),
};
let content = content[64..].to_vec();
match verifying_key {
Some(vk) => match verify_signature(&signature_as_bytes, vk, &content) {
Ok(_) => Ok(content),
Err(_) => Err("failed to verify signature"),
},
None => Ok(content),
}
}
Err(_) => return Err("failed to decrypt content"),
}
}