<commit_before>pub mod pgp;
pub mod crypto;

use pgp::PgpKey;

use std::fmt;

#[derive(Debug)]
pub enum HedwigError {
    Signature,
    Crypto(crypto::CryptoError),
    Pgp(pgp::PgpError)
}

impl fmt::Display for HedwigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HedwigError::Crypto(ref err) => err.fmt(f),
            HedwigError::Pgp(ref err) => err.fmt(f),
            HedwigError::Signature => write!(f, "Signature validation failed")
        }
    }
}

impl From<crypto::CryptoError> for HedwigError {
    fn from(err: crypto::CryptoError) -> HedwigError {
        HedwigError::Crypto(err)
    }
}

impl From<pgp::PgpError> for HedwigError {
    fn from(err: pgp::PgpError) -> HedwigError {
        HedwigError::Pgp(err)
    }
}

pub type HedwigResult<T> = Result<T, HedwigError>;

fn pgp_public_to_ssl(pgp: &pgp::PublicKey) -> crypto::CryptoResult<crypto::RSA> {
    let mut key = try!(crypto::RSA::new());
    key.set_n(try!(crypto::BIGNUM::new(&pgp.n)));
    key.set_e(try!(crypto::BIGNUM::new(&pgp.e)));
    Ok(key)
}

fn pgp_private_to_ssl(pgp: &pgp::PrivateKey) -> crypto::CryptoResult<crypto::RSA> {
    let mut key = try!(pgp_public_to_ssl(&pgp.public));
    key.set_d(try!(crypto::BIGNUM::new(&pgp.d)));
    key.set_p(try!(crypto::BIGNUM::new(&pgp.p)));
    key.set_q(try!(crypto::BIGNUM::new(&pgp.q)));
    Ok(key)
}

pub fn encrypt_message(sender: &pgp::PrivateKey, receiver: &pgp::PublicKey, data: &[u8]) -> HedwigResult<Vec<u8>> {
    let aes_key = crypto::rand::bytes(32);
    let mut aes = crypto::AES::new(&aes_key);
    let iv = crypto::rand::bytes(16);
    let payload = aes.cfb_encrypt(data, &iv);

    let mut pub_key = try!(pgp_public_to_ssl(receiver));
    let mut priv_key = try!(pgp_private_to_ssl(sender));

    let mut sha1 = crypto::SHA1::new();
    sha1.update(&payload);
    let payload_hash = sha1.finalize();

    let signature = try!(priv_key.private_encrypt(&payload_hash));

    let header: Vec<u8> = aes_key.iter()
        .chain(iv.iter())
        .chain(receiver.fingerprint().iter())
        .chain(sender.fingerprint().iter())
        .cloned().collect();
    let encrypted_header = try!(pub_key.public_encrypt(&header));

    Ok(encrypted_header.iter()
       .chain(signature.iter())
       .chain(payload.iter())
       .cloned().collect())
}

pub fn decrypt_message(receiver: &pgp::PrivateKey, sender: &pgp::PublicKey, data: &[u8]) -> HedwigResult<Vec<u8>> {
    let mut priv_key = try!(pgp_private_to_ssl(receiver));
    let mut pub_key = try!(pgp_public_to_ssl(sender));

    let priv_size = priv_key.size();
    let pub_size = pub_key.size();
    let header = try!(priv_key.private_decrypt(&data[..priv_size]));
    let signature = try!(pub_key.public_decrypt(&data[priv_size..priv_size+pub_size]));
    let payload = &data[priv_size+pub_size..];
    let mut sha1 = crypto::SHA1::new();
    sha1.update(&payload);
    let payload_hash = sha1.finalize();
    if signature != payload_hash {
        return Err(HedwigError::Signature)
    }
    let mut aes = crypto::AES::new(&header[0..32]);
    Ok(aes.cfb_decrypt(payload, &header[32..48]))
}

#[cfg(test)]
mod tests {
    use super::*;

    static MESSAGE: &'static str = "Hello, World!";

    #[test]
    fn can_roundtrip_message() {
        let pubkey = pgp::read_armored_packet(pgp::tests::PUBKEY, None)
            .unwrap().public_key().unwrap();
        let privkey = pgp::read_armored_packet(pgp::tests::PRIVKEY, Some("password"))
            .unwrap().private_key().unwrap();

        let encrypted_message = encrypt_message(&privkey, &pubkey, MESSAGE.as_bytes()).unwrap();
        let decrypted_message = decrypt_message(&privkey, &pubkey, &encrypted_message).unwrap();

        assert_eq!(decrypted_message, MESSAGE.as_bytes());
    }
}<commit_msg>[fix #100432928] Split recieving messages and decrypting them<commit_after>pub mod pgp;
pub mod crypto;

use pgp::PgpKey;

use std::fmt;

#[derive(Debug)]
pub enum HedwigError {
    Signature,
    NotMyMessage,
    Crypto(crypto::CryptoError),
    Pgp(pgp::PgpError)
}

impl fmt::Display for HedwigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HedwigError::Crypto(ref err) => err.fmt(f),
            HedwigError::Pgp(ref err) => err.fmt(f),
            HedwigError::Signature => write!(f, "Signature validation failed"),
            HedwigError::NotMyMessage => write!(f, "Message not intended for this recipient")
        }
    }
}

impl From<crypto::CryptoError> for HedwigError {
    fn from(err: crypto::CryptoError) -> HedwigError {
        HedwigError::Crypto(err)
    }
}

impl From<pgp::PgpError> for HedwigError {
    fn from(err: pgp::PgpError) -> HedwigError {
        HedwigError::Pgp(err)
    }
}

pub type HedwigResult<T> = Result<T, HedwigError>;

pub struct Message<'a> {
    sender_fingerprint: Vec<u8>,
    aes_key: Vec<u8>,
    aes_iv: Vec<u8>,
    data: &'a [u8]
}

fn pgp_public_to_ssl(pgp: &pgp::PublicKey) -> crypto::CryptoResult<crypto::RSA> {
    let mut key = try!(crypto::RSA::new());
    key.set_n(try!(crypto::BIGNUM::new(&pgp.n)));
    key.set_e(try!(crypto::BIGNUM::new(&pgp.e)));
    Ok(key)
}

fn pgp_private_to_ssl(pgp: &pgp::PrivateKey) -> crypto::CryptoResult<crypto::RSA> {
    let mut key = try!(pgp_public_to_ssl(&pgp.public));
    key.set_d(try!(crypto::BIGNUM::new(&pgp.d)));
    key.set_p(try!(crypto::BIGNUM::new(&pgp.p)));
    key.set_q(try!(crypto::BIGNUM::new(&pgp.q)));
    Ok(key)
}

pub fn encrypt_message(sender: &pgp::PrivateKey, receiver: &pgp::PublicKey, data: &[u8]) -> HedwigResult<Vec<u8>> {
    let aes_key = crypto::rand::bytes(32);
    let mut aes = crypto::AES::new(&aes_key);
    let iv = crypto::rand::bytes(16);
    let payload = aes.cfb_encrypt(data, &iv);

    let mut pub_key = try!(pgp_public_to_ssl(receiver));
    let mut priv_key = try!(pgp_private_to_ssl(sender));

    let mut sha1 = crypto::SHA1::new();
    sha1.update(&payload);
    let payload_hash = sha1.finalize();

    let signature = try!(priv_key.private_encrypt(&payload_hash));

    let header: Vec<u8> = aes_key.iter()
        .chain(iv.iter())
        .chain(receiver.fingerprint().iter())
        .chain(sender.fingerprint().iter())
        .cloned().collect();
    let encrypted_header = try!(pub_key.public_encrypt(&header));

    Ok(encrypted_header.iter()
       .chain(signature.iter())
       .chain(payload.iter())
       .cloned().collect())
}

pub fn receive_message<'a, 'b>(receiver: &'a pgp::PrivateKey, data: &'b [u8]) -> HedwigResult<Message<'b>> {
    let mut key = try!(pgp_private_to_ssl(receiver));

    let header_size = key.size();
    let header = try!(key.private_decrypt(&data[..header_size]));

    if header.len() != 88 {
        return Err(HedwigError::NotMyMessage);
    }

    let aes_key = &header[0..32];
    let aes_iv = &header[32..48];
    let recipient_fingerprint = &header[48..68];
    let sender_fingerprint = &header[68..88];

    if recipient_fingerprint != receiver.fingerprint() {
        Err(HedwigError::NotMyMessage)
    } else {
        Ok( Message { sender_fingerprint: sender_fingerprint.to_owned(),
                      aes_key: aes_key.to_owned(),
                      aes_iv: aes_iv.to_owned(),
                      data: &data[header_size..] })
    }
}

pub fn decrypt_message(sender: &pgp::PublicKey, msg: &Message) -> HedwigResult<Vec<u8>> {
    let mut key = try!(pgp_public_to_ssl(sender));
    let mut aes = crypto::AES::new(&msg.aes_key);
    let mut sha1 = crypto::SHA1::new();
    let sig_size = key.size();
    let signature = try!(key.public_decrypt(&msg.data[..sig_size]));
    let payload = &msg.data[sig_size..];
    sha1.update(&payload);
    let hash = sha1.finalize();
    if signature != hash {
        Err(HedwigError::Signature)
    } else {
        Ok(aes.cfb_decrypt(payload, &msg.aes_iv))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::pgp::PgpKey;

    static MESSAGE: &'static str = "Hello, World!";

    #[test]
    fn can_roundtrip_message() {
        let pubkey = pgp::read_armored_packet(pgp::tests::PUBKEY, None)
            .unwrap().public_key().unwrap();
        let privkey = pgp::read_armored_packet(pgp::tests::PRIVKEY, Some("password"))
            .unwrap().private_key().unwrap();

        let encrypted_message = encrypt_message(&privkey, &pubkey, MESSAGE.as_bytes()).unwrap();

        let received_message = receive_message(&privkey, &encrypted_message).unwrap();
        assert_eq!(received_message.sender_fingerprint, privkey.fingerprint());

        let decrypted_message = decrypt_message(&pubkey, &received_message).unwrap();
        assert_eq!(decrypted_message, MESSAGE.as_bytes());
    }
}
{'fraction_non_alphanumeric': 0.16892201834862386, 'fraction_numerical': 0.008142201834862386, 'mean_word_length': 3.643769968051118, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6757495', 'n_tokens_mistral': 3192, 'n_tokens_neox': 3097, 'n_words': 535}