mla 2.0.0-alpha

Multi Layer Archive - A pure rust encrypted and compressed archive file format
Documentation
use zeroize::Zeroize;

use crate::errors::Error;

const BASE64_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

pub(crate) fn base64_encode(data: &[u8]) -> Vec<u8> {
    let mut encoded = Vec::new();
    let mut i = 0;
    while i < data.len() {
        let mut val: u32 = 0;
        let mut n = 0;
        while n < 3 && i < data.len() {
            val = (val << 8) | (data[i] as u32);
            n += 1;
            i += 1;
        }
        if n == 1 {
            val <<= 16;
        } else if n == 2 {
            val <<= 8;
        }
        for j in 0..4 {
            if j < (n + 1) {
                let mut idx = ((val >> ((3 - j) * 6)) & 0x3F) as usize;
                encoded.push(BASE64_CHARS[idx]);
                idx.zeroize();
            } else {
                encoded.push(b'=');
            }
        }
        val.zeroize();
    }

    encoded
}

pub(crate) fn base64_decode(encoded: &[u8]) -> Result<Vec<u8>, Error> {
    let encoded = match encoded {
        [rest @ .., b'=', b'='] | [rest @ .., b'='] => rest,
        _ => encoded,
    };
    let mut decoded = Vec::new();
    let mut i = 0;
    while i < encoded.len() {
        let mut val: u32 = 0;
        let mut n = 0;
        while n < 4 && i < encoded.len() {
            let c = encoded[i];
            let idx = match c {
                b'A'..=b'Z' => c - b'A',
                b'a'..=b'z' => c - b'a' + 26,
                b'0'..=b'9' => c - b'0' + 52,
                b'+' => 62,
                b'/' => 63,
                _ => return Err(Error::DeserializationError),
            };
            val = (val << 6) | (idx as u32);
            n += 1;
            i += 1;
        }
        if n == 3 {
            val <<= 6;
        } else if n == 2 {
            val <<= 12;
        }
        for j in 0..3 {
            if j < n - 1 {
                decoded.push(((val >> ((2 - j) * 8)) & 0xFF) as u8);
            }
        }
        val.zeroize();
    }
    Ok(decoded)
}