mirror of
https://github.com/jixunmoe/tc_tea_rust
synced 2026-03-07 20:19:49 +00:00
refactor: use u64 instead of u8[8] buffer; allow user to override salt.
This commit is contained in:
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
86
src/lib.rs
86
src/lib.rs
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user