X-Git-Url: http://git.euphorik.ch/?a=blobdiff_plain;f=src%2Fcrypto.rs;h=caf34f7cd10b7f2f50ee10ea0e83cbd3416d1ed4;hb=f43bab0b61b36e53135569727476fc6f39a3deec;hp=419055252cd971e82d35fecbcb2595ca128192f0;hpb=7b132e2976883c7b8e63540129a36eb63ceb33c5;p=rup.git diff --git a/src/crypto.rs b/src/crypto.rs index 4190552..caf34f7 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -1,10 +1,89 @@ +use openssl::{symm, sha::sha256}; +use rand::prelude::*; -pub fn encrypt(key: &str, plain_text: &str) -> String { - String::new() +use crate::consts; + +#[derive(Debug)] +pub enum KeyError { + UnableToDecodeBase64Key, + WrongKeyLength, +} + +#[derive(Debug)] +pub enum EncryptError { + KeyError(KeyError), + UnableToEncrypt, } -pub fn decrypt(key: &str, cypher_text: &str) -> Option { +#[derive(Debug)] +pub enum DecryptError { + KeyError(KeyError), + WrongMessageVersion, + MessageToShort, + UnableToDecodeBase64Message, + UnableToDecrypt, + UnableToDecodeMessageAsUTF8String, + HashMismatch, +} + +fn decode_key(key: &str) -> Result, KeyError> { + match base64::decode(key) { + Ok(k) => if k.len() != 16 { Err(KeyError::WrongKeyLength) } else { Ok(k) }, + Err(_e) => Err(KeyError::UnableToDecodeBase64Key) + } +} + +/// Encrypt the given text with the given key. The key length must be 128 bits encoded in base64. +/// Ouput format: "1" + base_64( + + ) +/// IV: 16 bytes randomized. +/// Mode : CBC. +pub fn encrypt(key: &str, plain_text: &str) -> Result { + let key_as_bytes = decode_key(key).map_err(EncryptError::KeyError)?; + + let text_as_bytes = plain_text.as_bytes(); + let iv = rand::thread_rng().gen::<[u8; 16]>(); + + let cipher_text = + symm::encrypt(symm::Cipher::aes_128_cbc(), &key_as_bytes, Some(&iv), text_as_bytes) + .map_err(|_e| EncryptError::UnableToEncrypt)?; + + let hash_text = sha256(&text_as_bytes); + + let mut result: Vec = Vec::new(); + result.extend(&iv); + result.extend(&hash_text); + result.extend(&cipher_text); + + Ok(String::from("1") + &base64::encode(&result)) +} + +/// Decrypt the given text with the given key. The key length must be 128 bits encoded in base64. +/// Input format: "1" + base_64( + + ) +pub fn decrypt(key: &str, cipher_text: &str) -> Result { + let key_as_bytes = decode_key(key).map_err(DecryptError::KeyError)?; + + // Can't decrypt a message with the wrong version. + if !cipher_text.starts_with(consts::CURRENT_MESSAGE_VERSION) { return Err(DecryptError::WrongMessageVersion) } + + let cipher_text_bytes = + base64::decode(&cipher_text.as_bytes()[consts::CURRENT_MESSAGE_VERSION.as_bytes().len()..]) + .map_err(|_e| DecryptError::UnableToDecodeBase64Message)?; + + if cipher_text_bytes.len() <= 48 { return Err(DecryptError::MessageToShort) } + + let iv = &cipher_text_bytes[0..16]; + let hash = &cipher_text_bytes[16..48]; + let encrypted_message = &cipher_text_bytes[48..]; + + let plain_message_bytes = + symm::decrypt(symm::Cipher::aes_128_cbc(), &key_as_bytes, Some(iv), encrypted_message) + .map_err(|_e| DecryptError::UnableToDecrypt)?; + + if sha256(&plain_message_bytes) != hash { return Err(DecryptError::HashMismatch) } + + let plain_message = + String::from_utf8(plain_message_bytes) + .map_err(|_e| DecryptError::UnableToDecodeMessageAsUTF8String)?; - println!("cypher: {}", cypher_text); - Some(String::new()) + Ok(plain_message) }