1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use rand::Rng;
use std::io::Cursor;

use crate::traits::{HashAlgorithm, PublicKeyAlgorithm, SignatureAlgorithm, SymmetricAlgorithm};

pub fn encrypt<
    P: PublicKeyAlgorithm,
    S: SymmetricAlgorithm,
    H: HashAlgorithm,
    I: SignatureAlgorithm,
>(
    mut plaintext: Vec<u8>,
    receiver_pk: &P::PublicKey,
    self_sk: &I::SignKey,
) -> Result<Vec<u8>, ()> {
    let mut tmp_data = vec![];

    let mut hash_data = H::hash(&plaintext[..]);
    let mut signature = I::sign(&hash_data, self_sk);
    tmp_data.append(&mut hash_data);
    tmp_data.append(&mut signature);
    tmp_data.append(&mut plaintext);

    // TODO zip plaintext

    let session_bytes: Vec<u8> = (0..S::KEY_LENGTH)
        .map(|_| rand::thread_rng().gen::<u8>())
        .collect();
    let session_key = S::from_bytes(&session_bytes[..]).unwrap_or(Default::default());
    let mut ciphertext = S::encrypt(&tmp_data[..], &session_key);
    let mut cek = P::encrypt(&session_bytes[..], receiver_pk);

    let mut wtr = vec![];
    wtr.write_u32::<BigEndian>(cek.len() as u32).unwrap_or(());

    let mut last_data = vec![];
    last_data.append(&mut wtr);
    last_data.append(&mut cek);
    last_data.append(&mut ciphertext);

    // TODO ASCII radix-64

    Ok(last_data)
}

pub fn decrypt<
    P: PublicKeyAlgorithm,
    S: SymmetricAlgorithm,
    H: HashAlgorithm,
    I: SignatureAlgorithm,
>(
    mut data: Vec<u8>,
    sender_vk: &I::VerifyKey,
    self_sk: &P::SecretKey,
) -> Result<Vec<u8>, ()> {
    // TODO ASCII radix-64

    let (length, cipher) = data.split_at_mut(4);
    let mut rdr = Cursor::new(length);
    let length = rdr.read_u32::<BigEndian>().unwrap_or(0);
    let (cek, ciphertext) = cipher.split_at_mut(length as usize);
    let session_bytes = P::decrypt(cek, self_sk);
    let session_key = S::from_bytes(&session_bytes[..]).unwrap_or(Default::default());
    let mut plaintext = S::decrypt(ciphertext, &session_key);

    // TODO unzip

    let (hash, signature_plaintext) = plaintext.split_at_mut(H::HASH_LENGTH);
    let (signature, plaintext) = signature_plaintext.split_at_mut(I::SIGNATURE_LENGTH);

    if !I::verify(&hash, &signature, sender_vk) || hash != &H::hash(plaintext)[..] {
        return Err(());
    }

    Ok(plaintext.to_vec())
}