init
This commit is contained in:
commit
1352ef8ec8
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
23
Cargo.lock
generated
Normal file
23
Cargo.lock
generated
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reuqm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"base64",
|
||||||
|
]
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "reuqm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.86"
|
||||||
|
base64 = "0.22.1"
|
93
src/decrypto/cipher.rs
Normal file
93
src/decrypto/cipher.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use std::cmp::min;
|
||||||
|
|
||||||
|
use crate::{decrypto::rc4, key::read_key};
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
|
||||||
|
const FIRST_SEGMENT_SIZE: usize = 128;
|
||||||
|
const OTHER_SEGMENT_SIZE: usize = 5120;
|
||||||
|
|
||||||
|
pub struct Cipher {
|
||||||
|
hash: f64,
|
||||||
|
key: Vec<u8>,
|
||||||
|
key_stream: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cipher {
|
||||||
|
pub fn new(raw_key: &str) -> Result<Self, Error> {
|
||||||
|
let key = read_key(raw_key)?;
|
||||||
|
let key_stream = rc4::new(&key);
|
||||||
|
let hash = hash(&key);
|
||||||
|
Ok(Self {
|
||||||
|
hash,
|
||||||
|
key,
|
||||||
|
key_stream,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn decrypt(&mut self, mut offset: usize, mut buffer: &mut [u8]) {
|
||||||
|
if offset < FIRST_SEGMENT_SIZE {
|
||||||
|
let n = min(FIRST_SEGMENT_SIZE - offset, buffer.len());
|
||||||
|
let (block, rest) = buffer.split_at_mut(n);
|
||||||
|
buffer = rest;
|
||||||
|
self.decrypt_first_block(offset, block);
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
match offset % OTHER_SEGMENT_SIZE {
|
||||||
|
0 => {}
|
||||||
|
excess => {
|
||||||
|
let n = min(OTHER_SEGMENT_SIZE - excess, buffer.len());
|
||||||
|
let (block, rest) = buffer.split_at_mut(n);
|
||||||
|
buffer = rest;
|
||||||
|
self.decrypt_other_block(offset, block);
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while !buffer.is_empty() {
|
||||||
|
let n: usize = min(OTHER_SEGMENT_SIZE, buffer.len());
|
||||||
|
let (block, rest) = buffer.split_at_mut(n);
|
||||||
|
buffer = rest;
|
||||||
|
self.decrypt_other_block(offset, block);
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn decrypt_first_block(&mut self, offset: usize, dst: &mut [u8]) {
|
||||||
|
let n = self.key.len();
|
||||||
|
|
||||||
|
for (value, offset) in dst.iter_mut().zip(offset..) {
|
||||||
|
*value ^= self.key[idx(offset as u64, self.key[offset % n], self.hash) as usize % n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn decrypt_other_block(&mut self, offset: usize, dst: &mut [u8]) {
|
||||||
|
let n = self.key.len();
|
||||||
|
let id = offset / OTHER_SEGMENT_SIZE;
|
||||||
|
let block_offset = offset % OTHER_SEGMENT_SIZE;
|
||||||
|
let seed = self.key[id % n];
|
||||||
|
let skip = idx(id as u64, seed, self.hash) % 512;
|
||||||
|
let key_stream = self.key_stream.iter().skip(skip as usize + block_offset);
|
||||||
|
for (datum, &key) in dst.iter_mut().zip(key_stream) {
|
||||||
|
*datum ^= key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(key: &Vec<u8>) -> f64 {
|
||||||
|
let mut hash = 1u32;
|
||||||
|
for v in key.iter() {
|
||||||
|
if *v == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let next_hash = hash.wrapping_mul(*v as u32);
|
||||||
|
if next_hash == 0 || next_hash <= hash {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hash = next_hash;
|
||||||
|
}
|
||||||
|
hash.into()
|
||||||
|
}
|
||||||
|
fn idx(id: u64, seed: u8, hash: f64) -> u32 {
|
||||||
|
match seed {
|
||||||
|
0 => 0,
|
||||||
|
seed => (hash / ((id + 1).wrapping_mul(seed.into()) as f64) * 100.0) as u32,
|
||||||
|
}
|
||||||
|
}
|
2
src/decrypto/mod.rs
Normal file
2
src/decrypto/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod cipher;
|
||||||
|
mod rc4;
|
62
src/decrypto/rc4.rs
Normal file
62
src/decrypto/rc4.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
pub fn new(key: &Vec<u8>) -> Vec<u8> {
|
||||||
|
let key_lenght = key.len();
|
||||||
|
// init
|
||||||
|
let mut s_box = Vec::new();
|
||||||
|
let mut t_box = Vec::new();
|
||||||
|
for i in 0..key_lenght {
|
||||||
|
s_box.push(i as u8);
|
||||||
|
t_box.push(key[i % key_lenght]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// init S box
|
||||||
|
let mut j = 0;
|
||||||
|
for i in 0..key_lenght {
|
||||||
|
j = (j + s_box[i] as usize + t_box[i] as usize) % 512;
|
||||||
|
s_box.swap(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
let mut j = 0;
|
||||||
|
let mut ks = Vec::new();
|
||||||
|
for _ in 0..(5120 + 512) {
|
||||||
|
i = (i + 1) % key_lenght;
|
||||||
|
j = (j + s_box[i] as usize) % key_lenght;
|
||||||
|
s_box.swap(i, j);
|
||||||
|
let t = (s_box[i] as usize + s_box[j] as usize) % key_lenght;
|
||||||
|
ks.push(0 ^ s_box[t]);
|
||||||
|
}
|
||||||
|
ks
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let k = vec![
|
||||||
|
102, 121, 54, 88, 65, 52, 108, 55, 49, 87, 86, 79, 104, 83, 52, 106, 107, 50, 113, 54, 83,
|
||||||
|
82, 100, 99, 56, 103, 112, 78, 51, 56, 52, 112, 77, 53, 57, 56, 119, 49, 99, 117, 51, 76,
|
||||||
|
120, 121, 49, 109, 83, 73, 49, 74, 56, 52, 55, 110, 99, 98, 77, 114, 112, 90, 72, 65, 82,
|
||||||
|
48, 53, 50, 68, 48, 49, 108, 114, 97, 67, 82, 73, 83, 103, 116, 101, 53, 120, 121, 81, 73,
|
||||||
|
89, 76, 53, 88, 100, 53, 53, 100, 116, 111, 97, 83, 119, 51, 104, 109, 48, 55, 75, 102,
|
||||||
|
110, 66, 110, 76, 53, 49, 97, 102, 112, 76, 115, 104, 56, 113, 57, 89, 74, 81, 57, 103, 99,
|
||||||
|
55, 77, 99, 51, 68, 50, 72, 48, 51, 86, 114, 121, 100, 75, 87, 66, 48, 54, 116, 107, 118,
|
||||||
|
105, 76, 67, 65, 51, 68, 68, 51, 56, 103, 49, 52, 89, 87, 54, 76, 52, 81, 104, 66, 79, 52,
|
||||||
|
112, 75, 49, 73, 114, 98, 68, 67, 84, 50, 50, 87, 74, 76, 104, 57, 102, 52, 119, 109, 116,
|
||||||
|
51, 75, 71, 56, 65, 86, 80, 52, 53, 100, 71, 101, 69, 113, 81, 49, 75, 77, 54, 120, 102,
|
||||||
|
85, 89, 121, 65, 101, 79, 101, 76, 74, 104, 99, 49, 75, 102, 55, 98, 55, 48, 71, 110, 98,
|
||||||
|
48, 120, 57, 78, 120, 68, 73, 49, 52, 55, 103, 99, 89, 112, 97, 57, 88, 72, 51, 48, 75, 70,
|
||||||
|
72, 106, 122, 72, 98, 100, 48, 113, 77, 56, 50, 108, 50, 65, 113, 69, 88, 102, 99, 70, 49,
|
||||||
|
103, 54, 50, 103, 98, 90, 50, 112, 75, 116, 57, 103, 80, 97, 55, 54, 118, 57, 101, 57, 57,
|
||||||
|
88, 57, 48, 49, 54, 115, 56, 52, 53, 79, 87, 66, 102, 116, 111, 54, 89, 51, 122, 102, 53,
|
||||||
|
116, 50, 101, 56, 101, 102, 83, 111, 74, 81, 110, 50, 85, 56, 55, 51, 84, 81, 54, 51, 86,
|
||||||
|
82, 51, 50, 72, 120, 56, 54, 115, 56, 117, 87, 122, 79, 56, 56, 105, 83, 53, 54, 82, 82,
|
||||||
|
50, 103, 81, 119, 99, 56, 103, 54, 97, 83, 54, 107, 52, 102, 105, 68, 54, 108, 99, 66, 99,
|
||||||
|
70, 122, 97, 101, 109, 72, 53, 105, 88, 55, 55, 111, 73, 50, 88, 114, 103, 82, 50, 99, 99,
|
||||||
|
48, 57, 113, 106, 100, 72, 107, 109, 100, 54, 84, 51, 79, 106, 86, 97, 102, 118, 105, 76,
|
||||||
|
56, 104, 107, 56, 53, 79, 67, 75, 50, 103, 53, 56, 112, 111, 117, 108, 54, 98, 110, 119,
|
||||||
|
118, 118, 49, 80, 69, 119, 102, 101, 56, 51, 116, 71, 48, 86, 106, 104, 103, 71, 77, 72,
|
||||||
|
52, 54, 117, 88, 67, 54, 86, 55, 48, 102, 67, 51, 49, 74, 57, 52, 119, 56, 54, 111, 119,
|
||||||
|
108, 48, 79, 55, 72, 73, 57, 49, 72, 51, 81, 70, 74, 99, 55, 78, 53, 82, 84, 103, 52, 50,
|
||||||
|
115, 112, 54, 54, 50, 52, 65, 114, 122,
|
||||||
|
];
|
||||||
|
let rs4 = new(&k);
|
||||||
|
println!("{:?}", rs4);
|
||||||
|
}
|
91
src/key/mod.rs
Normal file
91
src/key/mod.rs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
mod tea;
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
use base64::prelude::{Engine, BASE64_STANDARD as base64};
|
||||||
|
|
||||||
|
pub fn read_key(raw_key: &str) -> Result<Vec<u8>> {
|
||||||
|
let base64_key = match base64.decode(raw_key) {
|
||||||
|
Ok(k) => k,
|
||||||
|
Err(err) => {
|
||||||
|
return Err(Error::msg(format!(
|
||||||
|
"use base64 decode raw key Failed,{err}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let simple_key: [u8; 8] = [105, 86, 70, 56, 43, 32, 21, 11];
|
||||||
|
let mut tea_key = vec![0; 16];
|
||||||
|
for i in 0..8 {
|
||||||
|
tea_key[i << 1] = simple_key[i];
|
||||||
|
tea_key[(i << 1) + 1] = base64_key[i];
|
||||||
|
}
|
||||||
|
let mut rs = decrypt_tencent_tea(base64_key[8..].to_owned(), tea_key)?;
|
||||||
|
let mut dkv1 = base64_key[..8].to_owned();
|
||||||
|
dkv1.append(&mut rs);
|
||||||
|
Ok(dkv1.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt_tencent_tea(in_buf: Vec<u8>, key: Vec<u8>) -> Result<Vec<u8>, Error> {
|
||||||
|
const SALTLEN: usize = 2;
|
||||||
|
const ZEROEN: usize = 7;
|
||||||
|
if in_buf.len() % 8 != 0 {
|
||||||
|
return Err(Error::msg("inBuf size not a multiple of the block size"));
|
||||||
|
}
|
||||||
|
if in_buf.len() < 16 {
|
||||||
|
return Err(Error::msg("inBuf size too small"));
|
||||||
|
}
|
||||||
|
let key = key[0..16].try_into().unwrap();
|
||||||
|
let blk = tea::Tea::new(key, 32);
|
||||||
|
let mut dst = blk.decrypt(in_buf[0..8].to_owned());
|
||||||
|
|
||||||
|
let pad_len = &dst[0] & 0x7;
|
||||||
|
let out_len = in_buf.len() - 1 - pad_len as usize - SALTLEN - ZEROEN;
|
||||||
|
let mut out = vec![0; out_len];
|
||||||
|
let mut iv_prev = vec![0; 8];
|
||||||
|
let mut iv_cur = in_buf[0..8].to_owned();
|
||||||
|
let mut in_buf_pos = 8;
|
||||||
|
let mut dst_idx = 1 + pad_len;
|
||||||
|
let mut i = 1;
|
||||||
|
while i <= SALTLEN {
|
||||||
|
if dst_idx < 8 {
|
||||||
|
dst_idx += 1;
|
||||||
|
i += 1;
|
||||||
|
} else if dst_idx == 8 {
|
||||||
|
iv_prev = iv_cur.clone()[0..8].to_owned();
|
||||||
|
iv_cur = in_buf[in_buf_pos..(in_buf_pos + 8)].to_owned();
|
||||||
|
dst = xor_8bytes(dst.clone(), in_buf[in_buf_pos..(in_buf_pos + 8)].to_owned());
|
||||||
|
dst = blk.decrypt(dst.clone());
|
||||||
|
in_buf_pos += 8;
|
||||||
|
dst_idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut out_pos = 0;
|
||||||
|
while out_pos < out_len {
|
||||||
|
if dst_idx < 8 {
|
||||||
|
out[out_pos] = dst[dst_idx as usize] ^ iv_prev[dst_idx as usize];
|
||||||
|
dst_idx += 1;
|
||||||
|
out_pos += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iv_prev = iv_cur.clone()[0..8].to_owned();
|
||||||
|
iv_cur = in_buf[in_buf_pos..(in_buf_pos + 8)].to_owned();
|
||||||
|
dst = xor_8bytes(dst.clone(), in_buf[in_buf_pos..(in_buf_pos + 8)].to_owned());
|
||||||
|
dst = blk.decrypt(dst.clone());
|
||||||
|
in_buf_pos += 8;
|
||||||
|
dst_idx = 0;
|
||||||
|
}
|
||||||
|
let mut i = 1;
|
||||||
|
while i <= ZEROEN {
|
||||||
|
i += 1;
|
||||||
|
if dst[dst_idx as usize] != iv_prev[dst_idx as usize] {
|
||||||
|
return Err(Error::msg("zero check failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
pub fn xor_8bytes(a: Vec<u8>, b: Vec<u8>) -> Vec<u8> {
|
||||||
|
let mut dst = vec![0; 8];
|
||||||
|
for i in 0..8 {
|
||||||
|
dst[i] = a[i] ^ b[i];
|
||||||
|
}
|
||||||
|
dst
|
||||||
|
}
|
51
src/key/tea.rs
Normal file
51
src/key/tea.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
pub struct Tea {
|
||||||
|
key: [u32; 4],
|
||||||
|
rounds: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tea {
|
||||||
|
pub fn new(key: [u8; 16], rounds: u32) -> Self {
|
||||||
|
let key = [
|
||||||
|
u32::from_be_bytes(key[0..4].try_into().unwrap()),
|
||||||
|
u32::from_be_bytes(key[4..8].try_into().unwrap()),
|
||||||
|
u32::from_be_bytes(key[8..12].try_into().unwrap()),
|
||||||
|
u32::from_be_bytes(key[12..16].try_into().unwrap()),
|
||||||
|
];
|
||||||
|
Self { key, rounds }
|
||||||
|
}
|
||||||
|
pub fn decrypt(&self, bl: Vec<u8>) -> Vec<u8> {
|
||||||
|
let delta = 0x9E3779b9;
|
||||||
|
let decrypto = |v: [u32; 2], k: [u32; 4]| -> (u32, u32) {
|
||||||
|
let mut sum: u32 = (self.rounds / 2).wrapping_mul(delta);
|
||||||
|
let mut v0 = v[0];
|
||||||
|
let mut v1 = v[1];
|
||||||
|
for _ in 0..(self.rounds / 2) {
|
||||||
|
v1 = v1.wrapping_sub(
|
||||||
|
((v0 << 4).wrapping_add(k[2]))
|
||||||
|
^ (v0.wrapping_add(sum))
|
||||||
|
^ ((v0 >> 5).wrapping_add(k[3])),
|
||||||
|
);
|
||||||
|
v0 = v0.wrapping_sub(
|
||||||
|
((v1 << 4).wrapping_add(k[0]))
|
||||||
|
^ (v1.wrapping_add(sum))
|
||||||
|
^ ((v1 >> 5).wrapping_add(k[1])),
|
||||||
|
);
|
||||||
|
sum = sum.wrapping_sub(delta);
|
||||||
|
}
|
||||||
|
(v0, v1)
|
||||||
|
};
|
||||||
|
let v0 = u32::from_be_bytes(bl[0..4].try_into().unwrap());
|
||||||
|
let v1 = u32::from_be_bytes(bl[4..8].try_into().unwrap());
|
||||||
|
let (v0, v1) = decrypto([v0, v1], self.key);
|
||||||
|
[v0.to_be_bytes(), v1.to_be_bytes()].concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let v: [u8; 16] = [
|
||||||
|
33, 14, 26, 47, 81, 10, 19, 22, 47, 35, 88, 21, 45, 23, 44, 55,
|
||||||
|
];
|
||||||
|
let k1 = u32::from_be_bytes(v[0..4].try_into().unwrap());
|
||||||
|
assert_eq!(k1, 554572335);
|
||||||
|
}
|
10
src/lib.rs
Normal file
10
src/lib.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
pub mod decrypto;
|
||||||
|
mod key;
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
|
||||||
|
pub fn decrypt(filename: &str, raw_key: &str) -> Result<Vec<u8>, Error> {
|
||||||
|
let mut audio = std::fs::read(filename)?;
|
||||||
|
let mut cipher = decrypto::cipher::Cipher::new(raw_key)?;
|
||||||
|
cipher.decrypt(0, &mut audio);
|
||||||
|
Ok(audio)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user