refactor: use u64 instead of u8[8] buffer; allow user to override salt.

This commit is contained in:
Jixun Wu
2024-09-12 00:18:12 +01:00
parent 8fcc07199b
commit f592acb220
3 changed files with 59 additions and 38 deletions

View File

@@ -17,12 +17,13 @@ categories = ["cryptography"]
maintenance = { status = "as-is" }
[dependencies]
byteorder = "1.5.0"
thiserror = "1.0.63"
rand = { version = "0.8.5" }
rand = { version = "0.8.5", optional = true }
rand_chacha = { version = "0.3.1", optional = true }
rand_pcg = { version = "0.3.1", optional = true }
byteorder = "1.5.0"
[features]
default = ["rand_pcg"]
secure_random = ["rand/getrandom", "rand/rand_chacha", "rand_chacha"]
default = ["random", "random_secure"]
random = ["rand", "rand_pcg"]
random_secure = ["rand/getrandom", "rand/rand_chacha", "rand_chacha"]

View File

@@ -53,7 +53,7 @@ pub fn encrypt<'a>(
let copy_to_header_len = min(16 - header_len, plain.len());
let (plain_header, plain) = plain.split_at(copy_to_header_len);
header[0] = (header[0] & 0b1111_1000) | ((pad_len as u8) & 0b0000_0111);
header[0] = (header[0] & !7) | ((pad_len as u8) & 7);
header[header_len..header_len + copy_to_header_len].copy_from_slice(plain_header);
// Access to slice of "cipher" from inner scope

View File

@@ -3,13 +3,11 @@
//! Notably, it uses a different round number and uses a "tweaked" CBC mode.
use byteorder::{ByteOrder, BE};
use rand::RngCore;
use thiserror::Error;
pub mod cbc;
pub mod ecb;
mod ecb_impl;
use rand::prelude::*;
#[derive(Error, Debug, PartialEq)]
pub enum TcTeaError {
@@ -50,48 +48,70 @@ pub fn parse_key(key: &[u8]) -> Result<[u32; 4], TcTeaError> {
Ok(parsed)
}
/// Encrypts an arbitrary length sized data in the following way:
///
/// * PadLen (1 byte)
/// * Padding (variable, 0-7byte)
/// * Salt (2 bytes)
/// * Body (? bytes)
/// * Zero (7 bytes)
///
/// Returned bytes will always have a length multiple of 8.
///
/// PadLen/Padding/Salt are randomly bytes, with a minimum of 21 bits (3 * 8 - 3) randomness.
/// Generate salt for encryption function (or fixed salt if we are not using them)
fn generate_salt() -> [u8; 10] {
#[cfg(not(feature = "random"))]
{
// Chosen by fair dice roll.
// Guaranteed to be random.
[0xA5, 0x6E, 0x35, 0xBC, 0x7C, 0x31, 0x04, 0x55, 0xA0, 0xBF]
}
#[cfg(feature = "random")]
{
use rand::RngCore;
use rand::prelude::*;
let mut salt = [0u8; 10];
#[cfg(not(feature = "random_secure"))]
rand_pcg::Pcg32::from_entropy().fill_bytes(&mut salt);
#[cfg(feature = "random_secure")]
rand_chacha::ChaCha20Rng::from_entropy().fill_bytes(&mut salt);
salt
}
}
/// Encrypts given plain text using tc_tea.
///
/// # Panics
///
/// If random number generator fails, it will panic.
pub fn encrypt<T: AsRef<[u8]>>(plaintext: T, key: &[u8]) -> Result<Vec<u8>, TcTeaError> {
let key = parse_key(key)?;
pub fn encrypt<T, K>(plaintext: T, key: K) -> Result<Vec<u8>, TcTeaError>
where
T: AsRef<[u8]>,
K: AsRef<[u8]>,
{
encrypt_with_salt(plaintext, key, &generate_salt())
}
/// Encrypts given plain text using tc_tea.
///
/// # Panics
///
/// If random number generator fails, it will panic.
pub fn encrypt_with_salt<T, K>(plaintext: T, key: K, salt: &[u8; 10]) -> Result<Vec<u8>, TcTeaError>
where
T: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let key = parse_key(key.as_ref())?;
let plaintext = plaintext.as_ref();
let cipher_len = get_encrypted_size(plaintext.len());
let mut cipher = vec![0u8; cipher_len];
let mut salt = [0u8; 10];
#[cfg(feature = "secure_random")]
rand_chacha::ChaCha20Rng::from_entropy().fill_bytes(&mut salt);
#[cfg(not(feature = "secure_random"))]
rand_pcg::Pcg32::from_entropy().fill_bytes(&mut salt);
cbc::encrypt(&mut cipher, plaintext, &key, &salt)?;
Ok(cipher)
}
/// Decrypts a byte array containing the following:
///
/// * PadLen (1 byte)
/// * Padding (variable, 0-7byte)
/// * Salt (2 bytes)
/// * Body (? bytes)
/// * Zero (7 bytes)
///
/// PadLen is taken from the last 3 bit of the first byte.
pub fn decrypt<T: AsRef<[u8]>>(encrypted: T, key: &[u8]) -> Result<Vec<u8>, TcTeaError> {
let key = parse_key(key)?;
/// Decrypts tc_tea encrypted data.
pub fn decrypt<T, K>(encrypted: T, key: K) -> Result<Vec<u8>, TcTeaError>
where
T: AsRef<[u8]>,
K: AsRef<[u8]>,
{
let key = parse_key(key.as_ref())?;
let encrypted = encrypted.as_ref();
let mut plain = vec![0u8; encrypted.len()];
let result = cbc::decrypt(&mut plain, encrypted, &key)?;