mirror of
https://git.um-react.app/um/lib_um_crypto_rust.git
synced 2026-03-08 04:29:54 +00:00
qmc: remove use of anyhow
This commit is contained in:
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -316,6 +316,15 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.76"
|
version = "0.3.76"
|
||||||
@@ -577,7 +586,7 @@ version = "0.1.9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"itertools",
|
"itertools 0.13.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"umc_qmc",
|
"umc_qmc",
|
||||||
"umc_utils",
|
"umc_utils",
|
||||||
@@ -600,7 +609,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"cipher",
|
"cipher",
|
||||||
"crc",
|
"crc",
|
||||||
"itertools",
|
"itertools 0.13.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"umc_utils",
|
"umc_utils",
|
||||||
]
|
]
|
||||||
@@ -609,9 +618,8 @@ dependencies = [
|
|||||||
name = "umc_qmc"
|
name = "umc_qmc"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"itertools",
|
"itertools 0.14.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"tc_tea",
|
"tc_tea",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -624,7 +632,7 @@ version = "0.1.9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"hex",
|
"hex",
|
||||||
"itertools",
|
"itertools 0.13.0",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"umc_qmc",
|
"umc_qmc",
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ version = "0.1.9"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.86"
|
|
||||||
byteorder = "1.5.0"
|
byteorder = "1.5.0"
|
||||||
itertools = "0.13.0"
|
itertools = "0.14"
|
||||||
lazy_static = "1.5.0"
|
lazy_static = "1.5.0"
|
||||||
tc_tea = { version = "0.2.1", default-features = false }
|
tc_tea = { version = "0.2.1", default-features = false }
|
||||||
thiserror = "2.0.7"
|
thiserror = "2.0.7"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
@@ -27,6 +26,8 @@ pub enum EKeyDecryptError {
|
|||||||
FailDecryptV1(TcTeaError),
|
FailDecryptV1(TcTeaError),
|
||||||
#[error("Error when decrypting ekey v2: {0}")]
|
#[error("Error when decrypting ekey v2: {0}")]
|
||||||
FailDecryptV2(TcTeaError),
|
FailDecryptV2(TcTeaError),
|
||||||
|
#[error("Failed to decode b64 content: {0}")]
|
||||||
|
Base64Decode(#[from] base64::DecodeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_simple_key<const N: usize>() -> [u8; N] {
|
fn make_simple_key<const N: usize>() -> [u8; N] {
|
||||||
@@ -42,7 +43,7 @@ fn make_simple_key<const N: usize>() -> [u8; N] {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt_v1(ekey: &[u8]) -> Result<Vec<u8>> {
|
pub fn decrypt_v1(ekey: &[u8]) -> Result<Vec<u8>, EKeyDecryptError> {
|
||||||
if ekey.len() < 12 {
|
if ekey.len() < 12 {
|
||||||
Err(EKeyDecryptError::EKeyTooShort)?;
|
Err(EKeyDecryptError::EKeyTooShort)?;
|
||||||
}
|
}
|
||||||
@@ -61,7 +62,7 @@ pub fn decrypt_v1(ekey: &[u8]) -> Result<Vec<u8>> {
|
|||||||
Ok([header, &plaintext].concat())
|
Ok([header, &plaintext].concat())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt_v2(ekey: &[u8]) -> Result<Vec<u8>> {
|
pub fn decrypt_v2(ekey: &[u8]) -> Result<Vec<u8>, EKeyDecryptError> {
|
||||||
let ekey = base64::decode(ekey)?;
|
let ekey = base64::decode(ekey)?;
|
||||||
let ekey = tc_tea::decrypt(ekey, EKEY_V2_KEY1).map_err(EKeyDecryptError::FailDecryptV2)?;
|
let ekey = tc_tea::decrypt(ekey, EKEY_V2_KEY1).map_err(EKeyDecryptError::FailDecryptV2)?;
|
||||||
let ekey = tc_tea::decrypt(ekey, EKEY_V2_KEY2).map_err(EKeyDecryptError::FailDecryptV2)?;
|
let ekey = tc_tea::decrypt(ekey, EKEY_V2_KEY2).map_err(EKeyDecryptError::FailDecryptV2)?;
|
||||||
@@ -70,7 +71,7 @@ pub fn decrypt_v2(ekey: &[u8]) -> Result<Vec<u8>> {
|
|||||||
decrypt_v1(&ekey)
|
decrypt_v1(&ekey)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt<T: AsRef<[u8]>>(ekey: T) -> Result<Vec<u8>> {
|
pub fn decrypt<T: AsRef<[u8]>>(ekey: T) -> Result<Vec<u8>, EKeyDecryptError> {
|
||||||
let ekey = ekey.as_ref();
|
let ekey = ekey.as_ref();
|
||||||
match ekey.strip_prefix(EKEY_V2_PREFIX) {
|
match ekey.strip_prefix(EKEY_V2_PREFIX) {
|
||||||
Some(v2_ekey) => decrypt_v2(v2_ekey),
|
Some(v2_ekey) => decrypt_v2(v2_ekey),
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ pub enum FooterParseError {
|
|||||||
PCv2InvalidVersion(u32),
|
PCv2InvalidVersion(u32),
|
||||||
#[error("PCv2/MusicEx: Invalid `MusicEx` size: {0}")]
|
#[error("PCv2/MusicEx: Invalid `MusicEx` size: {0}")]
|
||||||
PCv2MusicExUnsupportedPayloadSize(usize),
|
PCv2MusicExUnsupportedPayloadSize(usize),
|
||||||
#[error("PCv2/MusicEx: Invalid `MusicEx` data: {0}")]
|
|
||||||
PCv2MusicExInvalidError(anyhow::Error),
|
|
||||||
|
|
||||||
#[error("Android/STag: Invalid ID field: {0}")]
|
#[error("Android/STag: Invalid ID field: {0}")]
|
||||||
STagInvalidId(String),
|
STagInvalidId(String),
|
||||||
@@ -45,6 +43,9 @@ pub enum FooterParseError {
|
|||||||
|
|
||||||
#[error("Parse: Failed to parse string '{0}' as integer")]
|
#[error("Parse: Failed to parse string '{0}' as integer")]
|
||||||
StringToIntError(String),
|
StringToIntError(String),
|
||||||
|
|
||||||
|
#[error("Failed to parse MusicExV1: {0}")]
|
||||||
|
MusicEx1ParseError(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Footer type
|
/// Footer type
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ impl Default for MusicExV1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MusicExV1 {
|
impl MusicExV1 {
|
||||||
pub fn from_bytes(buffer: &[u8]) -> anyhow::Result<MusicExV1> {
|
#[allow(clippy::field_reassign_with_default)]
|
||||||
|
fn from_bytes_inner(buffer: &[u8]) -> Result<MusicExV1, std::io::Error> {
|
||||||
assert_eq!(buffer.len(), 0xC0 - 0x10);
|
assert_eq!(buffer.len(), 0xC0 - 0x10);
|
||||||
|
|
||||||
let mut cursor = Cursor::new(&buffer);
|
let mut cursor = Cursor::new(&buffer);
|
||||||
@@ -50,11 +51,15 @@ impl MusicExV1 {
|
|||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(buffer: &[u8]) -> Result<MusicExV1, FooterParseError> {
|
||||||
|
Self::from_bytes_inner(buffer).map_err(FooterParseError::MusicEx1ParseError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_v1(footer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
|
pub fn parse_v1(footer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
|
||||||
let (payload, payload_len) = footer.split_at(footer.len() - 4);
|
let (payload, payload_len) = footer.split_at(footer.len() - 4);
|
||||||
let payload_len = LE::read_u32(&payload_len) as usize;
|
let payload_len = LE::read_u32(payload_len) as usize;
|
||||||
if payload_len != 0xC0 {
|
if payload_len != 0xC0 {
|
||||||
Err(FooterParseError::PCv2MusicExUnsupportedPayloadSize(
|
Err(FooterParseError::PCv2MusicExUnsupportedPayloadSize(
|
||||||
payload_len,
|
payload_len,
|
||||||
@@ -62,8 +67,7 @@ pub fn parse_v1(footer: &[u8]) -> Result<Option<Metadata>, FooterParseError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let payload = &payload[payload.len() - (payload_len - 0x10)..];
|
let payload = &payload[payload.len() - (payload_len - 0x10)..];
|
||||||
let payload =
|
let payload = MusicExV1::from_bytes(payload)?;
|
||||||
MusicExV1::from_bytes(payload).map_err(FooterParseError::PCv2MusicExInvalidError)?;
|
|
||||||
let mid = from_ascii_utf16(&payload.mid);
|
let mid = from_ascii_utf16(&payload.mid);
|
||||||
let media_filename = from_ascii_utf16(&payload.media_filename);
|
let media_filename = from_ascii_utf16(&payload.media_filename);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::v2_map::QMC2Map;
|
use crate::v2_map::QMC2Map;
|
||||||
use crate::v2_rc4::cipher::QMC2RC4;
|
use crate::v2_rc4::cipher::QMC2RC4;
|
||||||
use anyhow::Result;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub mod ekey;
|
pub mod ekey;
|
||||||
@@ -13,6 +12,9 @@ pub mod v2_rc4;
|
|||||||
pub enum QmcCryptoError {
|
pub enum QmcCryptoError {
|
||||||
#[error("QMC V2/Map Cipher: Key is empty")]
|
#[error("QMC V2/Map Cipher: Key is empty")]
|
||||||
QMCV2MapKeyEmpty,
|
QMCV2MapKeyEmpty,
|
||||||
|
|
||||||
|
#[error("EKey: {0}")]
|
||||||
|
EKeyParseError(#[from] ekey::EKeyDecryptError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@@ -22,7 +24,7 @@ pub enum QMCv2Cipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl QMCv2Cipher {
|
impl QMCv2Cipher {
|
||||||
pub fn new<T>(key: T) -> Result<Self>
|
pub fn new<T>(key: T) -> Result<Self, QmcCryptoError>
|
||||||
where
|
where
|
||||||
T: AsRef<[u8]>,
|
T: AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
@@ -35,7 +37,7 @@ impl QMCv2Cipher {
|
|||||||
Ok(cipher)
|
Ok(cipher)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_ekey<T: AsRef<[u8]>>(ekey_str: T) -> Result<Self> {
|
pub fn new_from_ekey<T: AsRef<[u8]>>(ekey_str: T) -> Result<Self, QmcCryptoError> {
|
||||||
let key = ekey::decrypt(ekey_str)?;
|
let key = ekey::decrypt(ekey_str)?;
|
||||||
Self::new(key)
|
Self::new(key)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::QmcCryptoError;
|
|||||||
|
|
||||||
const INDEX_OFFSET: usize = 71214;
|
const INDEX_OFFSET: usize = 71214;
|
||||||
|
|
||||||
pub fn key_compress<T: AsRef<[u8]>>(long_key: T) -> anyhow::Result<[u8; V1_KEY_SIZE]> {
|
pub fn key_compress<T: AsRef<[u8]>>(long_key: T) -> Result<[u8; V1_KEY_SIZE], QmcCryptoError> {
|
||||||
let long_key = long_key.as_ref();
|
let long_key = long_key.as_ref();
|
||||||
if long_key.is_empty() {
|
if long_key.is_empty() {
|
||||||
Err(QmcCryptoError::QMCV2MapKeyEmpty)?;
|
Err(QmcCryptoError::QMCV2MapKeyEmpty)?;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ mod key;
|
|||||||
|
|
||||||
use crate::v1::cipher::{qmc1_transform, V1_KEY_SIZE};
|
use crate::v1::cipher::{qmc1_transform, V1_KEY_SIZE};
|
||||||
use crate::v2_map::key::key_compress;
|
use crate::v2_map::key::key_compress;
|
||||||
use anyhow::Result;
|
use crate::QmcCryptoError;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct QMC2Map {
|
pub struct QMC2Map {
|
||||||
@@ -10,7 +10,7 @@ pub struct QMC2Map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl QMC2Map {
|
impl QMC2Map {
|
||||||
pub fn new<T: AsRef<[u8]>>(key: T) -> Result<Self> {
|
pub fn new<T: AsRef<[u8]>>(key: T) -> Result<Self, QmcCryptoError> {
|
||||||
let key = key_compress(key)?;
|
let key = key_compress(key)?;
|
||||||
Ok(Self { key })
|
Ok(Self { key })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user