From 01334d31d02741b53f4e42e92c035d2f2df1025c Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 19:57:52 -0500 Subject: [PATCH 1/7] Fix panic-on-malformed-input defects found in code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Harden the decryptors against corrupt/edge-case input so a single bad file errors cleanly instead of panicking (and, in a batch, aborting the whole run): * ADEPT EPUB: the content-decrypt guard was `len < 16` but then sliced off the 16-byte pad block before reading the trailing pad length; a one-block (16-byte) ciphertext left an empty slice and panicked on `.last().unwrap()`. Guard is now `len <= 16`. * MOBI: validate the section table before indexing it — require >= 2 sections and reject a record count that exceeds the section count, preventing out-of-bounds panics on `section_offsets[1]` / `section_bounds(i)`. * MOBI: `trailing_size` now uses saturating/checked subtraction, and the caller clamps the trailing size to the record length, so a corrupt trailing-size encoding can't underflow. * MOBI: `normalize_pids` slices PIDs by characters, not bytes, so a non-ASCII `--pid` can't panic on a non-char-boundary. * CLI: wrap the per-file decrypt in `catch_unwind` so any future panic is contained to that file rather than aborting a multi-file run. Adds 5 regression tests (one per fix). 46 lib tests pass; clippy + fmt clean. Co-Authored-By: Claude Opus 4.8 --- crates/drmlibre-cli/src/remove.rs | 13 ++++- crates/drmlibre-core/src/adept/epub.rs | 13 ++++- crates/drmlibre-core/src/kindle/mobi.rs | 78 +++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/crates/drmlibre-cli/src/remove.rs b/crates/drmlibre-cli/src/remove.rs index 781445d..4ee5c20 100644 --- a/crates/drmlibre-cli/src/remove.rs +++ b/crates/drmlibre-cli/src/remove.rs @@ -124,7 +124,18 @@ fn process_one( let tmp = temp_sibling(output); let _ = std::fs::remove_file(&tmp); - match decrypt(input, &tmp, keys, opts) { + // Contain any panic in the engine so one malformed file can't abort a whole + // multi-file run; turn it into a per-file error instead. + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + decrypt(input, &tmp, keys, opts) + })) + .unwrap_or_else(|_| { + Err(Error::Decrypt( + "internal error while processing this file (skipped)".into(), + )) + }); + + match result { Ok(Outcome::Decrypted) => { std::fs::rename(&tmp, output)?; Ok(()) diff --git a/crates/drmlibre-core/src/adept/epub.rs b/crates/drmlibre-core/src/adept/epub.rs index a35cafd..493aa8b 100644 --- a/crates/drmlibre-core/src/adept/epub.rs +++ b/crates/drmlibre-core/src/adept/epub.rs @@ -146,7 +146,9 @@ pub fn decrypt_epub(input: &Path, output: &Path, key: UserKey, opts: &Options) - /// raw-inflate. Mirrors `ineptepub.py::Decryptor.decrypt`. fn decrypt_content(bookkey: &[u8], data: &[u8], decompress: bool) -> Result> { let pt = crypto::aes128_cbc_decrypt_nopad(bookkey, &[0u8; 16], data)?; - if pt.len() < 16 { + // The first 16 bytes are a throwaway pad block, so there must be at least + // one more block after them before we can read the trailing pad length. + if pt.len() <= 16 { return Err(Error::Decrypt("ciphertext too short".into())); } let pt = &pt[16..]; @@ -333,6 +335,15 @@ mod tests { assert!(decrypt_epub(&input, &output, UserKey::Rsa(&other_der), &opts).is_err()); } + #[test] + fn decrypt_content_rejects_single_block_without_panic() { + // A one-block ciphertext decrypts to 16 bytes; after dropping the 16-byte + // pad block nothing is left, so this must error rather than panic. + let bookkey = [0u8; 16]; + let ct = [0xABu8; 16]; + assert!(decrypt_content(&bookkey, &ct, false).is_err()); + } + #[test] fn drm_free_epub_reports_already_free() { let dir = tempfile::tempdir().unwrap(); diff --git a/crates/drmlibre-core/src/kindle/mobi.rs b/crates/drmlibre-core/src/kindle/mobi.rs index b234252..a13d943 100644 --- a/crates/drmlibre-core/src/kindle/mobi.rs +++ b/crates/drmlibre-core/src/kindle/mobi.rs @@ -186,6 +186,20 @@ impl MobiBook { ))); } + // Guard the section table against a corrupt header before we index it: + // we need at least sections 0 and 1, and every text record (1..=records) + // must have a corresponding section. + if self.section_offsets.len() < 2 { + return Err(Error::Decrypt( + "MOBI has too few sections to decrypt".into(), + )); + } + if self.records >= self.section_offsets.len() { + return Err(Error::Decrypt( + "MOBI record count exceeds section count (corrupt)".into(), + )); + } + // Normalize the supplied PIDs to 8-character form (mobidedrm goodpids). let goodpids = normalize_pids(pidlist); @@ -235,7 +249,7 @@ impl MobiBook { for i in 1..=self.records { let (start, end) = self.section_bounds(i); let sec = &self.data[start..end]; - let extra = trailing_size(sec, self.extra_data_flags); + let extra = trailing_size(sec, self.extra_data_flags).min(sec.len()); let body = &sec[..sec.len() - extra]; out.extend_from_slice(&pc1(&found_key, body, true)?); if extra > 0 { @@ -270,8 +284,9 @@ impl MobiBook { fn normalize_pids(pidlist: &[String]) -> Vec { let mut good = Vec::new(); for pid in pidlist { - match pid.len() { - 10 => good.push(pid[..8].to_string()), + // Count/slice by characters, not bytes: a non-ASCII --pid must not panic. + match pid.chars().count() { + 10 => good.push(pid.chars().take(8).collect()), // drop the 2-char checksum 8 => good.push(pid.clone()), _ => tracing::debug!("ignoring PID {pid} with wrong length"), } @@ -342,12 +357,16 @@ fn trailing_size(ptr: &[u8], flags: u16) -> usize { let mut testflags = flags >> 1; while testflags != 0 { if testflags & 1 != 0 { - num += entry(ptr, ptr.len() - num); + // `num` may already exceed the record on corrupt input; saturate so + // the size param can't underflow. + num += entry(ptr, ptr.len().saturating_sub(num)); } testflags >>= 1; } if flags & 1 != 0 { - num += (ptr[ptr.len() - num - 1] & 0x3) as usize + 1; + if let Some(&b) = ptr.len().checked_sub(num + 1).and_then(|i| ptr.get(i)) { + num += (b & 0x3) as usize + 1; + } } num } @@ -483,4 +502,53 @@ mod tests { let out = book.process(&[]).unwrap(); assert_eq!(out, data); } + + /// A single-section BOOKMOBI (num_sections = 1) claiming encryption. + fn build_one_section_mobi(crypto_type: u16) -> Vec { + let mut sec0 = vec![0u8; 0x100]; + sec0[0..2].copy_from_slice(&1u16.to_be_bytes()); // compression + sec0[0xC..0xE].copy_from_slice(&crypto_type.to_be_bytes()); + sec0[0x14..0x18].copy_from_slice(&0xC8u32.to_be_bytes()); // mobi_length + sec0[0x68..0x6C].copy_from_slice(&6u32.to_be_bytes()); // mobi_version + + let num_sections = 1u16; + let header_len = 78 + num_sections as usize * 8; // 86 + let mut data = vec![0u8; header_len]; + data[0x3C..0x44].copy_from_slice(b"BOOKMOBI"); + data[76..78].copy_from_slice(&num_sections.to_be_bytes()); + data[78..82].copy_from_slice(&(header_len as u32).to_be_bytes()); + data.extend_from_slice(&sec0); + data + } + + #[test] + fn single_section_mobi_errors_not_panics() { + let data = build_one_section_mobi(2); + let book = MobiBook::from_bytes(data).unwrap(); + assert!(book.process(&[]).is_err()); + } + + #[test] + fn corrupt_record_count_errors_not_panics() { + let bookkey = [0xC3u8; 16]; + let mut data = build_encrypted_mobi(&bookkey, "12345678", b"hi"); + // Patch the record count (sec0 + 8; sec0 starts at 94) to exceed sections. + data[94 + 8..94 + 10].copy_from_slice(&0xFFFFu16.to_be_bytes()); + let book = MobiBook::from_bytes(data).unwrap(); + assert!(book.process(&["12345678".to_string()]).is_err()); + } + + #[test] + fn trailing_size_does_not_underflow_on_corrupt_input() { + // Encoded sizes far exceed the record length; must return, not panic. + let _ = trailing_size(&[0x7F, 0x7F], 0b110); // two size entries + let _ = trailing_size(&[0x7F], 0b11); // size entry + multibyte flag + } + + #[test] + fn normalize_pids_handles_non_ascii() { + // A 10-byte PID whose 8th byte is mid-character must not panic. + let pids = vec!["XXXXXXXéX".to_string()]; + assert!(normalize_pids(&pids).is_empty()); + } } -- 2.47.3 From e5e4173ee63dcb39d394fac7a72f9e910245e41c Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:03:32 -0500 Subject: [PATCH 2/7] Add CI and release GitHub Actions workflows * ci.yml: on pull requests to main, runs on windows-latest and macos-latest; checks formatting, runs clippy (warnings denied), and runs the unit tests (`cargo test --workspace`). * release.yml: manual workflow_dispatch (tag + optional prerelease inputs); builds release binaries for Windows (x86_64) and macOS (aarch64 + x86_64), then publishes them to GitHub Releases with auto-generated notes. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 40 +++++++++++++++ .github/workflows/release.yml | 91 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..29a805d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + pull_request: + branches: [main] + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [windows-latest, macos-latest] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache cargo build + uses: Swatinem/rust-cache@v2 + + - name: Format check + run: cargo fmt --all -- --check + + - name: Clippy + run: cargo clippy --workspace --all-targets --locked -- -D warnings + + - name: Run unit tests + run: cargo test --workspace --locked diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c951036 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,91 @@ +name: Release + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag, e.g. v0.1.0" + required: true + type: string + prerelease: + description: "Mark this release as a pre-release" + required: false + type: boolean + default: false + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + name: Build ${{ matrix.asset }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + target: x86_64-pc-windows-msvc + bin: drmlibre.exe + asset: drmlibre-windows-x86_64.exe + - os: macos-latest + target: aarch64-apple-darwin + bin: drmlibre + asset: drmlibre-macos-aarch64 + - os: macos-latest + target: x86_64-apple-darwin + bin: drmlibre + asset: drmlibre-macos-x86_64 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - name: Cache cargo build + uses: Swatinem/rust-cache@v2 + + - name: Build release binary + run: cargo build --release --locked --target ${{ matrix.target }} --bin drmlibre + + - name: Stage artifact + shell: bash + run: | + mkdir -p dist + cp "target/${{ matrix.target }}/release/${{ matrix.bin }}" "dist/${{ matrix.asset }}" + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.asset }} + path: dist/${{ matrix.asset }} + if-no-files-found: error + + release: + name: Publish GitHub Release + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Publish to GitHub Releases + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ inputs.tag }} + name: ${{ inputs.tag }} + prerelease: ${{ inputs.prerelease }} + generate_release_notes: true + fail_on_unmatched_files: true + files: dist/* -- 2.47.3 From f776172d57bd64048fcd6469f1ed4888a662c692 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:08:40 -0500 Subject: [PATCH 3/7] Pin GitHub Actions to commit SHAs at their latest versions Update each action to its current latest release and pin to the full commit SHA (supply-chain hardening), with the version in a trailing comment: * actions/checkout v4 -> v7.0.0 * Swatinem/rust-cache v2 -> v2.9.1 * actions/upload-artifact v4 -> v7.0.1 * actions/download-artifact v4 -> v8.0.1 * softprops/action-gh-release v2 -> v3.0.1 * dtolnay/rust-toolchain pinned to master @ 2026-06-20 (no tagged releases); add explicit `toolchain: stable` since the channel can no longer be inferred from the @ref once pinned to a SHA. Verified upload-artifact v7 (zips by default) and download-artifact v8 interoperate, and that every input still exists in the new majors. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 9 ++++++--- .github/workflows/release.yml | 15 +++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29a805d..48c54ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,15 +20,18 @@ jobs: os: [windows-latest, macos-latest] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + # dtolnay/rust-toolchain has no tagged releases; pinned to master @ 2026-06-20. + # When pinned to a SHA the channel must be given explicitly via `toolchain`. + uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 with: + toolchain: stable components: rustfmt, clippy - name: Cache cargo build - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Format check run: cargo fmt --all -- --check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c951036..0e7b6fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,15 +41,18 @@ jobs: asset: drmlibre-macos-x86_64 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable + # dtolnay/rust-toolchain has no tagged releases; pinned to master @ 2026-06-20. + # When pinned to a SHA the channel must be given explicitly via `toolchain`. + uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 with: + toolchain: stable targets: ${{ matrix.target }} - name: Cache cargo build - uses: Swatinem/rust-cache@v2 + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 - name: Build release binary run: cargo build --release --locked --target ${{ matrix.target }} --bin drmlibre @@ -61,7 +64,7 @@ jobs: cp "target/${{ matrix.target }}/release/${{ matrix.bin }}" "dist/${{ matrix.asset }}" - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.asset }} path: dist/${{ matrix.asset }} @@ -75,13 +78,13 @@ jobs: contents: write steps: - name: Download build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: dist merge-multiple: true - name: Publish to GitHub Releases - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 with: tag_name: ${{ inputs.tag }} name: ${{ inputs.tag }} -- 2.47.3 From 47041225a09a95c3875c30bb4f33e29d92245d86 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:11:24 -0500 Subject: [PATCH 4/7] Pin CI/release Rust toolchain to 1.96.0 (latest stable) Replace the floating `stable` channel with the exact current latest stable (1.96.0, which also matches the crate's rust-version/MSRV) so builds are reproducible and `clippy -D warnings` can't break from an unrelated toolchain bump. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48c54ed..6c2658c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: # When pinned to a SHA the channel must be given explicitly via `toolchain`. uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 with: - toolchain: stable + toolchain: "1.96.0" # latest stable as of 2026-05-28 components: rustfmt, clippy - name: Cache cargo build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e7b6fd..28cd8a2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,7 +48,7 @@ jobs: # When pinned to a SHA the channel must be given explicitly via `toolchain`. uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 with: - toolchain: stable + toolchain: "1.96.0" # latest stable as of 2026-05-28 targets: ${{ matrix.target }} - name: Cache cargo build -- 2.47.3 From 2d8f3f910d913b467044e5948bdd88aaf5eb3494 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:13:08 -0500 Subject: [PATCH 5/7] date comment update --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c2658c..ff20b38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: # When pinned to a SHA the channel must be given explicitly via `toolchain`. uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 with: - toolchain: "1.96.0" # latest stable as of 2026-05-28 + toolchain: "1.96.0" # latest stable as of 2026-06-24 components: rustfmt, clippy - name: Cache cargo build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28cd8a2..e9b36e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,7 +48,7 @@ jobs: # When pinned to a SHA the channel must be given explicitly via `toolchain`. uses: dtolnay/rust-toolchain@67ef31d5b988238dd797d409d6f9574278e20537 with: - toolchain: "1.96.0" # latest stable as of 2026-05-28 + toolchain: "1.96.0" # latest stable as of 2026-06-24 targets: ${{ matrix.target }} - name: Cache cargo build -- 2.47.3 From 259bb4d6fa8e0b97c1291a139db4bb6499bbeb35 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:27:43 -0500 Subject: [PATCH 6/7] Update dependencies to latest versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump dependency requirements to their current latest and migrate the code for the breaking API changes; refresh Cargo.lock for the rest. Notable version bumps: * zip 2 -> 8, quick-xml 0.37 -> 0.40, toml 0.8 -> 1 * windows 0.58 -> 0.62, winreg 0.52 -> 0.56 * RustCrypto: aes 0.8 -> 0.9, cbc 0.1 -> 0.2, sha1/sha2 0.10 -> 0.11, md-5 0.10 -> 0.11, ctr 0.9 -> 0.10, hmac 0.12 -> 0.13, pbkdf2 0.12 -> 0.13 Code migrations: * quick-xml 0.40: BytesText::unescape() -> xml10_content(); Attribute::unescape_value() -> normalized_value(XmlVersion::Implicit1_0) * windows 0.62: LocalFree now takes Option * cipher 0.5 (aes 0.9 / cbc 0.2): BlockEncryptMut/BlockDecryptMut -> BlockModeEncrypt/BlockModeDecrypt; encrypt_padded_mut/decrypt_padded_mut -> encrypt_padded/decrypt_padded Held back deliberately: rand stays 0.8 because the latest rsa (0.9) still needs an rand_core 0.6 RNG for keygen, which rand 0.9+ no longer provides. rsa pinning the older RustCrypto generation also leaves a couple of duplicate transitive versions (digest 0.10/0.11, crypto-common 0.1/0.2) — harmless. Verified: 46 tests pass, clippy + rustfmt clean, and a real ADEPT EPUB still decrypts end-to-end (DPAPI key extraction + RSA/AES) to a valid DRM-free file. Co-Authored-By: Claude Opus 4.8 --- Cargo.lock | 446 +++++++----------- Cargo.toml | 22 +- crates/drmlibre-core/Cargo.toml | 6 +- .../drmlibre-core/src/adept/encryption_xml.rs | 5 +- crates/drmlibre-core/src/adept/fonts.rs | 7 +- crates/drmlibre-core/src/crypto.rs | 10 +- crates/drmlibre-core/src/extract/win.rs | 2 +- crates/drmlibre-core/src/xmlutil.rs | 7 +- 8 files changed, 217 insertions(+), 288 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f93968..8ed00dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,12 +10,12 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aes" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" dependencies = [ - "cfg-if", "cipher", + "cpubits", "cpufeatures", ] @@ -64,7 +64,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -75,16 +75,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", + "windows-sys", ] [[package]] @@ -113,20 +104,20 @@ checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] name = "block-padding" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +checksum = "710f1dd022ef4e93f8a438b4ba958de7f64308434fa6a87104481645cc30068b" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -137,9 +128,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "cbc" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" dependencies = [ "cipher", ] @@ -152,11 +143,11 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ - "crypto-common", + "crypto-common 0.2.2", "inout", ] @@ -213,10 +204,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "const-oid" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ "libc", ] @@ -230,12 +233,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - [[package]] name = "crypto-common" version = "0.1.7" @@ -246,48 +243,45 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "der" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "const-oid 0.9.6", + "crypto-common 0.1.7", ] [[package]] -name = "displaydoc" -version = "0.2.6" +name = "digest" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "proc-macro2", - "quote", - "syn", + "block-buffer", + "const-oid 0.10.2", + "crypto-common 0.2.2", ] [[package]] @@ -338,7 +332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -355,6 +349,7 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] [[package]] @@ -407,6 +402,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "indexmap" version = "2.14.0" @@ -419,12 +423,12 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ "block-padding", - "generic-array", + "hybrid-array", ] [[package]] @@ -477,12 +481,12 @@ dependencies = [ [[package]] name = "md-5" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" dependencies = [ "cfg-if", - "digest", + "digest 0.11.3", ] [[package]] @@ -507,7 +511,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -624,9 +628,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.5" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +checksum = "2474bd2e5029e7ccb6abb2ba48cf2383a333851dedf495901544281590c7da7f" dependencies = [ "memchr", ] @@ -699,8 +703,8 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -723,7 +727,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -758,33 +762,33 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "sha1" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.11.3", ] [[package]] name = "sha2" -version = "0.10.9" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.11.3", ] [[package]] @@ -802,7 +806,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core", ] @@ -867,7 +871,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys", ] [[package]] @@ -901,44 +905,42 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" dependencies = [ "indexmap", - "serde", + "serde_core", "serde_spanned", "toml_datetime", - "toml_write", + "toml_parser", + "toml_writer", "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tracing" @@ -1001,6 +1003,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "typed-path" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" + [[package]] name = "typenum" version = "1.20.1" @@ -1039,32 +1047,54 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "windows" -version = "0.58.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ "windows-core", - "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.58.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", + "windows-link", "windows-result", "windows-strings", - "windows-targets 0.52.6", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.58.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -1073,9 +1103,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.58.0" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -1089,31 +1119,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-result" -version = "0.2.0" +name = "windows-numerics" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-targets 0.52.6", + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-link", ] [[package]] @@ -1126,143 +1156,28 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-threading" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - [[package]] name = "winnow" -version = "0.7.15" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" [[package]] name = "winreg" -version = "0.52.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1293,21 +1208,24 @@ checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zip" -version = "2.4.2" +version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" dependencies = [ - "arbitrary", "crc32fast", - "crossbeam-utils", - "displaydoc", "flate2", "indexmap", "memchr", - "thiserror", + "typed-path", "zopfli", ] +[[package]] +name = "zlib-rs" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977347db8caa080403f6b6b7c1cda9479a8e869316f7e13a59b19076a40f94e3" + [[package]] name = "zopfli" version = "0.8.3" diff --git a/Cargo.toml b/Cargo.toml index 04c2afe..5001c0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,23 +24,23 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } # Crypto (RustCrypto — pure Rust, statically linked) rsa = "0.9" -aes = "0.8" -cbc = "0.1" -ctr = "0.9" -sha1 = "0.10" -sha2 = "0.10" -md-5 = "0.10" -hmac = "0.12" -pbkdf2 = { version = "0.12", default-features = false } +aes = "0.9" +cbc = "0.2" +ctr = "0.10" +sha1 = "0.11" +sha2 = "0.11" +md-5 = "0.11" +hmac = "0.13" +pbkdf2 = { version = "0.13", default-features = false } # Config / serialization serde = { version = "1", features = ["derive"] } -toml = "0.8" +toml = "1" # Containers / encoding -zip = { version = "2", default-features = false, features = ["deflate"] } +zip = { version = "8", default-features = false, features = ["deflate"] } flate2 = "1" -quick-xml = "0.37" +quick-xml = "0.40" base64 = "0.22" hex = "0.4" diff --git a/crates/drmlibre-core/Cargo.toml b/crates/drmlibre-core/Cargo.toml index 05dfc06..50d6afa 100644 --- a/crates/drmlibre-core/Cargo.toml +++ b/crates/drmlibre-core/Cargo.toml @@ -29,14 +29,16 @@ md-5.workspace = true # Local key extraction from installed Adobe Digital Editions / Kindle (Windows). [target.'cfg(windows)'.dependencies] -windows = { version = "0.58", features = [ +windows = { version = "0.62", features = [ "Win32_Foundation", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Memory", ] } -winreg = "0.52" +winreg = "0.56" [dev-dependencies] tempfile = "3" +# Held at 0.8: the latest `rsa` (0.9) requires an `rand_core` 0.6 RNG for keygen, +# which rand 0.9+ no longer provides; bumping breaks the RSA-based EPUB tests. rand = "0.8" diff --git a/crates/drmlibre-core/src/adept/encryption_xml.rs b/crates/drmlibre-core/src/adept/encryption_xml.rs index 10afd67..3650d42 100644 --- a/crates/drmlibre-core/src/adept/encryption_xml.rs +++ b/crates/drmlibre-core/src/adept/encryption_xml.rs @@ -113,7 +113,10 @@ fn handle_open( fn attr_value(e: &quick_xml::events::BytesStart, local: &str) -> Option { for attr in e.attributes().flatten() { if local_eq(local_name(attr.key.as_ref()), local) { - return attr.unescape_value().ok().map(|v| v.into_owned()); + return attr + .normalized_value(quick_xml::XmlVersion::Implicit1_0) + .ok() + .map(|v| v.into_owned()); } } None diff --git a/crates/drmlibre-core/src/adept/fonts.rs b/crates/drmlibre-core/src/adept/fonts.rs index a3019a7..04fdcb7 100644 --- a/crates/drmlibre-core/src/adept/fonts.rs +++ b/crates/drmlibre-core/src/adept/fonts.rs @@ -207,7 +207,7 @@ fn parse_opf(xml: &[u8]) -> (Option, Vec) { } Ok(Event::Text(t)) => { if let Some(ident) = cur.as_mut() { - if let Ok(s) = t.unescape() { + if let Ok(s) = t.xml10_content() { ident.text.push_str(&s); } } @@ -228,7 +228,10 @@ fn parse_opf(xml: &[u8]) -> (Option, Vec) { fn attr_value(e: &quick_xml::events::BytesStart, local: &str) -> Option { for attr in e.attributes().flatten() { if local_eq(local_name(attr.key.as_ref()), local) { - return attr.unescape_value().ok().map(|v| v.into_owned()); + return attr + .normalized_value(quick_xml::XmlVersion::Implicit1_0) + .ok() + .map(|v| v.into_owned()); } } None diff --git a/crates/drmlibre-core/src/crypto.rs b/crates/drmlibre-core/src/crypto.rs index 05b5d0f..ae38720 100644 --- a/crates/drmlibre-core/src/crypto.rs +++ b/crates/drmlibre-core/src/crypto.rs @@ -6,7 +6,7 @@ use aes::Aes128; use cbc::cipher::block_padding::NoPadding; -use cbc::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}; +use cbc::cipher::{BlockModeDecrypt, BlockModeEncrypt, KeyIvInit}; use sha2::Digest; use crate::error::{Error, Result}; @@ -42,7 +42,7 @@ pub fn aes128_cbc_decrypt_nopad(key: &[u8], iv: &[u8], data: &[u8]) -> Result::new_from_slices(key, iv) .map_err(|_| Error::Decrypt("bad AES key/iv length".into()))?; let pt = dec - .decrypt_padded_mut::(&mut buf) + .decrypt_padded::(&mut buf) .map_err(|e| Error::Decrypt(format!("AES-CBC decrypt failed: {e}")))?; let len = pt.len(); buf.truncate(len); @@ -62,7 +62,7 @@ pub fn aes128_cbc_encrypt_nopad(key: &[u8], iv: &[u8], data: &[u8]) -> Result::new_from_slices(key, iv) .map_err(|_| Error::Decrypt("bad AES key/iv length".into()))?; let ct = enc - .encrypt_padded_mut::(&mut buf, len) + .encrypt_padded::(&mut buf, len) .map_err(|e| Error::Decrypt(format!("AES-CBC encrypt failed: {e}")))?; Ok(ct.to_vec()) } @@ -147,7 +147,7 @@ mod tests { fn aes_cbc_roundtrip_nopad() { use aes::Aes128; use cbc::cipher::block_padding::NoPadding; - use cbc::cipher::{BlockEncryptMut, KeyIvInit}; + use cbc::cipher::{BlockModeEncrypt, KeyIvInit}; let key = [0x11u8; 16]; let iv = [0x22u8; 16]; @@ -155,7 +155,7 @@ mod tests { let mut buf = pt.to_vec(); let ct = cbc::Encryptor::::new_from_slices(&key, &iv) .unwrap() - .encrypt_padded_mut::(&mut buf, 32) + .encrypt_padded::(&mut buf, 32) .unwrap() .to_vec(); let back = aes128_cbc_decrypt_nopad(&key, &iv, &ct).unwrap(); diff --git a/crates/drmlibre-core/src/extract/win.rs b/crates/drmlibre-core/src/extract/win.rs index b0913be..9e035aa 100644 --- a/crates/drmlibre-core/src/extract/win.rs +++ b/crates/drmlibre-core/src/extract/win.rs @@ -213,7 +213,7 @@ fn crypt_unprotect(data: &[u8], entropy: &[u8]) -> Result> { }, )?; let result = std::slice::from_raw_parts(out.pbData, out.cbData as usize).to_vec(); - let _ = LocalFree(HLOCAL(out.pbData as *mut core::ffi::c_void)); + let _ = LocalFree(Some(HLOCAL(out.pbData as *mut core::ffi::c_void))); Ok(result) } } diff --git a/crates/drmlibre-core/src/xmlutil.rs b/crates/drmlibre-core/src/xmlutil.rs index 1decb58..c6523cb 100644 --- a/crates/drmlibre-core/src/xmlutil.rs +++ b/crates/drmlibre-core/src/xmlutil.rs @@ -25,7 +25,7 @@ pub fn first_element_text(xml: &[u8], local_name: &str) -> Option { } } Ok(Event::Text(e)) if inside => { - if let Ok(t) = e.unescape() { + if let Ok(t) = e.xml10_content() { text.push_str(&t); } } @@ -54,7 +54,10 @@ pub fn first_element_attr(xml: &[u8], local_name_wanted: &str, attr: &str) -> Op { for a in e.attributes().flatten() { if local_eq(local_name(a.key.as_ref()), attr) { - return a.unescape_value().ok().map(|v| v.into_owned()); + return a + .normalized_value(quick_xml::XmlVersion::Implicit1_0) + .ok() + .map(|v| v.into_owned()); } } return None; -- 2.47.3 From 2cdefbe45c2b298529924092b492e2bea0e7b242 Mon Sep 17 00:00:00 2001 From: Jason Ross Date: Wed, 24 Jun 2026 20:44:22 -0500 Subject: [PATCH 7/7] Update rand to 0.10 with a rand_core 0.6 compatibility shim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the `rand` dev-dependency to the latest (0.10), which exposes rand_core 0.10, while the latest `rsa` (0.9) still requires an rand_core 0.6 RNG for key generation. Bridge the skew with a small, test-only adapter instead of pinning rand back. * Add `rand_core_06 = { package = "rand_core", version = "0.6" }` so the shim can implement the old traits (cargo unifies it with the rand_core 0.6 that rsa already uses). * `RandCompat` wraps a modern RNG and re-implements rand_core 0.6's RngCore + CryptoRng over it, delegating to rand_core 0.10's infallible methods. Implementing both satisfies rand_core 0.6's blanket CryptoRngCore impl, which is exactly the bound rsa keygen requires. * The CryptoRng bound is preserved (only wraps RNGs still marked cryptographically secure), so the randomness is not weakened — it is purely a trait-version shim. Tests now use `RandCompat(rand::rng())`. 46 tests pass (incl. the RSA-based EPUB roundtrips that exercise the shim); clippy + rustfmt clean. Co-Authored-By: Claude Opus 4.8 --- Cargo.lock | 43 +++++++++++++++++++++----- crates/drmlibre-core/Cargo.toml | 9 ++++-- crates/drmlibre-core/src/adept/epub.rs | 40 ++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ed00dc..25bd2a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core 0.10.1", +] + [[package]] name = "cipher" version = "0.5.2" @@ -305,7 +316,8 @@ dependencies = [ "hex", "md-5", "quick-xml", - "rand", + "rand 0.10.1", + "rand_core 0.6.4", "rsa", "serde", "sha1", @@ -382,6 +394,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core 0.10.1", ] [[package]] @@ -525,7 +538,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -656,9 +669,19 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ - "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", ] [[package]] @@ -668,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -680,6 +703,12 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "regex-automata" version = "0.4.14" @@ -710,7 +739,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -807,7 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] diff --git a/crates/drmlibre-core/Cargo.toml b/crates/drmlibre-core/Cargo.toml index 50d6afa..35373a3 100644 --- a/crates/drmlibre-core/Cargo.toml +++ b/crates/drmlibre-core/Cargo.toml @@ -39,6 +39,9 @@ winreg = "0.56" [dev-dependencies] tempfile = "3" -# Held at 0.8: the latest `rsa` (0.9) requires an `rand_core` 0.6 RNG for keygen, -# which rand 0.9+ no longer provides; bumping breaks the RSA-based EPUB tests. -rand = "0.8" +rand = "0.10" +# Escape hatch: the latest `rsa` (0.9) still requires an `rand_core` 0.6 RNG for +# key generation, while `rand` 0.10 provides `rand_core` 0.10. We depend on +# `rand_core` 0.6 directly (package-renamed to avoid the name clash) so the +# test-only `RandCompat` shim can re-implement its traits over a modern RNG. +rand_core_06 = { package = "rand_core", version = "0.6" } diff --git a/crates/drmlibre-core/src/adept/epub.rs b/crates/drmlibre-core/src/adept/epub.rs index 493aa8b..1d90a93 100644 --- a/crates/drmlibre-core/src/adept/epub.rs +++ b/crates/drmlibre-core/src/adept/epub.rs @@ -269,9 +269,43 @@ mod tests { Some(buf) } + /// Test-only escape hatch for the `rand_core` version skew: `rsa` 0.9 still + /// requires an `rand_core` 0.6 RNG for key generation, while `rand` 0.10 + /// exposes `rand_core` 0.10. `RandCompat` wraps a modern RNG and + /// re-implements `rand_core` 0.6's `RngCore`/`CryptoRng` over it, delegating + /// to the new (infallible) methods. Implementing both satisfies `rand_core` + /// 0.6's blanket `CryptoRngCore` impl — exactly what `rsa` keygen wants. + /// + /// The `CryptoRng` bound is preserved (we only wrap RNGs the new crate still + /// marks cryptographically secure), so this is a pure trait-version shim that + /// does not weaken the randomness. + struct RandCompat(R); + + impl rand_core_06::RngCore for RandCompat { + fn next_u32(&mut self) -> u32 { + rand::Rng::next_u32(&mut self.0) + } + fn next_u64(&mut self) -> u64 { + rand::Rng::next_u64(&mut self.0) + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + rand::Rng::fill_bytes(&mut self.0, dest) + } + fn try_fill_bytes( + &mut self, + dest: &mut [u8], + ) -> std::result::Result<(), rand_core_06::Error> { + // `fill_bytes` is infallible in rand_core 0.10. + rand::Rng::fill_bytes(&mut self.0, dest); + Ok(()) + } + } + + impl rand_core_06::CryptoRng for RandCompat {} + fn make_rsa() -> (Vec, rsa::RsaPublicKey) { use rsa::pkcs8::EncodePrivateKey; - let mut rng = rand::thread_rng(); + let mut rng = RandCompat(rand::rng()); let priv_key = rsa::RsaPrivateKey::new(&mut rng, 1024).unwrap(); let der = priv_key.to_pkcs8_der().unwrap().as_bytes().to_vec(); let pub_key = rsa::RsaPublicKey::from(&priv_key); @@ -286,7 +320,7 @@ mod tests { let (der, pub_key) = make_rsa(); let bookkey = [0x5Au8; 16]; - let mut rng = rand::thread_rng(); + let mut rng = RandCompat(rand::rng()); let enc_key = pub_key .encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &bookkey) .unwrap(); @@ -323,7 +357,7 @@ mod tests { let (_der, pub_key) = make_rsa(); let (other_der, _other_pub) = make_rsa(); let bookkey = [0x5Au8; 16]; - let mut rng = rand::thread_rng(); + let mut rng = RandCompat(rand::rng()); let enc_key = pub_key .encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &bookkey) .unwrap(); -- 2.47.3