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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
use crate::{Error, Result, CONFIG};
use base64;
use byteorder::{LittleEndian, ReadBytesExt};
use crc;
use crypto::{
    self, aes, blockmodes,
    buffer::{self, BufferResult, ReadBuffer, WriteBuffer},
    digest::Digest,
    sha2,
};
use std::io::Cursor;

pub fn decode_ekey(
    ekey: &str,
    sub_key: &str,
    secret_key: &str,
    secret_key_bytes: &[u8],
) -> Result<u64> {
    if ekey.len() == 0 {
        return Err(Error::InvalidInput.into());
    }
    let ekey = ekey.to_string();
    let padding: String = vec!['='; 3 - ekey.len() % 3].into_iter().collect();
    let ekey = ekey + &padding.to_string();
    let emsg = match base64::decode_config(&ekey, base64::URL_SAFE) {
        Ok(m) => m,
        Err(_) => return Err(Error::InvalidInput.into()),
    };

    let mut sha = sha2::Sha256::new();
    sha.input_str(&format!("{}{}", secret_key, sub_key));
    let mut iv: Vec<u8> = vec![0; 32];
    sha.result(&mut iv);
    let iv = &iv[..16];

    let mut decryptor = aes::cbc_decryptor(
        aes::KeySize::KeySize256,
        &secret_key_bytes[..32],
        iv,
        blockmodes::NoPadding,
    );

    let mut final_result = Vec::<u8>::new();
    let mut read_buffer = buffer::RefReadBuffer::new(&emsg);
    let mut buffer = [0; 16];
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        let result = decryptor.decrypt(&mut read_buffer, &mut write_buffer, true);
        let result = match result {
            Ok(v) => v,
            Err(e) => return Err(Error::Decrypt(e).into()),
        };
        final_result.extend(
            write_buffer
                .take_read_buffer()
                .take_remaining()
                .iter()
                .map(|&i| i),
        );

        match result {
            BufferResult::BufferUnderflow => break,
            BufferResult::BufferOverflow => {}
        }
    }

    let mut rdr = Cursor::new(final_result);
    let crc = rdr.read_u32::<LittleEndian>()? & 0xffffffff;
    let id = rdr.read_u64::<LittleEndian>()?;
    let version = rdr.read_u32::<LittleEndian>()?;

    let expected_crc: u32;
    if version == 0 {
        expected_crc = crc::crc32::checksum_ieee(&vec![0; id as usize]) & 0xffffffff;
    } else {
        let id_bytes: String = id.to_string();
        let id_bytes = id_bytes.as_bytes();
        expected_crc = crc::crc32::checksum_ieee(id_bytes) & 0xffffffff;
    }

    if crc != expected_crc {
        return Err(Error::CRCMismatch.into());
    }

    Ok(id)
}

pub fn decode_ekey_util(ekey: &str, sub_key: &str) -> Result<u64> {
    let config = CONFIG.read().unwrap();
    if config.secret_key.is_none() {
        return Err(Error::SecretKeyNotFound.into());
    }
    decode_ekey(
        ekey,
        sub_key,
        config.secret_key.as_ref().unwrap(),
        config.secret_key_bytes.as_ref(),
    )
}