use crate::ecdh::{ecdh_decrypt, ecdh_encrypt};
use crate::errors::{BottleError, Result};
use crate::signing::Sign;
use rand::RngCore;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Bottle {
message: Vec<u8>,
encryptions: Vec<EncryptionLayer>,
signatures: Vec<SignatureLayer>,
metadata: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct EncryptionLayer {
ciphertext: Vec<u8>,
key_fingerprint: Vec<u8>,
algorithm: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct SignatureLayer {
signature: Vec<u8>,
key_fingerprint: Vec<u8>,
algorithm: String,
}
#[derive(Debug, Clone)]
pub struct BottleInfo {
pub is_encrypted: bool,
pub is_signed: bool,
pub signers: Vec<Vec<u8>>,
pub recipients: Vec<Vec<u8>>,
}
impl Bottle {
pub fn new(message: Vec<u8>) -> Self {
Self {
message,
encryptions: Vec::new(),
signatures: Vec::new(),
metadata: HashMap::new(),
}
}
pub fn message(&self) -> &[u8] {
&self.message
}
pub fn is_encrypted(&self) -> bool {
!self.encryptions.is_empty()
}
pub fn is_signed(&self) -> bool {
!self.signatures.is_empty()
}
pub fn encryption_count(&self) -> usize {
self.encryptions.len()
}
pub fn encrypt<R: RngCore + rand::CryptoRng>(
&mut self,
rng: &mut R,
public_key: &[u8],
) -> Result<()> {
let data_to_encrypt = if self.encryptions.is_empty() {
self.message.clone()
} else {
self.message.clone()
};
let ciphertext = ecdh_encrypt(rng, &data_to_encrypt, public_key)?;
let fingerprint = crate::hash::sha256(public_key);
let layer = EncryptionLayer {
ciphertext: ciphertext.clone(),
key_fingerprint: fingerprint,
algorithm: "ECDH-AES256-GCM".to_string(),
};
self.message = ciphertext;
self.encryptions.push(layer);
Ok(())
}
pub fn sign<R: RngCore>(
&mut self,
rng: &mut R,
signer: &dyn Sign,
public_key: &[u8],
) -> Result<()> {
let data_to_sign = self.create_signing_data()?;
let signature = signer.sign(rng, &data_to_sign)?;
let fingerprint = crate::hash::sha256(public_key);
let layer = SignatureLayer {
signature,
key_fingerprint: fingerprint,
algorithm: "ECDSA-SHA256".to_string(), };
self.signatures.push(layer);
Ok(())
}
pub fn set_metadata(&mut self, key: &str, value: &str) {
self.metadata.insert(key.to_string(), value.to_string());
}
pub fn metadata(&self, key: &str) -> Option<&str> {
self.metadata.get(key).map(|s| s.as_str())
}
fn create_signing_data(&self) -> Result<Vec<u8>> {
let mut data = self.message.clone();
for enc in &self.encryptions {
data.extend_from_slice(&enc.ciphertext);
}
Ok(data)
}
pub fn to_bytes(&self) -> Result<Vec<u8>> {
bincode::serialize(self)
.map_err(|e| BottleError::Serialization(format!("Failed to serialize bottle: {}", e)))
}
pub fn from_bytes(data: &[u8]) -> Result<Self> {
bincode::deserialize(data).map_err(|e| {
BottleError::Deserialization(format!("Failed to deserialize bottle: {}", e))
})
}
}
pub struct Opener {
}
impl Opener {
pub fn new() -> Self {
Self {}
}
pub fn open(&self, bottle: &Bottle, private_key: Option<&[u8]>) -> Result<Vec<u8>> {
if bottle.encryptions.is_empty() {
return Ok(bottle.message.clone());
}
let key = private_key.ok_or(BottleError::NoAppropriateKey)?;
let mut current_data = bottle.message.clone();
for _layer in bottle.encryptions.iter().rev() {
current_data = ecdh_decrypt(¤t_data, key)?;
}
Ok(current_data)
}
pub fn open_info(&self, bottle: &Bottle) -> Result<BottleInfo> {
Ok(BottleInfo {
is_encrypted: bottle.is_encrypted(),
is_signed: bottle.is_signed(),
signers: bottle
.signatures
.iter()
.map(|s| s.key_fingerprint.clone())
.collect(),
recipients: bottle
.encryptions
.iter()
.map(|e| e.key_fingerprint.clone())
.collect(),
})
}
}
impl Default for Opener {
fn default() -> Self {
Self::new()
}
}
impl BottleInfo {
pub fn is_signed_by(&self, public_key: &[u8]) -> bool {
let fingerprint = crate::hash::sha256(public_key);
self.signers.contains(&fingerprint)
}
}