Add Support for muisca paz archive

This commit is contained in:
2025-11-02 17:43:00 +08:00
parent fe31f5c595
commit 04f9b1469a
20 changed files with 903 additions and 29 deletions

View File

@@ -168,6 +168,7 @@ mod consts {
use anyhow::Result;
use byteorder::{BE, ByteOrder, LE};
use std::io::{Read, Seek};
use std::marker::PhantomData;
/// Blowfish variant which uses Little Endian byte order read/writes.s.
@@ -181,15 +182,9 @@ pub struct Blowfish<T: ByteOrder = BE> {
_pd: PhantomData<T>,
}
impl std::fmt::Debug for Blowfish<BE> {
impl<T: ByteOrder> std::fmt::Debug for Blowfish<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Blowfish<BE> { ... }")
}
}
impl std::fmt::Debug for Blowfish<LE> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Blowfish<LE> { ... }")
f.write_str("Blowfish { ... }")
}
}
@@ -290,3 +285,106 @@ impl<T: ByteOrder> Blowfish<T> {
Ok(blowfish)
}
}
#[derive(Debug)]
/// Blowfish decryption stream wrapper.
pub struct BlowfishDecryptor<B: ByteOrder, T> {
cipher: Blowfish<B>,
buffer: [u8; 8],
buffer_len: usize,
buffer_is_decrypted: bool,
stream: T,
}
impl<B: ByteOrder, T: std::io::Read> BlowfishDecryptor<B, T> {
pub fn new(cipher: Blowfish<B>, stream: T) -> Self {
Self {
cipher,
buffer: [0u8; 8],
buffer_len: 0,
buffer_is_decrypted: false,
stream,
}
}
pub fn new_with_key(key: &[u8], stream: T) -> Result<Self> {
let cipher = Blowfish::new(key)?;
Ok(Self::new(cipher, stream))
}
}
impl<B: ByteOrder, T: Read> Read for BlowfishDecryptor<B, T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.buffer_is_decrypted && self.buffer_len > 0 {
let to_copy = std::cmp::min(buf.len(), self.buffer_len);
buf[..to_copy].copy_from_slice(&self.buffer[..to_copy]);
if to_copy < self.buffer_len {
for i in 0..(self.buffer_len - to_copy) {
self.buffer[i] = self.buffer[to_copy + i];
}
}
self.buffer_len -= to_copy;
self.buffer_is_decrypted = self.buffer_len > 0;
return Ok(to_copy);
}
if buf.len() < 8 {
if self.buffer_len < 8 {
self.stream
.read_exact(&mut self.buffer[self.buffer_len..])?;
}
self.cipher.decrypt_block(&mut self.buffer);
self.buffer_len = 8;
self.buffer_is_decrypted = true;
let to_copy = std::cmp::min(buf.len(), self.buffer_len);
buf[..to_copy].copy_from_slice(&self.buffer[..to_copy]);
if to_copy < self.buffer_len {
for i in 0..(self.buffer_len - to_copy) {
self.buffer[i] = self.buffer[to_copy + i];
}
}
self.buffer_len -= to_copy;
self.buffer_is_decrypted = self.buffer_len > 0;
return Ok(to_copy);
}
let mut start_index = 0;
if self.buffer_len > 0 {
buf[..self.buffer_len].copy_from_slice(&self.buffer[..self.buffer_len]);
start_index += self.buffer_len;
}
let readed = self.stream.read(&mut buf[start_index..])?;
let total_readed = start_index + readed;
let total_decrypted = total_readed - (total_readed % 8);
self.cipher.decrypt_block(&mut buf[..total_decrypted]);
if total_readed != total_decrypted {
self.buffer_len = total_readed - total_decrypted;
self.buffer[..self.buffer_len].copy_from_slice(&buf[total_decrypted..total_readed]);
} else {
self.buffer_len = 0;
}
self.buffer_is_decrypted = false;
Ok(total_decrypted)
}
}
impl<T: Read + Seek, B: ByteOrder> Seek for BlowfishDecryptor<B, T> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
if matches!(pos, std::io::SeekFrom::End(0)) {
let newpos = self.stream.seek(pos)?;
self.buffer_len = 0;
self.buffer_is_decrypted = false;
return Ok(newpos);
}
let newpos = self.stream.seek(pos)?;
if newpos % 8 != 0 {
let block_start = newpos - (newpos % 8);
self.stream.seek(std::io::SeekFrom::Start(block_start))?;
self.buffer_len = (newpos - block_start) as usize;
self.stream
.read_exact(&mut self.buffer[..self.buffer_len])?;
} else {
self.buffer_len = 0;
}
self.buffer_is_decrypted = false;
Ok(newpos)
}
}

View File

@@ -25,10 +25,16 @@ pub mod name_replacement;
pub mod num_range;
#[cfg(feature = "utils-pcm")]
pub mod pcm;
#[cfg(feature = "utils-rc4")]
pub mod rc4;
#[cfg(feature = "utils-serde-base64bytes")]
pub mod serde_base64bytes;
#[cfg(feature = "utils-str")]
pub mod str;
pub mod struct_pack;
pub mod threadpool;
#[cfg(feature = "utils-xored-stream")]
pub mod xored_stream;
#[cfg(windows)]
pub use encoding_win::WinError;

87
src/utils/rc4.rs Normal file
View File

@@ -0,0 +1,87 @@
use std::io::{Read, Write};
pub struct Rc4 {
state: [u8; 256],
i: u8,
j: u8,
}
impl Rc4 {
pub fn new(key: &[u8]) -> Self {
let mut state = [0u8; 256];
for i in 0..256 {
state[i] = i as u8;
}
let mut j: u8 = 0;
for i in 0..256 {
j = j.wrapping_add(state[i]).wrapping_add(key[i % key.len()]);
state.swap(i, j as usize);
}
Rc4 { state, i: 0, j: 0 }
}
pub fn next_byte(&mut self) -> u8 {
self.i = self.i.wrapping_add(1);
self.j = self.j.wrapping_add(self.state[self.i as usize]);
self.state.swap(self.i as usize, self.j as usize);
let k = self.state
[(self.state[self.i as usize].wrapping_add(self.state[self.j as usize])) as usize];
k
}
pub fn skip_bytes(&mut self, n: usize) {
for _ in 0..n {
self.next_byte();
}
}
pub fn generate_block(&mut self, len: usize) -> Vec<u8> {
(0..len).map(|_| self.next_byte()).collect()
}
pub fn process_block(&mut self, data: &mut [u8]) {
for byte in data.iter_mut() {
*byte ^= self.next_byte();
}
}
}
pub struct Rc4Stream<T> {
inner: T,
rc4: Rc4,
}
impl<T> Rc4Stream<T> {
pub fn new(inner: T, rc4: Rc4) -> Self {
Rc4Stream { inner, rc4 }
}
pub fn new_with_key(inner: T, key: &[u8]) -> Self {
Rc4Stream {
inner,
rc4: Rc4::new(key),
}
}
}
impl<T: Read> Read for Rc4Stream<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let n = self.inner.read(buf)?;
self.rc4.process_block(&mut buf[..n]);
Ok(n)
}
}
impl<T: Write> Write for Rc4Stream<T> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut data = buf.to_vec();
self.rc4.process_block(&mut data);
self.inner.write(&data)
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}

View File

@@ -0,0 +1,45 @@
use base64::Engine;
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Base64Bytes {
pub bytes: Vec<u8>,
}
impl Deref for Base64Bytes {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
impl DerefMut for Base64Bytes {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.bytes
}
}
impl Serialize for Base64Bytes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let encoded = base64::engine::general_purpose::STANDARD.encode(&self.bytes);
serializer.serialize_str(&encoded)
}
}
impl<'de> Deserialize<'de> for Base64Bytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
let decoded = base64::engine::general_purpose::STANDARD
.decode(s)
.map_err(serde::de::Error::custom)?;
Ok(Base64Bytes { bytes: decoded })
}
}

59
src/utils/xored_stream.rs Normal file
View File

@@ -0,0 +1,59 @@
use std::io::{Read, Seek, Write};
pub struct XoredStream<T> {
reader: T,
key: u8,
}
impl<T> XoredStream<T> {
pub fn new(reader: T, key: u8) -> Self {
XoredStream { reader, key }
}
}
impl<T: Read> Read for XoredStream<T> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let read_bytes = self.reader.read(buf)?;
for byte in &mut buf[..read_bytes] {
*byte ^= self.key;
}
Ok(read_bytes)
}
}
impl<T: Seek> Seek for XoredStream<T> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.reader.seek(pos)
}
fn rewind(&mut self) -> std::io::Result<()> {
self.reader.rewind()
}
fn stream_position(&mut self) -> std::io::Result<u64> {
self.reader.stream_position()
}
}
impl<T: Write> Write for XoredStream<T> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut encrypted_buf = buf.to_vec();
for byte in &mut encrypted_buf {
*byte ^= self.key;
}
self.reader.write(&encrypted_buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.reader.flush()
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for XoredStream<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("XoredStream")
.field("reader", &self.reader)
.field("key", &self.key)
.finish()
}
}