<commit_before>use std::io::Cursor;

use rand::thread_rng;
use rand::Rng;
use rustc_serialize::base64;
use rustc_serialize::base64::{FromBase64, ToBase64};
use byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};
use openssl::crypto::symm;

use errors::WeChatError;

#[derive(Debug, Eq, PartialEq)]
pub struct PrpCrypto {
    key: Vec<u8>,
}

impl PrpCrypto {
    pub fn new(key: &[u8]) -> PrpCrypto {
        PrpCrypto {
            key: key.to_vec(),
        }
    }

    fn get_random_string() -> String {
        if cfg!(test) {
            "1234567890123456".to_owned()
        } else {
            thread_rng().gen_ascii_chars().take(16).collect()
        }
    }

    pub fn encrypt(&self, plaintext: &str, _id: &str) -> Result<String, WeChatError> {
        let mut wtr = PrpCrypto::get_random_string().into_bytes();
        wtr.write_u32::<NativeEndian>((plaintext.len() as u32).to_be()).unwrap();
        wtr.extend(plaintext.bytes());
        wtr.extend(_id.bytes());
        let encrypted = symm::encrypt(symm::Type::AES_256_CBC, &self.key, &self.key[..16], &wtr);
        let b64encoded = encrypted.to_base64(base64::STANDARD);
        Ok(b64encoded)
    }

    pub fn decrypt(&self, ciphertext: &str, _id: &str) -> Result<String, WeChatError> {
        let b64decoded = match ciphertext.from_base64() {
            Ok(val) => val,
            Err(err) => return Err(WeChatError::InvalidBase64(err)),
        };
        let text = symm::decrypt(symm::Type::AES_256_CBC, &self.key, &self.key[..16], &b64decoded);
        let mut rdr = Cursor::new(text[16..20].to_vec());
        let content_length = u32::from_be(rdr.read_u32::<NativeEndian>().unwrap()) as usize;
        let content = &text[20 .. content_length + 20];
        let from_id = &text[content_length + 20 ..];
        if from_id != _id.as_bytes() {
            return Err(WeChatError::InvalidAppId);
        }<commit_msg>Refactor FromBase64Error handling using try! macro<commit_after>use std::io::Cursor;

use rand::thread_rng;
use rand::Rng;
use rustc_serialize::base64;
use rustc_serialize::base64::{FromBase64, ToBase64};
use byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};
use openssl::crypto::symm;

use errors::WeChatError;

#[derive(Debug, Eq, PartialEq)]
pub struct PrpCrypto {
    key: Vec<u8>,
}

impl PrpCrypto {
    pub fn new(key: &[u8]) -> PrpCrypto {
        PrpCrypto {
            key: key.to_vec(),
        }
    }

    fn get_random_string() -> String {
        if cfg!(test) {
            "1234567890123456".to_owned()
        } else {
            thread_rng().gen_ascii_chars().take(16).collect()
        }
    }

    pub fn encrypt(&self, plaintext: &str, _id: &str) -> Result<String, WeChatError> {
        let mut wtr = PrpCrypto::get_random_string().into_bytes();
        wtr.write_u32::<NativeEndian>((plaintext.len() as u32).to_be()).unwrap();
        wtr.extend(plaintext.bytes());
        wtr.extend(_id.bytes());
        let encrypted = symm::encrypt(symm::Type::AES_256_CBC, &self.key, &self.key[..16], &wtr);
        let b64encoded = encrypted.to_base64(base64::STANDARD);
        Ok(b64encoded)
    }

    pub fn decrypt(&self, ciphertext: &str, _id: &str) -> Result<String, WeChatError> {
        let b64decoded = try!(ciphertext.from_base64());
        let text = symm::decrypt(symm::Type::AES_256_CBC, &self.key, &self.key[..16], &b64decoded);
        let mut rdr = Cursor::new(text[16..20].to_vec());
        let content_length = u32::from_be(rdr.read_u32::<NativeEndian>().unwrap()) as usize;
        let content = &text[20 .. content_length + 20];
        let from_id = &text[content_length + 20 ..];
        if from_id != _id.as_bytes() {
            return Err(WeChatError::InvalidAppId);
        }
{'fraction_non_alphanumeric': 0.16049382716049382, 'fraction_numerical': 0.03864734299516908, 'mean_word_length': 3.0687772925764194, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 23, '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': '3914422', 'n_tokens_mistral': 1399, 'n_tokens_neox': 1299, 'n_words': 239}