Skip to content

Commit

Permalink
security: use stronger AES-256, HKDF-SHA256 crypto for time sanitization
Browse files Browse the repository at this point in the history
This scheme is also more closer to standard cryptosystem designs
documented in IETF RFCs and the like. Limiting ourselves to a single
system ID that we directly use as a key after a reversible
transformation is unnecessarily risky.
  • Loading branch information
AlexTMjugador committed Dec 18, 2024
1 parent ec4472c commit b86db81
Show file tree
Hide file tree
Showing 10 changed files with 406 additions and 285 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,21 @@ Versioning](https://semver.org/spec/v2.0.0.html).
aware of the context in which they appear to suggest likely helpful corrective
actions.

#### Security

- PackSquash now sanitizes file modification times for storage as Squash Times
in the generated ZIP files with a stronger AES-256 encryption algorithm.
- The encryption key length has been increased from 128 bits to 256 bits. This
key is now derived using the HKDF-SHA256 algorithm applied to all collected
non-volatile system IDs, unless a specific system ID is set via the
`PACKSQUASH_SYSTEM_ID` environment variable. If only volatile system IDs are
available, the key is derived from those instead. This updated scheme aligns
more closely with documented modern best practices for entropy-based key
derivation.
- On Linux targets, DMI product UUIDs and serial numbers are now included in the
candidate system IDs, potentially bringing the entropy of the derived
encryption keys to parity with Windows.

### Removed

#### Internal
Expand Down
66 changes: 59 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/packsquash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ edition.workspace = true

[dependencies]
bytes = "1.9.0"
bytemuck = "1.20.0"
globset = { version = "0.4.15", default-features = false }
enumset = { version = "1.1.5", features = ["serde"] }
indexmap = { version = "2.7.0", features = ["serde"] }
itertools = "0.13.0"
thiserror = "2.0.6"
ahash = "0.8.11"
patricia_tree = "0.8.0"
tinyvec = "1.8.0"

sysinfo = { version = "0.33.0", default-features = false, features = [
"system",
Expand Down Expand Up @@ -82,9 +84,10 @@ zopfli = { version = "0.8.1", default-features = false, features = [

obfstr = "0.4.4"
aes = "0.8.4"
hkdf = "0.12.4"
sha2 = "0.10.8"
fpe = "0.6.1"
uuid = "1.11.0"
entropy = "0.4.2"
rand_xoshiro = "0.6.0"
regex = "1.11.1"
aho-corasick = "1.1.3"
Expand Down
28 changes: 15 additions & 13 deletions packages/packsquash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
#![feature(if_let_guard)]
#![feature(impl_trait_in_assoc_type)]
#![feature(generic_const_exprs)]
#![feature(lazy_get)]

use itertools::Itertools;
use std::borrow::Cow;
use std::convert::Infallible;
use std::io::ErrorKind;
use std::panic;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, LazyLock};
use std::{io, time::SystemTime};

use enumset::EnumSet;
Expand Down Expand Up @@ -42,8 +43,8 @@ use crate::pack_file::PackFileProcessData;
use crate::pack_file::asset_type::{
PackFileAssetTypeMatcher, PackFileAssetTypeMatches, tweak_asset_types_mask_from_global_options
};
use crate::squash_zip::PreviousZipParseError;
pub use crate::squash_zip::relative_path::RelativePath;
use crate::squash_zip::{PreviousZipParseError, system_id};
use crate::vfs::{IteratorTraversalOptions, VfsPackFileIterEntry, VirtualFileSystem};

pub mod config;
Expand Down Expand Up @@ -527,18 +528,19 @@ impl PackSquasher {

// Finally, send warnings about relevant conditions
if let Some(tx) = pack_file_status_sender {
if let Some(system_id) = system_id::get_system_id() {
if system_id.has_low_entropy {
if let Some(system_time_sanitizer) = LazyLock::get(&squash_zip::SYSTEM_TIME_SANITIZER)
{
if system_time_sanitizer.using_predictable_key() {
tx.send(PackSquasherStatus::Warning(
PackSquasherWarning::LowEntropySystemId
PackSquasherWarning::PredictableSystemTimeSanitizationKey
))
.await
.ok();
}

if system_id.is_volatile {
if system_time_sanitizer.using_volatile_key() {
tx.send(PackSquasherStatus::Warning(
PackSquasherWarning::VolatileSystemId
PackSquasherWarning::VolatileSystemTimeSanitizationKey
))
.await
.ok();
Expand Down Expand Up @@ -599,12 +601,12 @@ pub enum PackSquasherWarning {
/// are usually caused due to the system identifier changing, a previously
/// failed optimization process, or using different PackSquash versions.
UnusablePreviousZip(PreviousZipParseError),
/// A system identifier with low entropy was used to encrypt data, which
/// may render that data easier to decrypt.
LowEntropySystemId,
/// A system identifier that may change even if no targeted action by the
/// user to explicitly change it was done was used.
VolatileSystemId,
/// A predictable key was used to encrypt system time data, which can render
/// that data easier to decrypt.
PredictableSystemTimeSanitizationKey,
/// The key used to encrypt system time data may change in the future even if
/// no targeted action by the user to explicitly change it is done.
VolatileSystemTimeSanitizationKey,
/// The number of parallel tasks used to process pack files was limited
/// due to limits on the number of concurrent open file descriptors.
#[cfg(unix)]
Expand Down
6 changes: 3 additions & 3 deletions packages/packsquash/src/squash_zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
time::SystemTime
};

use aes::Aes128;
use aes::Aes256;
use ahash::AHashMap;
use futures::{StreamExt, TryStreamExt, future};
use thiserror::Error;
Expand Down Expand Up @@ -42,7 +42,7 @@ pub use self::obfuscation_engine::FileListingCircumstances;
mod buffered_async_spooled_temp_file;
mod obfuscation_engine;
pub mod relative_path;
pub mod system_id;
mod system_id;
pub mod system_time_sanitizer;
mod zip_file_record;

Expand Down Expand Up @@ -194,7 +194,7 @@ struct MutableSquashZipState<F: AsyncRead + AsyncSeek + Unpin> {

/// The system time sanitizer that SquashZip will use for sanitizing and
/// desanitizing dates to and from ZIP files, respectively.
static SYSTEM_TIME_SANITIZER: LazyLock<SystemTimeSanitizer<Aes128>> =
pub static SYSTEM_TIME_SANITIZER: LazyLock<SystemTimeSanitizer<Aes256>> =
LazyLock::new(SystemTimeSanitizer::new);

impl<F: AsyncRead + AsyncSeek + Unpin> SquashZip<F> {
Expand Down
Loading

0 comments on commit b86db81

Please sign in to comment.