Compare commits

..
Author SHA1 Message Date
Mounir IDRASSI f9089b0202 Linux: improve AppImage portability
Bundle the FUSE2 userspace library inside the AppImage AppDir and make AppRun prefer APPDIR/usr/lib. This lets the bundled VeraCrypt binary resolve libfuse.so.2 on systems where FUSE2 userspace packages are no longer installed by default.

Name AppImage artifacts according to the GTK backend detected during the build. GTK3 builds keep the default VeraCrypt-<version>-<arch>.AppImage name, while GTK2 builds use a gtk2-legacy suffix to distinguish the legacy compatibility artifact.

Include immintrin.h in the Argon2 AVX2 implementation so GCC toolchains such as the one on CentOS 7 see the AVX2 intrinsic types when compiling with -mavx2.

Refs: https://github.com/veracrypt/VeraCrypt/issues/1595
2026-05-26 23:46:33 +09:00
Mounir IDRASSI 4ad36447b2 Linux: fix CentOS 6 build with GCC 4.4
CentOS 6 builds VeraCrypt with GCC 4.4.7 and -std=c++0x. That compiler does not support range-based for loops, and its libstdc++ does not provide std::string::back() or std::string::pop_back().

Avoid those constructs in the affected Unix/Linux code paths: use VeraCrypt's existing foreach helper when iterating PKCS#11 object handles, and use indexing plus erase() when trimming trailing slashes from PATH entries.

This keeps the code valid for newer Linux toolchains while restoring compatibility with the CentOS 6 build environment.
2026-05-26 21:04:52 +09:00
Mounir IDRASSI 9b20099255 Build: harden OpenWrt package input handling
Stage VeraCrypt and wxWidgets sources under the SDK package directory before rendering the OpenWrt package Makefile. The generated recipe now refers only to fixed package-local paths, so checkout and work directory names are no longer parsed as GNU Make syntax or passed unquoted through recipe source arguments.

Validate VeraCrypt and wxWidgets version tokens before substituting them into generated package metadata. This prevents unexpected Make metacharacters from entering the generated OpenWrt recipe while preserving normal dotted release versions.

Quote OpenWrt QEMU test container-size values with the existing shell quoting helper, matching the password handling and preventing user-supplied size text from being split or interpreted by the guest shell.
2026-05-26 18:16:33 +09:00
Mounir IDRASSI d0bc546614 OpenBSD: fix CLI build and PCSC exit handling
OpenBSD builds were relying on ggod to generate embedded resource
headers. That tool is not available on a stock OpenBSD 7.9 install,
and using base od directly is not a safe substitute because it emits
zero-padded decimal values such as 060 and 098. Those tokens are then
included in C++ source and parsed as octal constants, which either
changes values or fails compilation.

Use hexdump with an explicit unsigned-byte format for OpenBSD. It is
part of the base system and emits unpadded decimal byte values suitable
for the existing resource-header pipeline.

The text-mode binary also crashed on normal process exit on OpenBSD,
including after --version, --test, create, mount, list, and dismount.
GDB showed the crash in libpcsclite_real during SCardReleaseContext(),
called from the static SCardManager destructor. This happened even for
commands that did not use EMV or security-token support because the
static manager constructor eagerly initialized PC/SC at startup.

Avoid eager PC/SC initialization and exit-time finalization on OpenBSD.
The existing call sites still initialize PC/SC lazily when EMV/token
operations need it, while ordinary CLI commands no longer touch
pcsc-lite and no longer crash during static destruction.

Validated on OpenBSD 7.9 amd64 with:
- gmake NOGUI=1 -j2
- veracrypt --text --version
- veracrypt --text --test
- device-hosted create/mount/list/dismount smoke test through doas/vnd

Refs #1589.
Refs #1593.
2026-05-26 17:58:04 +09:00
Mounir IDRASSI 6774de941d OpenBSD: honor doas user for mount ownership and FUSE access
VeraCrypt derives the real (non-root) user from SUDO_UID/SUDO_GID
to set default mount-point ownership and the FUSE service access
filter. On OpenBSD, privileged commands are normally run through doas,
which exposes the invoking login name via DOAS_USER and does not set
the sudo variables. As a result, VeraCrypt launched through doas
attributes both to root instead of the invoking user.

When the sudo identity variables are absent, resolve DOAS_USER through
the password database and use that uid/gid for default mount-point
ownership and the VeraCrypt FUSE service access filter. sudo behavior
is unchanged.

This is a correctness fix for the doas launch path. It is not confirmed
to resolve the non-root ext2fs EACCES reported in the linked issues:
that failure occurs at the ext2fs layer reached through vnd, whose
backing-image I/O runs as root and is therefore already permitted by
the access filter.

Refs #1589.
Refs #1593.
2026-05-26 11:07:40 +09:00
Mounir IDRASSI 5d7a2a78b8 OpenBSD: fix device-hosted volume sizing
OpenBSD device length detection was returning the raw disk sector count from DIOCGPDINFO directly. That value is not bytes and it describes the physical/default disk label, which caused VeraCrypt to expose an incorrectly sized FUSE backing image through vnd for device-hosted volumes.

Use the current disklabel from DIOCGDINFO, derive the opened partition from the device minor number, and return the selected partition size in bytes. Keep the raw c partition on the whole-disk path by using DL_GETDSIZE there.

Also reject sector-misaligned device-hosted sizes during volume creation so new malformed OpenBSD device-hosted volumes are not created. Do not reject existing malformed headers at mount time, so users can still mount old OpenBSD-created volumes for recovery.

Refs #1589.

Refs #1593.
2026-05-26 11:04:54 +09:00
Mounir IDRASSI 0190270f9d Add OpenWrt package build and QEMU test scripts
Add OpenWrt SDK packaging under src/Build for console-only x86/64 builds. The build helper prepares the SDK, renders a local package recipe, builds VeraCrypt with the OpenWrt musl toolchain, uses wxWidgets 3.2.10 as static wxBase, enables FUSE3, and skips release self-tests during cross compilation.

Add a package template that installs the console binary, mount.veracrypt, and license files only. The package declares bash for mount.veracrypt and keeps runtime dependencies focused on the direct userland requirements.

Add a documented QEMU runtime test path that boots the matching OpenWrt image, installs the locally built package set with opkg, runs the VeraCrypt version and algorithm self-tests, and exercises a small filesystem=none container mount/unmount flow.

Allow wxbuild callers to pass WX_CONFIGURE_EXTRA_FLAGS so OpenWrt cross configure flags can be passed into the wxWidgets build without carrying an OpenWrt-specific source patch.
2026-05-26 10:39:21 +09:00
Mounir IDRASSI 3c771c07fc Windows: set version to 1.26.28.1 and update signed Windows drivers 2026-05-26 10:10:11 +09:00
Mounir IDRASSI a173a11cfe Linux: parallelize header KDF autodetection
Extend the Unix encryption thread pool to run key-derivation work items and use it when mounting volumes without an explicitly selected KDF. This brings Linux/macOS header PRF autodetection closer to the Windows path while keeping selected-KDF mounts unchanged.

Fixes #1610.
2026-05-25 21:54:14 +09:00
Mounir IDRASSI 66ddd29c91 Windows: report missing EFI boot loader clearly
When preparing UEFI system encryption, check for the standard Windows bootmgfw.efi path before reading it. If it is absent, show the existing VeraCrypt diagnostic instead of surfacing a generic file-not-found error from the elevated COM path.
2026-05-25 17:06:10 +09:00
Mounir IDRASSI 0d86b9b3e6 Document system favorite VHD startup limitation
Clarify that Windows startup-managed VHD/VHDX files, including Dev Drive backing images, cannot live on system favorite volumes because they are accessed before those volumes are mounted.

Document that native-boot VHD/VHDX files also cannot live on system favorite volumes and remain subject to the existing VeraCrypt pre-boot authentication limitation for operating systems installed within VHD/VHDX files.

Mention a delayed/retrying attach workaround for non-boot-critical VHD/VHDX files after VeraCryptSystemFavorites mounts the host volume.

Closes #1605.
2026-05-25 16:25:48 +09:00
Mounir IDRASSI 5bd9277970 Windows: fix MSI Start Menu folder upgrades
Use a stable VeraCrypt Start Menu folder for MSI installs instead of deriving it from the versioned product name. Refresh the shortcut component identities for the new folder location and add upgrade-time cleanup for old versioned VeraCrypt Start Menu folders while preserving folders that contain non-VeraCrypt content.

Fixes #1631.
2026-05-25 04:50:49 +09:00
Mounir IDRASSI 854f85f013 Linux: fix language loading when running as AppImage
Fixes #1624

The language file path was hardcoded to /usr/share/veracrypt/languages/
which doesn't exist inside an AppImage runtime. Language files are
actually located under $APPDIR/usr/share/veracrypt/languages/ when
running from an AppImage.

This affected both the language file loading in Resources.cpp and the
language enumeration in PreferencesDialog.cpp, causing the language
selection to show only "System default" and "English" regardless of
which translations were packaged in the AppImage.
2026-05-24 21:47:11 +09:00
Mounir IDRASSI fc2efd0b8f Linux: suppress redundant already-running dialog
When a second GUI process successfully notifies the running instance through the show-request FIFO, the handoff is not an error. Avoid showing the informational modal before exiting, and let the running instance restore the main window on any show request.

Also initialize the GTK indicator menu item pointers to NULL and guard the show/hide label update, preventing a latent crash in SetBackgroundMode when the indicator menu has not been built (e.g. background task disabled in preferences) -- a path made more reachable by the FIFO timer now invoking SetBackgroundMode unconditionally on incoming show requests.

Fixes #1447.

Closes #1745.

Refs #461.
2026-05-22 23:45:04 +09:00
Mounir IDRASSI d1f73ce429 Windows driver: queue volume flushes as ordered barriers
Route IRP_MJ_FLUSH_BUFFERS through EncryptedIoQueue for mounted writable non-system volumes. Flushes are represented as zero-length queue items handled by the I/O thread, so ZwFlushBuffersFile runs after earlier encrypted write fragments before completing to the caller.

Also perform a best-effort ZwFlushBuffersFile before closing writable mounted-volume host handles, after the encrypted I/O queue has drained, so clean dismount/shutdown paths push the host file or raw device before close.

This keeps the change focused on ordinary mounted-volume flush ordering and avoids system-encryption, boot-drive, and header-update paths.
2026-05-22 18:29:14 +09:00
Mounir IDRASSI 79bee911be Linux/macOS: enable quick format for file containers
Allow normal file-hosted containers to use quick format in the Unix volume creation path by sizing the host file with ftruncate before backup headers are written.

Enable the GUI checkbox for normal file containers and honor --quick in text mode. Update the Unix HTML documentation for the weaker deniability properties of sparse or unwritten host regions.
2026-05-22 10:46:30 +09:00
Mounir IDRASSI 1fd2fb06cd Build: avoid awk warning in version extraction 2026-05-21 23:43:49 +09:00
Mounir IDRASSI c3ce2db9ac Document fixed Argon2id header key size
Argon2id includes the requested output length in its computation, so deriving 192 bytes and using a prefix is not equivalent to deriving only the selected cipher's key material length. This differs from PBKDF2, where the prefix property made this detail invisible.

VeraCrypt derives the maximum header key material currently needed by the supported cipher/cascade set, which is 192 bytes, and then uses the required prefix for the selected encryption algorithm. For AES-XTS this means the first 64 bytes of the 192-byte Argon2id output are used.

Make this design rule explicit in code and documentation by introducing ARGON2_HEADER_KEYDATA_SIZE instead of relying implicitly on GetMaxPkcs5OutSize. If a future cipher or cascade requires more than 192 bytes, that must be handled as an explicit format/design change.

Document the 192-byte Argon2id header KDF output requirement so third-party implementations derive the same header key material.

References: https://github.com/veracrypt/VeraCrypt/issues/1614
2026-05-21 18:10:06 +09:00
74 changed files with 2683 additions and 147 deletions
+4
View File
@@ -4,6 +4,10 @@
# CLion
.idea/
# Python build/test artifacts
__pycache__/
*.py[cod]
# VC Linux build artifacts
*.o
*.o0
Binary file not shown.
+1 -1
View File
@@ -161,7 +161,7 @@ When using Argon2id in VeraCrypt:
<strong>Algorithm:</strong> Argon2id as defined in RFC 9106<br/>
<strong>Internal hash:</strong> BLAKE2b<br/>
<strong>Salt size:</strong> 512 bits (same as PBKDF2-HMAC)<br/>
<strong>Output length:</strong> Variable, depending on the encryption algorithm (e.g., 256 bits for AES-256, 768 bits for AES-Twofish-Serpent cascade)<br/>
<strong>Header KDF output length:</strong> Fixed at 1536 bits (192 bytes) for the current VeraCrypt format. The required prefix is used for the selected encryption algorithm (for example, the first 64 bytes for AES (AES-256-XTS)). Third-party implementations must request 192 bytes from Argon2id before selecting the required prefix; requesting only the selected algorithm's key material length produces a different Argon2id output.<br/>
<strong>Version:</strong> Argon2 version 0x13 (19 decimal)
</div>
+2 -2
View File
@@ -253,7 +253,7 @@
</tr>
<tr>
<td><em>--quick</em></td>
<td>Enable quick formatting when creating a volume. This option must not be used when creating an outer volume.</td>
<td>Enable quick formatting when creating a normal file-hosted or device-hosted volume. Do not use this option when creating an outer volume. In text mode, VeraCrypt cannot infer that a normal volume is intended to become an outer volume. For file containers, Quick Format may create sparse or unwritten host regions. Allocation behavior depends on host filesystem sparse-file support, and later writes can fail if the host filesystem runs out of space.</td>
</tr>
<tr>
<td><em>--random-source=FILE</em></td>
@@ -326,7 +326,7 @@
<h4>Hidden Volume Creation in Text Mode</h4>
<p>Inexperienced users should use the graphical user interface to create a hidden volume. When using the text user interface, the following procedure must be followed:</p>
<ol>
<li>Create an outer volume with no filesystem.</li>
<li>Create an outer volume with no filesystem and without <em>--quick</em>.</li>
<li>Create a hidden volume within the outer volume.</li>
<li>Mount the outer volume using hidden volume protection.</li>
<li>Create a filesystem on the virtual device of the outer volume.</li>
+3 -2
View File
@@ -56,10 +56,11 @@ Note that the output of a hash function is <em>never </em>used directly as an en
<p>This allows you to select the encryption algorithm with which your new volume will be encrypted. Note that the encryption algorithm cannot be changed after the volume is created. For more information, please see the chapter
<a href="Encryption%20Algorithms.html"><em>Encryption Algorithms</em></a>.</p>
<h3 id="QuickFormat">Quick Format</h3>
<p>If you are not sure whether to enable or disable Quick Format, we recommend that you leave this option unchecked.</p>
<p>If unchecked, each sector of the new volume will be formatted. This means that the new volume will be
<em>entirely </em>filled with random data. Quick format is much faster but may be less secure because until the whole volume has been filled with files, it may be possible to tell how much data it contains (if the space was not filled with random data beforehand).
If you are not sure whether to enable or disable Quick Format, we recommend that you leave this option unchecked. Note that Quick Format can only be enabled when encrypting partitions/devices, except on Windows where it is also available when creating file containers.</p>
<p>Important: When encrypting a partition/device within which you intend to create a hidden volume afterwards, leave this option unchecked.</p>
For file containers, the host filesystem may create sparse or unwritten regions, which can reveal unused areas and reduce plausible deniability. Host allocation behavior depends on filesystem sparse-file support. On filesystems without sparse-file support, creating the container may allocate most or all of its space immediately or fail if there is not enough host space. The encrypted filesystem may also report more free space than the host filesystem can actually provide. If host space runs out, later writes may fail or corrupt the encrypted filesystem. Quick Format is available for normal file containers and when encrypting partitions/devices.</p>
<p>Important: When creating an outer volume within which you intend to create a hidden volume afterwards, do not use Quick Format.</p>
<h3 id="dynamic">Dynamic</h3>
<p>Dynamic VeraCrypt container is a pre-allocated NTFS sparse file whose physical size (actual disk space used) grows as new data is added to it. Note that the physical size of the container (actual disk space that the container uses) will not decrease when
files are deleted on the VeraCrypt volume. The physical size of the container can only
+2
View File
@@ -304,6 +304,8 @@ The System Favorites Organizer window should appear now. In this window, enable
For more information, see the chapter <a href="System%20Favorite%20Volumes.html" target="_blank" style="text-align:left; color:#0080c0; text-decoration:none">
System Favorite Volumes</a>.</div>
<div style="text-align:left; margin-top:19px; margin-bottom:19px; padding-top:0px; padding-bottom:0px">
Note: System favorite volumes are not available during the earlier Windows boot and storage initialization phases. Therefore, Windows-managed startup dependencies such as automatically attached VHD/VHDX files, Dev Drive backing VHDX files, and native-boot VHD/VHDX files must not be stored on system favorite volumes. For VHD/VHDX files that are not required during boot or early startup, use a delayed/retrying task or a service that depends on <em>VeraCryptSystemFavorites</em> to attach them after the system favorite volume has been mounted. This workaround is not suitable for native-boot VHD/VHDX files or any other file that Windows must access before services can run.</div>
<div style="text-align:left; margin-top:19px; margin-bottom:19px; padding-top:0px; padding-bottom:0px">
<br style="text-align:left">
<strong style="text-align:left">Can a volume be automatically mounted whenever I log on to Windows?</strong></div>
<div style="text-align:left; margin-top:19px; margin-bottom:19px; padding-top:0px; padding-bottom:0px">
+1
View File
@@ -87,6 +87,7 @@ PIM </a>value is given by the user, the number of iterations of the PBKDF2 key d
<h4>Argon2id Parameters</h4>
<p>When Argon2id is selected as the key derivation function, the PIM value controls both memory and time costs as described in the <a href="Personal%20Iterations%20Multiplier%20%28PIM%29.html">PIM section</a>. If no PIM is specified, default parameters equivalent to PIM = 12 are used (416 MiB memory, 6 iterations).</p>
<p>For Argon2id, VeraCrypt derives a fixed 192 bytes of header key material for the current volume format, independently of the selected encryption algorithm. The selected encryption algorithm then uses the required prefix of that derived output. For example, AES-XTS uses the first 64 bytes. Implementations must request 192 bytes from Argon2id and then select the required prefix; requesting only the selected algorithm's key material length produces a different Argon2id output because Argon2id includes the requested output length in its computation.</p>
</div>
<div style="text-align:left; margin-top:19px; margin-bottom:19px; padding-top:0px; padding-bottom:0px">
+2 -1
View File
@@ -62,7 +62,8 @@ In such situations, the issue can be solved by disabling VeraCrypt waiting dialo
by selecting <em>System</em> &gt; <em>Mount Without Pre-Boot Authentication,</em> is limited to primary partitions (extended/logical partitions cannot be mounted this way).
</li><li>Due to a Windows 2000 issue, VeraCrypt does not support the Windows Mount Manager under Windows 2000. Therefore, some Windows 2000 built-in tools, such as Disk Defragmenter, do not work on VeraCrypt volumes. Furthermore, it is not possible to use the Mount
Manager services under Windows 2000, e.g., assign a mount point to a VeraCrypt volume (i.e., attach a VeraCrypt volume to a folder).
</li><li>VeraCrypt does not support pre-boot authentication for operating systems installed within VHD files, except when booted using appropriate virtual-machine software such as Microsoft Virtual PC.
</li><li>VeraCrypt does not support pre-boot authentication for operating systems installed within VHD/VHDX files, except when booted using appropriate virtual-machine software such as Microsoft Virtual PC.
</li><li>VHD/VHDX files that Windows must attach automatically during startup, including Dev Drive backing VHDX files, cannot be stored on system favorite volumes because these volumes are mounted only after the earlier Windows boot and storage initialization phases have already started. Store such non-boot VHD/VHDX files on the encrypted system partition/drive or on another partition within the key scope of system encryption. Native-boot VHD/VHDX files also cannot be stored on system favorite volumes; they remain subject to the preceding limitation on pre-boot authentication for operating systems installed within VHD/VHDX files. For VHD/VHDX files that are not required for boot or early Windows startup, disable Windows automatic attachment and attach them later using a delayed/retrying startup task or a service that depends on the <em>VeraCryptSystemFavorites</em> service. This workaround is not suitable for native-boot VHD/VHDX files or any other file that Windows must access before services can run.
</li><li>The Windows Volume Shadow Copy Service is currently supported only for partitions within the key scope of system encryption (e.g. a system partition encrypted by VeraCrypt, or a non- system partition located on a system drive encrypted by VeraCrypt, mounted
when the encrypted operating system is running). Note: For other types of volumes, the Volume Shadow Copy Service is not supported because the documentation for the necessary API is not available.
</li><li>Windows boot settings cannot be changed from within a hidden operating system if the system does not boot from the partition on which it is installed. This is due to the fact that, for security reasons, the boot partition is mounted as read-only when the
+5
View File
@@ -48,6 +48,11 @@
<li>Translator note: the previous Linux ntfs3 preference strings were replaced by generic in-kernel NTFS driver strings and should be retranslated.</li>
</ul>
</li>
<li><strong>Linux and macOS:</strong>
<ul>
<li>Enable Quick Format for normal file containers. The container is sized with <code>ftruncate()</code>, so the host filesystem may keep regions unwritten or sparse until data is written to them.</li>
</ul>
</li>
</ul>
<p><strong style="text-align:left">1.26.27</strong> (September 20<sup>th</sup>, 2025):</p>
+2 -2
View File
@@ -74,8 +74,8 @@ System favorite volumes <strong>can be configured to be available within VeraCry
<br>
Warning: When the drive letter assigned to a system favorite volume (saved in the configuration file) is not free, the volume is not mounted and no error message is displayed.<br>
<br>
Note that Windows needs to use some files (e.g. paging files, Active Directory files, etc.) before system favorite volumes are mounted. Therefore, such files cannot be stored on system favorite volumes. Note, however, that they
<em>can </em>be stored on any partition that is within the key scope of system encryption (e.g. on the system partition or on any partition of a system drive that is entirely encrypted by VeraCrypt).<br>
Note that Windows needs to use some files (e.g. paging files, Active Directory files, VHD/VHDX files configured for automatic attachment at startup, Dev Drive backing VHDX files, native-boot VHD/VHDX files, etc.) before system favorite volumes are mounted. Therefore, such files cannot be stored on system favorite volumes. Note, however, that files supported by VeraCrypt system encryption
<em>can </em>be stored on any partition that is within the key scope of system encryption (e.g. on the system partition or on any partition of a system drive that is entirely encrypted by VeraCrypt). Native-boot VHD/VHDX files remain subject to the limitation that VeraCrypt does not support pre-boot authentication for operating systems installed within VHD/VHDX files. For VHD/VHDX files that are not required for boot or early Windows startup, a possible workaround is to disable Windows automatic attachment and attach them only after the corresponding system favorite volume has been mounted, for example by using a delayed/retrying startup task or a service that depends on the <em>VeraCryptSystemFavorites</em> service and runs <code>Mount-DiskImage</code> or <code>diskpart attach vdisk</code>. This workaround is not suitable for paging files, Active Directory files, native-boot VHD/VHDX files, or any other file that Windows must access before services can run.<br>
<br>
<strong>To remove a volume from the list of system favorite volumes</strong>, select
<em>Favorites </em>&gt; <em>Organize System Favorite Volumes</em>, select the volume, click
+1 -1
View File
@@ -96,7 +96,7 @@ endif
# Embedded files
ifeq "$(PLATFORM)" "OpenBSD"
OD_BIN := ggod -v -t u1 -A n
OD_BIN := hexdump -v -e '1/1 "%u "'
else
OD_BIN := od -v -t u1 -A n
endif
+163
View File
@@ -0,0 +1,163 @@
# OpenWrt packaging
This directory contains the canonical OpenWrt package template and local test
configuration for building VeraCrypt console-only with the OpenWrt SDK.
It is a maintainer build-and-test harness for the VeraCrypt working tree, not
an OpenWrt packages-feed submission recipe.
The current supported target is `x86/64`, matching the QEMU runtime smoke test.
The build uses:
- OpenWrt 24.10.6 x86/64 SDK by default
- musl through the OpenWrt toolchain
- `NOGUI=1`
- `WITHFUSE3=1`
- `WXSTATIC=1`
- wxWidgets 3.2.10 built as static wxBase
- `NOTEST=1` during cross compilation
- `NOSTRIP=1`, with OpenWrt package stripping disabled for maintainer
diagnostics
The package installs only:
- `/usr/bin/veracrypt`
- `/sbin/mount.veracrypt`
- `/usr/share/licenses/veracrypt/License.txt`
`mount.veracrypt` uses a Bash shebang, so the OpenWrt package declares `bash`
as a runtime dependency.
## Build
From the VeraCrypt checkout root:
```sh
src/Build/build_veracrypt_openwrt.sh
```
The script downloads and verifies the OpenWrt SDK against a pinned SHA-256 for
the supported release/target, downloads and verifies wxWidgets 3.2.10, installs
the required OpenWrt feeds, renders
`package/utils/veracrypt/Makefile` inside the SDK, builds the `.ipk`, and
also builds the local userland `bash`, `fuse3`, `util-linux`, and `lvm2` feed
packages used by the QEMU runtime test. Kernel modules for the stock OpenWrt
image are resolved by the test from the official OpenWrt kmod feed for the
selected release and target.
Default output location:
```text
../openwrt-veracrypt/openwrt-sdk-24.10.6-x86-64_gcc-13.3.0_musl.Linux-x86_64/bin/packages/x86_64/base/veracrypt_<version>-r1_x86_64.ipk
```
Useful options:
```sh
src/Build/build_veracrypt_openwrt.sh --fresh-sdk
src/Build/build_veracrypt_openwrt.sh --work-dir /tmp/veracrypt-openwrt
src/Build/build_veracrypt_openwrt.sh --sdk-dir /path/to/openwrt-sdk
src/Build/build_veracrypt_openwrt.sh --sdk-url URL --sdk-sha256 HASH
src/Build/build_veracrypt_openwrt.sh --wx-version 3.2.10
```
Custom SDK URLs or unsupported OpenWrt release/target combinations must pass
`--sdk-sha256`; the build script does not trust an unsigned `sha256sums` file as
the sole integrity source for SDK archives.
If the host only has `mawk`, the build script downloads and builds GNU awk
locally under the OpenWrt work directory because OpenWrt feed scripts require
GNU awk behavior on some hosts.
## QEMU Runtime Test
Install or provide `qemu-system-x86_64`. On Debian/Ubuntu hosts:
```sh
sudo apt install qemu-system-x86
```
Then run:
```sh
python3 src/Build/test_veracrypt_openwrt_qemu.py \
--ipk ../openwrt-veracrypt/openwrt-sdk-24.10.6-x86-64_gcc-13.3.0_musl.Linux-x86_64/bin/packages/x86_64/base/veracrypt_<version>-r1_x86_64.ipk
```
The test script downloads and verifies the matching OpenWrt x86/64 ext4 image,
boots it with QEMU user networking, waits for OpenWrt network init to settle,
gets a DHCP lease on `br-lan` or `eth0`, resolves the needed dependency closure
from local SDK `.ipk` control metadata plus the official OpenWrt kmod feed,
serves those packages to the guest, and installs them with `opkg`. It then runs:
```sh
veracrypt --text --version
veracrypt --text --test
```
By default it also creates a 16 MiB AES/SHA-512 test container, opens it with
`--filesystem=none`, verifies it appears in `veracrypt --text --list`, and
unmounts it. Use `--skip-container` to run only the package install, version,
and algorithm self-test path.
If QEMU was extracted locally instead of installed system-wide, pass the binary
and firmware directory explicitly:
```sh
LD_LIBRARY_PATH=/path/to/qemu-libs \
python3 src/Build/test_veracrypt_openwrt_qemu.py \
--qemu /path/to/qemu-system-x86_64 \
--qemu-data-dir /path/to/pc-bios \
--ipk /path/to/veracrypt_<version>-r1_x86_64.ipk
```
The runner defaults to one QEMU vCPU because TCG with multiple vCPUs can
intermittently trip x86 APIC timer startup in the stock OpenWrt image.
The runner does not require external package feed access from the guest; all
runtime packages are served over the host-to-guest QEMU user-networking link.
Local userland packages come from the SDK `bin/` directory, while stock-image
kmods are downloaded by the host from the official OpenWrt kmod feed and staged
locally. If the VeraCrypt `.ipk` is not below the SDK `bin/` directory, pass
`--package-bin-dir /path/to/sdk/bin`.
For custom images whose kernel does not match the official release feed, pass
`--kmod-feed-url` for the matching kmod feed, or `--local-kmods` to resolve
kmods from `--package-bin-dir`.
The test log is written to:
```text
../openwrt-veracrypt/openwrt-qemu-test.log
```
## Runtime Packages
The VeraCrypt package itself declares the direct userland dependencies using
OpenWrt package symbols:
- `libstdcpp`
- `libfuse3`
- `bash`
OpenWrt's FUSE3 recipe defines `Package/libfuse3` with ABI version `3`, so the
binary IPK and package-index metadata are emitted as `libfuse3-3` while still
providing `libfuse3`. The QEMU test installs the seed runtime support normally
needed for useful mounts using package-index names:
- `libfuse3-3`
- `fuse3-utils`
- `kmod-fuse`
- `kmod-loop`
- `lvm2`
- `kmod-dm`
- `losetup`
- `blkid`
- `mount-utils`
- `kmod-crypto-misc`
The test resolver also stages required transitive dependencies from package
metadata, such as `libdevmapper` when pulled by `lvm2`.
Filesystem-specific mounts also need the corresponding OpenWrt filesystem
kernel modules and tools. Smart-card and EMV keyfile support should install
`libpcsclite`, `pcscd`, and the appropriate reader driver such as `ccid`; these
are optional and are not part of the base package dependency set.
@@ -0,0 +1,23 @@
CONFIG_TARGET_x86=y
CONFIG_TARGET_x86_64=y
# CONFIG_TARGET_MULTI_PROFILE is not set
# CONFIG_TARGET_ALL_PROFILES is not set
CONFIG_TARGET_DEVICE_x86_64_DEVICE_generic=y
# CONFIG_ALL is not set
# CONFIG_ALL_KMODS is not set
# CONFIG_ALL_NONSHARED is not set
# CONFIG_DEVEL is not set
CONFIG_PACKAGE_veracrypt=m
CONFIG_PACKAGE_bash=m
CONFIG_PACKAGE_libfuse3=m
CONFIG_PACKAGE_fuse3-utils=m
CONFIG_PACKAGE_kmod-fuse=m
CONFIG_PACKAGE_kmod-loop=m
CONFIG_PACKAGE_kmod-dm=m
CONFIG_PACKAGE_kmod-crypto-misc=m
CONFIG_PACKAGE_lvm2=m
CONFIG_PACKAGE_losetup=m
CONFIG_PACKAGE_blkid=m
CONFIG_PACKAGE_mount-utils=m
@@ -0,0 +1,90 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=veracrypt
PKG_VERSION:=@VERACRYPT_VERSION@
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0 AND LicenseRef-TrueCrypt
PKG_LICENSE_FILES:=veracrypt/src/License.txt
PKG_MAINTAINER:=Mounir IDRASSI <mounir.idrassi@amcrypto.jp>
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_PARALLEL:=1
PKG_BUILD_DEPENDS:=fuse3 pcsc-lite
VERACRYPT_STAGED_SOURCE:=sources/veracrypt
WXWIDGETS_STAGED_SOURCE:=sources/wxWidgets
include $(INCLUDE_DIR)/package.mk
RSTRIP:=:
STRIP:=:
define Package/veracrypt
SECTION:=utils
CATEGORY:=Utilities
SUBMENU:=Filesystem
TITLE:=VeraCrypt console
URL:=https://www.veracrypt.fr/
DEPENDS:=+libstdcpp +libfuse3 +bash
endef
define Package/veracrypt/description
Console-only VeraCrypt build for OpenWrt using FUSE3 and a static wxBase.
endef
define Build/Prepare
rm -rf "$(PKG_BUILD_DIR)"
$(INSTALL_DIR) "$(PKG_BUILD_DIR)"
rsync -a --delete \
--exclude .git \
--exclude 'src/wxrelease' \
--exclude 'src/wxdebug' \
--exclude 'src/Main/veracrypt' \
--exclude 'src/Setup/Linux/usr' \
--exclude '*.o' \
--exclude '*.d' \
--exclude '*.a' \
"$(VERACRYPT_STAGED_SOURCE)/" "$(PKG_BUILD_DIR)/veracrypt/"
rsync -a --delete "$(WXWIDGETS_STAGED_SOURCE)/" "$(PKG_BUILD_DIR)/wxWidgets/"
endef
define Build/Configure
endef
VC_COMMON_MAKE_FLAGS = \
AR="$(TARGET_AR)" \
CC="$(TARGET_CC)" \
CXX="$(TARGET_CXX)" \
AS="yasm" \
RANLIB="$(TARGET_RANLIB)" \
PKG_CONFIG="$(PKG_CONFIG)" \
PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" \
WX_ROOT="$(PKG_BUILD_DIR)/wxWidgets" \
WX_BUILD_DIR="$(PKG_BUILD_DIR)/wxBuildConsole" \
WX_CONFIGURE_EXTRA_FLAGS="--target=$(GNU_TARGET_NAME) --host=$(GNU_TARGET_NAME) --build=$(GNU_HOST_NAME) --prefix=/usr --exec-prefix=/usr --disable-rpath" \
TC_EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
TC_EXTRA_CXXFLAGS="$(TARGET_CXXFLAGS) $(TARGET_CPPFLAGS)" \
TC_EXTRA_LFLAGS="$(TARGET_LDFLAGS)" \
NOGUI=1 \
WITHFUSE3=1 \
WXSTATIC=1 \
NOTEST=1 \
NOSTRIP=1 \
VERBOSE=1
define Build/Compile
+$(MAKE) -C "$(PKG_BUILD_DIR)/veracrypt/src" $(VC_COMMON_MAKE_FLAGS) clean
+$(MAKE) -C "$(PKG_BUILD_DIR)/veracrypt/src" $(VC_COMMON_MAKE_FLAGS) wxbuild
+$(MAKE) -C "$(PKG_BUILD_DIR)/veracrypt/src" $(PKG_JOBS) $(VC_COMMON_MAKE_FLAGS)
endef
define Package/veracrypt/install
$(INSTALL_DIR) "$(1)/usr/bin"
$(INSTALL_BIN) "$(PKG_BUILD_DIR)/veracrypt/src/Main/veracrypt" "$(1)/usr/bin/veracrypt"
$(INSTALL_DIR) "$(1)/sbin"
$(INSTALL_BIN) "$(PKG_BUILD_DIR)/veracrypt/src/Setup/Linux/mount.veracrypt" "$(1)/sbin/mount.veracrypt"
$(INSTALL_DIR) "$(1)/usr/share/licenses/veracrypt"
$(INSTALL_DATA) "$(PKG_BUILD_DIR)/veracrypt/src/License.txt" "$(1)/usr/share/licenses/veracrypt/License.txt"
endef
$(eval $(call BuildPackage,veracrypt))
+452
View File
@@ -0,0 +1,452 @@
#!/bin/sh
#
# Copyright (c) 2026 AM Crypto
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
#
set -eu
umask 022
OPENWRT_VERSION=24.10.6
OPENWRT_TARGET=x86/64
WX_VERSION=3.2.10
WX_URL=
WX_SHA256=d66e929569947a4a5920699539089a9bda83a93e5f4917fb313a61f0c344b896
SDK_URL=
SDK_SHA256=
SDK_DIR=
FRESH_SDK=0
SCRIPT=$(readlink -f "$0")
SCRIPTPATH=$(dirname "$SCRIPT")
REPOROOT=$(readlink -f "$SCRIPTPATH/../..")
SOURCEPATH="$REPOROOT/src"
PARENTDIR=$(readlink -f "$SCRIPTPATH/../../..")
WORK_DIR="$PARENTDIR/openwrt-veracrypt"
JOBS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)
GAWK_VERSION=5.3.2
GAWK_URL="https://ftp.gnu.org/gnu/gawk/gawk-$GAWK_VERSION.tar.xz"
GAWK_SHA256=f8c3486509de705192138b00ef2c00bbbdd0e84c30d5c07d23fc73a9dc4cc9cc
usage() {
cat <<EOF
Usage: $(basename "$0") [options]
Build the VeraCrypt console-only OpenWrt package with the OpenWrt SDK.
Options:
--openwrt-version VERSION OpenWrt release to use (default: $OPENWRT_VERSION)
--target TARGET OpenWrt target/subtarget (default: $OPENWRT_TARGET)
--work-dir DIR Download/build workspace (default: $WORK_DIR)
--sdk-url URL SDK archive URL (auto-detected for x86/64)
--sdk-sha256 HASH SDK archive SHA-256 (required for custom SDKs)
--sdk-dir DIR Use an already extracted SDK directory
--fresh-sdk Re-extract the SDK before building
--wx-version VERSION wxWidgets version (default: $WX_VERSION)
--wx-url URL wxWidgets source archive URL
--wx-sha256 HASH wxWidgets source archive SHA-256
-j, --jobs N Parallel make jobs (default: host CPU count)
-h, --help Show this help
Only x86/64 is currently wired because it is the QEMU smoke-test target.
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
need_tool() {
command -v "$1" >/dev/null 2>&1 || die "Required tool '$1' was not found"
}
require_option_arg() {
[ $# -ge 2 ] || die "Option $1 requires an argument"
}
validate_version_token() {
name=$1
value=$2
case "$value" in
''|*[!A-Za-z0-9._+-]*)
die "$name must contain only letters, digits, '.', '_', '+', or '-'"
;;
esac
}
download_file() {
url=$1
out=$2
expected_sha=$3
tmp="$out.tmp.$$"
mkdir -p "$(dirname "$out")"
if [ -f "$out" ]; then
if [ -z "$expected_sha" ]; then
return
fi
actual_sha=$(sha256sum "$out" | awk '{print $1}')
if [ "$actual_sha" = "$expected_sha" ]; then
return
fi
echo "Checksum mismatch for existing $out; re-downloading" >&2
rm -f "$out"
fi
rm -f "$tmp"
echo "Downloading $url"
if ! wget -O "$tmp" "$url"; then
rm -f "$tmp"
die "Download failed: $url"
fi
if [ -n "$expected_sha" ]; then
actual_sha=$(sha256sum "$tmp" | awk '{print $1}')
if [ "$actual_sha" != "$expected_sha" ]; then
rm -f "$tmp"
die "SHA-256 mismatch for $out: expected $expected_sha, got $actual_sha"
fi
fi
mv "$tmp" "$out"
}
pinned_sdk_sha256() {
archive_name=$1
case "$OPENWRT_VERSION:$OPENWRT_TARGET:$archive_name" in
24.10.6:x86/64:openwrt-sdk-24.10.6-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst)
printf '%s\n' "9e398ea7efc098e4a986f97efff595e32d08c615fe356bcb3d885d7ad3a39ac0"
;;
esac
}
target_defaults() {
case "$OPENWRT_TARGET" in
x86/64)
OPENWRT_TARGET_SLUG=x86-64
OPENWRT_CONFIG="$REPOROOT/src/Build/Packaging/openwrt/configs/x86_64-minimal.config"
;;
*)
die "Unsupported target '$OPENWRT_TARGET'. Add a config under src/Build/Packaging/openwrt/configs first."
;;
esac
}
openwrt_base_url() {
printf 'https://downloads.openwrt.org/releases/%s/targets/%s\n' "$OPENWRT_VERSION" "$OPENWRT_TARGET"
}
resolve_sdk() {
if [ -n "$SDK_DIR" ]; then
SDK_DIR=$(readlink -f "$SDK_DIR")
[ -d "$SDK_DIR" ] || die "SDK directory does not exist: $SDK_DIR"
return
fi
base_url=$(openwrt_base_url)
mkdir -p "$WORK_DIR/downloads"
if [ -z "$SDK_URL" ]; then
index_file="$WORK_DIR/downloads/openwrt-$OPENWRT_VERSION-$OPENWRT_TARGET_SLUG-index.html"
wget -q -O "$index_file" "$base_url/"
sdk_archive=$(sed -n "s/.*href=\"\\(openwrt-sdk-$OPENWRT_VERSION-${OPENWRT_TARGET_SLUG}_[^\"]*\\.Linux-x86_64\\.tar\\.zst\\)\".*/\\1/p" "$index_file" | head -n 1)
[ -n "$sdk_archive" ] || die "Could not find an SDK archive at $base_url/"
SDK_URL="$base_url/$sdk_archive"
else
sdk_archive=$(basename "$SDK_URL")
fi
if [ -z "$SDK_SHA256" ]; then
SDK_SHA256=$(pinned_sdk_sha256 "$sdk_archive")
fi
[ -n "$SDK_SHA256" ] || die "No trusted SDK SHA-256 is available for $sdk_archive; pass --sdk-sha256 for custom SDKs"
SDK_ARCHIVE_PATH="$WORK_DIR/downloads/$sdk_archive"
download_file "$SDK_URL" "$SDK_ARCHIVE_PATH" "$SDK_SHA256"
sdk_top=$(zstd -dc "$SDK_ARCHIVE_PATH" | tar -tf - | sed -n '1{s,/.*,,;p;q;}')
[ -n "$sdk_top" ] || die "Could not determine SDK archive top-level directory"
SDK_DIR="$WORK_DIR/$sdk_top"
if [ "$FRESH_SDK" = "1" ]; then
rm -rf "$SDK_DIR"
fi
if [ ! -d "$SDK_DIR" ]; then
echo "Extracting $SDK_ARCHIVE_PATH"
zstd -dc "$SDK_ARCHIVE_PATH" | tar -xf - -C "$WORK_DIR"
fi
}
ensure_gawk() {
HOST_TOOLS="$WORK_DIR/host-tools"
if command -v gawk >/dev/null 2>&1; then
mkdir -p "$HOST_TOOLS/bin"
ln -sf "$(command -v gawk)" "$HOST_TOOLS/bin/gawk"
ln -sf "$(command -v gawk)" "$HOST_TOOLS/bin/awk"
return
fi
if [ -x "$HOST_TOOLS/prefix/bin/gawk" ]; then
mkdir -p "$HOST_TOOLS/bin"
ln -sf ../prefix/bin/gawk "$HOST_TOOLS/bin/gawk"
ln -sf ../prefix/bin/gawk "$HOST_TOOLS/bin/awk"
return
fi
need_tool make
if ! command -v gcc >/dev/null 2>&1 && ! command -v cc >/dev/null 2>&1; then
die "GNU awk is not installed and no C compiler was found to build it"
fi
mkdir -p "$HOST_TOOLS/src"
gawk_archive="$HOST_TOOLS/src/gawk-$GAWK_VERSION.tar.xz"
download_file "$GAWK_URL" "$gawk_archive" "$GAWK_SHA256"
rm -rf "$HOST_TOOLS/src/gawk-$GAWK_VERSION"
tar -xf "$gawk_archive" -C "$HOST_TOOLS/src"
echo "Building GNU awk $GAWK_VERSION for OpenWrt feed scripts"
(
cd "$HOST_TOOLS/src/gawk-$GAWK_VERSION"
./configure --prefix="$HOST_TOOLS/prefix" >/dev/null
make -j "$JOBS" >/dev/null
make install >/dev/null
)
mkdir -p "$HOST_TOOLS/bin"
ln -sf ../prefix/bin/gawk "$HOST_TOOLS/bin/gawk"
ln -sf ../prefix/bin/gawk "$HOST_TOOLS/bin/awk"
}
prepare_wxwidgets() {
if [ -z "$WX_URL" ]; then
WX_URL="https://github.com/wxWidgets/wxWidgets/releases/download/v$WX_VERSION/wxWidgets-$WX_VERSION.tar.bz2"
fi
wx_archive="$WORK_DIR/downloads/wxWidgets-$WX_VERSION.tar.bz2"
WX_SOURCE_DIR="$WORK_DIR/sources/wxWidgets-$WX_VERSION"
download_file "$WX_URL" "$wx_archive" "$WX_SHA256"
if [ ! -f "$WX_SOURCE_DIR/configure" ]; then
rm -rf "$WX_SOURCE_DIR"
mkdir -p "$WORK_DIR/sources"
echo "Extracting $wx_archive"
tar -xjf "$wx_archive" -C "$WORK_DIR/sources"
fi
}
sed_escape() {
printf '%s' "$1" | sed 's/[&|]/\\&/g'
}
assert_package_dir_outside_checkout() {
package_dir=$1
case "$package_dir/" in
"$REPOROOT"/*)
die "OpenWrt package directory is inside the VeraCrypt checkout; choose a --work-dir or --sdk-dir outside the repository"
;;
esac
}
stage_package_sources() {
package_dir=$1
staging_dir="$package_dir/sources"
assert_package_dir_outside_checkout "$package_dir"
rm -rf "$staging_dir"
mkdir -p "$staging_dir/veracrypt" "$staging_dir/wxWidgets"
rsync -a --delete \
--exclude .git \
--exclude 'src/wxrelease' \
--exclude 'src/wxdebug' \
--exclude 'src/Main/veracrypt' \
--exclude 'src/Setup/Linux/usr' \
--exclude '*.o' \
--exclude '*.d' \
--exclude '*.a' \
"$REPOROOT/" "$staging_dir/veracrypt/"
rsync -a --delete "$WX_SOURCE_DIR/" "$staging_dir/wxWidgets/"
}
render_package_makefile() {
version=$(sed -n 's/^#define[[:space:]][[:space:]]*VERSION_STRING[[:space:]][[:space:]]*"\([^"]*\)".*/\1/p' "$SOURCEPATH/Common/Tcdefs.h" | head -n 1)
[ -n "$version" ] || die "Could not determine VeraCrypt version from src/Common/Tcdefs.h"
validate_version_token "VeraCrypt version" "$version"
package_dir="$SDK_DIR/package/utils/veracrypt"
template="$REPOROOT/src/Build/Packaging/openwrt/package/utils/veracrypt/Makefile.in"
assert_package_dir_outside_checkout "$package_dir"
rm -rf "$package_dir"
mkdir -p "$package_dir"
stage_package_sources "$package_dir"
sed \
-e "s|@VERACRYPT_VERSION@|$(sed_escape "$version")|g" \
"$template" > "$package_dir/Makefile"
VERACRYPT_VERSION=$version
}
configure_sdk() {
[ -f "$OPENWRT_CONFIG" ] || die "Missing OpenWrt config seed: $OPENWRT_CONFIG"
cp "$OPENWRT_CONFIG" "$SDK_DIR/.config"
(
cd "$SDK_DIR"
if ! PATH="$HOST_TOOLS/bin:$PATH" ./scripts/feeds update packages base; then
echo "Feed update failed; removing stale feed checkouts and retrying" >&2
rm -rf feeds/base feeds/packages
PATH="$HOST_TOOLS/bin:$PATH" ./scripts/feeds update packages base
fi
PATH="$HOST_TOOLS/bin:$PATH" ./scripts/feeds install fuse3 lvm2 util-linux pcsc-lite bash
PATH="$HOST_TOOLS/bin:$PATH" make defconfig
)
}
build_package() {
(
cd "$SDK_DIR"
PATH="$HOST_TOOLS/bin:$PATH" make package/utils/veracrypt/clean V=s
PATH="$HOST_TOOLS/bin:$PATH" make package/utils/veracrypt/compile V=s -j "$JOBS"
)
IPK_PATH=$(find "$SDK_DIR/bin/packages" "$SDK_DIR/bin/targets" -name "veracrypt_${VERACRYPT_VERSION}-*.ipk" 2>/dev/null | sort | tail -n 1)
[ -n "$IPK_PATH" ] || die "Build completed but no VeraCrypt .ipk was found"
}
build_runtime_packages() {
(
cd "$SDK_DIR"
for target in \
package/feeds/packages/bash/compile \
package/feeds/packages/fuse3/compile \
package/feeds/base/util-linux/compile \
package/feeds/packages/lvm2/compile
do
echo "Building OpenWrt runtime dependency: $target"
PATH="$HOST_TOOLS/bin:$PATH" make "$target" V=s -j "$JOBS"
done
)
}
while [ $# -gt 0 ]; do
case "$1" in
--openwrt-version)
require_option_arg "$@"
OPENWRT_VERSION=$2
shift 2
;;
--target)
require_option_arg "$@"
OPENWRT_TARGET=$2
shift 2
;;
--work-dir)
require_option_arg "$@"
WORK_DIR=$(readlink -m "$2")
shift 2
;;
--sdk-url)
require_option_arg "$@"
SDK_URL=$2
shift 2
;;
--sdk-sha256)
require_option_arg "$@"
SDK_SHA256=$2
shift 2
;;
--sdk-dir)
require_option_arg "$@"
SDK_DIR=$2
shift 2
;;
--fresh-sdk)
FRESH_SDK=1
shift
;;
--wx-version)
require_option_arg "$@"
WX_VERSION=$2
shift 2
;;
--wx-url)
require_option_arg "$@"
WX_URL=$2
shift 2
;;
--wx-sha256)
require_option_arg "$@"
WX_SHA256=$2
shift 2
;;
-j|--jobs)
require_option_arg "$@"
JOBS=$2
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
die "Unknown option: $1"
;;
esac
done
case "$JOBS" in
''|*[!0-9]*)
die "jobs must be a positive integer"
;;
esac
[ "$JOBS" -gt 0 ] || die "jobs must be a positive integer"
validate_version_token "wxWidgets version" "$WX_VERSION"
need_tool awk
need_tool find
need_tool make
need_tool rsync
need_tool sed
need_tool sha256sum
need_tool tar
need_tool wget
need_tool yasm
need_tool zstd
mkdir -p "$WORK_DIR"
target_defaults
resolve_sdk
ensure_gawk
prepare_wxwidgets
render_package_makefile
configure_sdk
build_package
build_runtime_packages
echo
echo "OpenWrt release: $OPENWRT_VERSION $OPENWRT_TARGET"
if [ -n "$SDK_URL" ]; then
echo "OpenWrt SDK: $SDK_URL"
else
echo "OpenWrt SDK: existing directory supplied with --sdk-dir"
fi
echo "SDK directory: $SDK_DIR"
echo "wxWidgets: $WX_URL"
echo "VeraCrypt package: $IPK_PATH"
sha256sum "$IPK_PATH"
echo
echo "Run the QEMU runtime test with:"
echo " python3 \"$SCRIPTPATH/test_veracrypt_openwrt_qemu.py\" --ipk \"$IPK_PATH\" --work-dir \"$WORK_DIR\""
+864
View File
@@ -0,0 +1,864 @@
#!/usr/bin/env python3
#
# Copyright (c) 2026 AM Crypto
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
#
import argparse
import gzip
import hashlib
import http.server
import io
import lzma
import os
import re
import selectors
import shutil
import socketserver
import subprocess
import sys
import tarfile
import tempfile
import threading
import time
import urllib.parse
import urllib.request
from pathlib import Path
DEFAULT_OPENWRT_VERSION = "24.10.6"
DEFAULT_TARGET = "x86/64"
DEFAULT_PASSWORD = "OpenWrt-VeraCrypt-Test-Password-123456"
SHELL_PROMPT = ":~#"
PREINSTALLED_PACKAGES = {
"base-files",
"busybox",
"kernel",
"libc",
"libgcc1",
"libpthread",
"librt",
"opkg",
}
DEFAULT_RUNTIME_PACKAGES = [
"bash",
# OpenWrt emits the FUSE3 library IPK with its ABI suffix; it still
# Provides: libfuse3.
"libfuse3-3",
"fuse3-utils",
"lvm2",
"losetup",
"blkid",
"mount-utils",
"kmod-fuse",
"kmod-loop",
"kmod-dm",
"kmod-crypto-misc",
"veracrypt",
]
class TestError(Exception):
pass
class ReusableTCPServer(socketserver.TCPServer):
allow_reuse_address = True
class PackageMetadata:
def __init__(self, path, fields, url=None, source="local"):
self.path = path
self.url = url
self.source = source
self.package = fields.get("Package", "")
self.version = fields.get("Version", "")
self.filename = fields.get("Filename", "")
self.sha256sum = fields.get("SHA256sum", "")
self.depends = parse_depends(fields.get("Depends", ""))
self.provides = parse_name_list(fields.get("Provides", ""))
def identity(self):
if self.path:
return f"local:{self.path.resolve()}"
return f"remote:{self.url}"
def display_location(self):
return str(self.path) if self.path else self.url
def package_file_name(self):
if self.path:
return self.path.name
url_path = urllib.parse.urlparse(self.url).path
return Path(url_path).name
class Console:
def __init__(self, proc, log_path):
self.proc = proc
self.selector = selectors.DefaultSelector()
self.selector.register(proc.stdout, selectors.EVENT_READ)
os.set_blocking(proc.stdout.fileno(), False)
self.buffer = ""
self.log = open(log_path, "w", encoding="utf-8", errors="replace")
self.command_index = 0
def close(self):
self.log.close()
def _record(self, data):
text = data.decode("utf-8", errors="replace")
self.buffer += text
self.log.write(text)
self.log.flush()
sys.stdout.write(text)
sys.stdout.flush()
def send(self, text):
self.proc.stdin.write(text.encode("utf-8"))
self.proc.stdin.flush()
def read_until(self, patterns, timeout, start=0):
if isinstance(patterns, str):
patterns = [patterns]
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
tail = self.buffer[start:]
for pattern in patterns:
if pattern in tail:
return pattern
if self.proc.poll() is not None:
raise TestError(f"QEMU exited before seeing {patterns}")
events = self.selector.select(0.25)
for key, _ in events:
try:
data = os.read(key.fileobj.fileno(), 8192)
except BlockingIOError:
continue
if data:
self._record(data)
raise TestError(f"Timed out waiting for {patterns}")
def run(self, command, timeout=120):
self.command_index += 1
marker = f"__VC_STATUS_{self.command_index:03d}__"
start = len(self.buffer)
wrapped = (
f"printf '\\n__VC_BEGIN_{self.command_index:03d}__\\n'\n"
"{\n"
f"{command}\n"
"}\n"
f"echo {marker}:$?\n"
)
self.send(wrapped)
deadline = time.monotonic() + timeout
status_re = re.compile(rf"{re.escape(marker)}:(\d+)")
while time.monotonic() < deadline:
tail = self.buffer[start:]
match = status_re.search(tail)
if match:
self.read_until(SHELL_PROMPT, 60, start + match.end())
tail = self.buffer[start:]
status = int(match.group(1))
if status != 0:
raise TestError(f"Command failed with status {status}: {command}")
return tail
if self.proc.poll() is not None:
raise TestError(f"QEMU exited while running: {command}")
events = self.selector.select(0.25)
for key, _ in events:
try:
data = os.read(key.fileobj.fileno(), 8192)
except BlockingIOError:
continue
if data:
self._record(data)
raise TestError(f"Timed out running: {command}")
def target_info(target, version):
if target != "x86/64":
raise TestError("Only x86/64 is currently supported by this QEMU test")
return {
"slug": "x86-64",
"image": f"openwrt-{version}-x86-64-generic-ext4-combined.img.gz",
"manifest": f"openwrt-{version}-x86-64.manifest",
"base_url": f"https://downloads.openwrt.org/releases/{version}/targets/x86/64",
}
def sha256_file(path):
digest = hashlib.sha256()
with open(path, "rb") as fh:
for chunk in iter(lambda: fh.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def download(url, path, expected_sha256=None):
if path.exists() and expected_sha256:
actual_sha = sha256_file(path)
if actual_sha == expected_sha256:
return
print(f"Checksum mismatch for existing {path}; re-downloading", file=sys.stderr)
path.unlink()
elif path.exists():
return
path.parent.mkdir(parents=True, exist_ok=True)
tmp = path.with_name(f"{path.name}.tmp-{os.getpid()}")
if tmp.exists():
tmp.unlink()
print(f"Downloading {url}")
try:
with urllib.request.urlopen(url) as response, open(tmp, "wb") as out:
shutil.copyfileobj(response, out)
if expected_sha256:
actual_sha = sha256_file(tmp)
if actual_sha != expected_sha256:
raise TestError(f"SHA-256 mismatch for {path}: expected {expected_sha256}, got {actual_sha}")
tmp.replace(path)
finally:
if tmp.exists():
tmp.unlink()
def read_text_archive(path):
data = path.read_bytes()
if path.name.endswith(".gz"):
return gzip.decompress(data).decode("utf-8", errors="replace")
if path.name.endswith(".xz"):
return lzma.decompress(data).decode("utf-8", errors="replace")
return data.decode("utf-8", errors="replace")
def expected_sha_from_sums(sums_path, filename):
with open(sums_path, "r", encoding="utf-8") as fh:
for line in fh:
parts = line.split()
if len(parts) >= 2 and parts[1].lstrip("*") == filename:
return parts[0]
return None
def sh_quote(text):
return "'" + str(text).replace("'", "'\"'\"'") + "'"
def read_ar_control_archive(ipk_path):
with open(ipk_path, "rb") as fh:
magic = fh.read(8)
if magic != b"!<arch>\n":
raise TestError(f"Unsupported .ipk format for {ipk_path}")
while True:
header = fh.read(60)
if not header:
break
if len(header) != 60 or header[58:60] != b"`\n":
raise TestError(f"Malformed ar archive in {ipk_path}")
name = header[:16].decode("utf-8", errors="replace").strip().rstrip("/")
size = int(header[48:58].decode("ascii").strip())
data = fh.read(size)
if size % 2:
fh.read(1)
if Path(name).name.startswith("control.tar"):
return name, data
raise TestError(f"No control archive found in {ipk_path}")
def extract_top_level_control_archive(ipk_path):
with open(ipk_path, "rb") as fh:
magic = fh.read(8)
if magic == b"!<arch>\n":
return read_ar_control_archive(ipk_path)
try:
with tarfile.open(ipk_path, "r:*") as outer:
for member in outer:
if Path(member.name).name.startswith("control.tar"):
member_file = outer.extractfile(member)
if member_file:
return member.name, member_file.read()
except tarfile.TarError as exc:
raise TestError(f"Unsupported .ipk format for {ipk_path}: {exc}") from exc
raise TestError(f"No control archive found in {ipk_path}")
def open_control_tar(name, data):
try:
return tarfile.open(fileobj=io.BytesIO(data), mode="r:*")
except tarfile.TarError:
pass
if name.endswith(".zst"):
zstd = shutil.which("zstd")
if not zstd:
raise TestError(f"{name} is zstd-compressed, but zstd was not found")
result = subprocess.run([zstd, "-dc"], input=data, stdout=subprocess.PIPE, check=False)
if result.returncode != 0:
raise TestError(f"zstd failed while reading {name}")
return tarfile.open(fileobj=io.BytesIO(result.stdout), mode="r:")
if name.endswith(".gz"):
return tarfile.open(fileobj=io.BytesIO(gzip.decompress(data)), mode="r:")
if name.endswith(".xz"):
return tarfile.open(fileobj=io.BytesIO(lzma.decompress(data)), mode="r:")
raise TestError(f"Unsupported control archive compression: {name}")
def read_control_fields(ipk_path):
control_name, control_data = extract_top_level_control_archive(ipk_path)
with open_control_tar(control_name, control_data) as control_tar:
for member in control_tar:
if member.name in ("control", "./control") or member.name.endswith("/control"):
member_file = control_tar.extractfile(member)
if member_file:
text = member_file.read().decode("utf-8", errors="replace")
return parse_control_fields(text)
raise TestError(f"No control file found in {ipk_path}")
def parse_control_fields(text):
fields = {}
current = None
for line in text.splitlines():
if not line:
current = None
continue
if line[0].isspace() and current:
fields[current] += "\n" + line.strip()
continue
key, sep, value = line.partition(":")
if not sep:
continue
current = key
fields[key] = value.strip()
return fields
def parse_control_paragraphs(text):
paragraphs = []
lines = []
for line in text.splitlines():
if line.strip():
lines.append(line)
continue
if lines:
paragraphs.append(parse_control_fields("\n".join(lines)))
lines = []
if lines:
paragraphs.append(parse_control_fields("\n".join(lines)))
return paragraphs
def parse_package_name(text):
text = re.sub(r"\s*\([^)]*\)", "", text).strip()
return text.split()[0] if text else ""
def parse_depends(value):
groups = []
for item in value.replace("\n", " ").split(","):
alternatives = [parse_package_name(part) for part in item.split("|")]
alternatives = [name for name in alternatives if name]
if alternatives:
groups.append(alternatives)
return groups
def parse_name_list(value):
names = []
for item in value.replace("\n", " ").split(","):
name = parse_package_name(item)
if name:
names.append(name)
return names
def infer_package_bin_dir(ipk_path):
for parent in [ipk_path.parent] + list(ipk_path.parents):
if parent.name == "bin":
return parent
return ipk_path.parent
def read_package_metadata(ipk_path):
meta = PackageMetadata(ipk_path, read_control_fields(ipk_path))
if not meta.package:
raise TestError(f"Package metadata in {ipk_path} has no Package field")
return meta
def add_package_metadata(index, meta, override=False):
for name in [meta.package] + meta.provides:
if name and (override or name not in index):
index[name] = meta
def build_package_index(package_bin_dir, veracrypt_ipk, skip_local_kmods=False):
if not package_bin_dir.is_dir():
raise TestError(f"Package bin directory does not exist: {package_bin_dir}")
index = {}
for ipk in sorted(package_bin_dir.rglob("*.ipk")):
if skip_local_kmods and ipk.name.startswith("kmod-"):
continue
add_package_metadata(index, read_package_metadata(ipk))
add_package_metadata(index, read_package_metadata(veracrypt_ipk), override=True)
return index
def parse_packages_index(text, feed_url, source):
index = {}
feed_url = feed_url.rstrip("/") + "/"
for fields in parse_control_paragraphs(text):
package = fields.get("Package", "")
filename = fields.get("Filename", "")
if not package or not filename:
continue
url = urllib.parse.urljoin(feed_url, filename)
meta = PackageMetadata(None, fields, url=url, source=source)
add_package_metadata(index, meta)
return index
def download_packages_index(index_url, cache_path):
download(index_url, cache_path)
return read_text_archive(cache_path)
def official_index_cache_path(work_dir, info, name):
safe_name = re.sub(r"[^A-Za-z0-9._-]+", "_", name).strip("_")
return work_dir / "package-indexes" / info["slug"] / safe_name
def kmod_dir_from_kernel_version(version):
match = re.match(r"^([^~]+)~([0-9a-fA-F]+)-r([0-9A-Za-z_.+-]+)$", version)
if not match:
return None
linux_version, vermagic, release = match.groups()
return f"{linux_version}-{release}-{vermagic}"
def official_manifest_kernel_version(args, info):
manifest_url = f"{info['base_url']}/{info['manifest']}"
cache_path = official_index_cache_path(args.work_dir, info, info["manifest"])
download(manifest_url, cache_path)
manifest = read_text_archive(cache_path)
for line in manifest.splitlines():
name, sep, version = line.partition(" - ")
if sep and name == "kernel":
return version.strip()
return None
def discover_single_kmod_feed_url(info):
kmods_url = f"{info['base_url']}/kmods/"
print(f"Discovering OpenWrt kmod feed from {kmods_url}")
with urllib.request.urlopen(kmods_url) as response:
html = response.read().decode("utf-8", errors="replace")
candidates = sorted(set(re.findall(r'href="([^"/]+-[^"/]+-[0-9a-fA-F]+/)"', html)))
if len(candidates) == 1:
return urllib.parse.urljoin(kmods_url, candidates[0]).rstrip("/")
if not candidates:
raise TestError(f"Could not discover an OpenWrt kmod feed at {kmods_url}")
raise TestError(
"Multiple OpenWrt kmod feeds are available; pass --kmod-feed-url explicitly: "
+ ", ".join(urllib.parse.urljoin(kmods_url, candidate).rstrip("/") for candidate in candidates)
)
def resolve_official_kmod_feed_url(args, info):
if args.kmod_feed_url:
return args.kmod_feed_url.rstrip("/")
kernel_version = official_manifest_kernel_version(args, info)
if kernel_version:
kmod_dir = kmod_dir_from_kernel_version(kernel_version)
if kmod_dir:
return f"{info['base_url']}/kmods/{kmod_dir}"
return discover_single_kmod_feed_url(info)
def official_kmod_package_index(args):
info = target_info(args.target, args.openwrt_version)
feed_url = resolve_official_kmod_feed_url(args, info)
index_url = f"{feed_url}/Packages.gz"
cache_path = official_index_cache_path(args.work_dir, info, f"kmods-{Path(feed_url).name}-Packages.gz")
text = download_packages_index(index_url, cache_path)
index = parse_packages_index(text, feed_url, f"official kmods {feed_url}")
if not index:
raise TestError(f"No packages were found in OpenWrt kmod feed {index_url}")
return index, feed_url
def overlay_package_index(index, overlay):
seen = set()
for meta in overlay.values():
meta_key = meta.identity()
if meta_key in seen:
continue
seen.add(meta_key)
add_package_metadata(index, meta, override=True)
def resolve_runtime_packages(package_index, seed_packages):
resolved = []
resolved_paths = set()
visiting = set()
def visit(name, chain):
if name in PREINSTALLED_PACKAGES:
return
meta = package_index.get(name)
if not meta:
chain_text = " -> ".join(chain + [name])
raise TestError(f"Missing .ipk metadata for dependency '{name}' while resolving {chain_text}")
meta_key = meta.identity()
if meta_key in resolved_paths:
return
if meta_key in visiting:
return
visiting.add(meta_key)
for alternatives in meta.depends:
selected = None
for alternative in alternatives:
if alternative in PREINSTALLED_PACKAGES or alternative in package_index:
selected = alternative
break
if not selected:
chain_text = " -> ".join(chain + [meta.package])
raise TestError(
f"Missing .ipk metadata for dependency '{alternatives[0]}' required by {chain_text}"
)
visit(selected, chain + [meta.package])
visiting.remove(meta_key)
resolved_paths.add(meta_key)
resolved.append(meta)
for package in seed_packages:
visit(package, [])
return resolved
def staged_package_name(index, meta):
return f"{index:03d}-{meta.package_file_name()}"
def ensure_remote_package(meta, cache_dir):
if not meta.url:
raise TestError(f"Package {meta.package} has no local path or remote URL")
file_name = meta.package_file_name()
cache_name = f"{hashlib.sha256(meta.url.encode('utf-8')).hexdigest()[:12]}-{file_name}"
cached = cache_dir / cache_name
def verify_cached():
if meta.sha256sum and sha256_file(cached) != meta.sha256sum:
cached.unlink()
return False
return True
if cached.exists() and verify_cached():
return cached
download(meta.url, cached, meta.sha256sum)
if meta.sha256sum and sha256_file(cached) != meta.sha256sum:
raise TestError(f"SHA-256 mismatch for {cached} downloaded from {meta.url}")
return cached
def stage_packages(packages, directory, cache_dir):
directory.mkdir(parents=True, exist_ok=True)
cache_dir.mkdir(parents=True, exist_ok=True)
for index, meta in enumerate(packages):
source = meta.path if meta.path else ensure_remote_package(meta, cache_dir)
shutil.copy2(source, directory / staged_package_name(index, meta))
def package_download_command(packages, http_port):
lines = [
"set -e",
"rm -rf /tmp/veracrypt-ipks",
"mkdir -p /tmp/veracrypt-ipks",
]
for index, meta in enumerate(packages):
package_name = staged_package_name(index, meta)
url_path = urllib.parse.quote(package_name, safe="")
lines.append(
f"wget -O {sh_quote(f'/tmp/veracrypt-ipks/{package_name}')} "
f"{sh_quote(f'http://10.0.2.2:{http_port}/{url_path}')}"
)
lines.append("opkg install /tmp/veracrypt-ipks/*.ipk")
return "\n".join(lines)
def prepare_image(args):
if args.image:
image = Path(args.image).resolve()
if not image.exists():
raise TestError(f"Image does not exist: {image}")
return image
info = target_info(args.target, args.openwrt_version)
image_gz = args.work_dir / "images" / info["image"]
image = image_gz.with_suffix("")
sums = args.work_dir / "images" / f"sha256sums-{args.openwrt_version}-{info['slug']}"
download(f"{info['base_url']}/sha256sums", sums)
expected_sha = expected_sha_from_sums(sums, info["image"])
if not expected_sha:
raise TestError(f"Could not find {info['image']} in {sums}")
download(f"{info['base_url']}/{info['image']}", image_gz, expected_sha)
actual_sha = sha256_file(image_gz)
if actual_sha != expected_sha:
raise TestError(f"SHA-256 mismatch for {image_gz}: expected {expected_sha}, got {actual_sha}")
if not image.exists():
print(f"Extracting {image_gz}")
with open(image, "wb") as out:
result = subprocess.run(["gzip", "-cd", str(image_gz)], stdout=out)
if result.returncode not in (0, 2):
raise TestError(f"gzip failed while extracting {image_gz}")
return image
def start_http_server(directory, address, port):
handler = lambda *args, **kwargs: http.server.SimpleHTTPRequestHandler(
*args, directory=str(directory), **kwargs
)
server = ReusableTCPServer((address, port), handler)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
return server
def boot_qemu(args, image):
qemu = shutil.which(args.qemu) if os.sep not in args.qemu else args.qemu
if not qemu:
raise TestError("qemu-system-x86_64 was not found; install QEMU or pass --qemu")
netdev = "user,id=net0"
if args.ssh_port is not None:
netdev += f",hostfwd=tcp::{args.ssh_port}-:22"
qemu_cmd = [
qemu,
"-accel", args.accel,
"-M", "pc",
"-cpu", args.cpu,
"-m", args.memory,
"-smp", str(args.smp),
"-nographic",
"-drive", f"file={image},format=raw,if=virtio",
"-netdev", netdev,
"-device", "virtio-net-pci,netdev=net0",
]
if args.qemu_data_dir:
qemu_cmd[1:1] = ["-L", str(args.qemu_data_dir)]
print("Starting QEMU:")
print(" ".join(qemu_cmd))
return subprocess.Popen(
qemu_cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
def run_guest_tests(args, console, http_port, packages):
console.read_until(["Please press Enter", SHELL_PROMPT], args.boot_timeout)
prompt_start = len(console.buffer)
console.send("\n")
console.read_until(SHELL_PROMPT, 90, prompt_start)
console.run(
"sleep 20\n"
"if ip link show br-lan >/dev/null 2>&1; then NETDEV=br-lan; else NETDEV=eth0; fi\n"
"ip addr flush dev \"$NETDEV\" || true\n"
"ip link set \"$NETDEV\" up\n"
"udhcpc -n -q -t 10 -i \"$NETDEV\"\n"
"ip -4 addr show \"$NETDEV\"\n"
"ping -c 1 10.0.2.2",
timeout=120,
)
console.run(package_download_command(packages, http_port), timeout=900)
version_output = console.run("veracrypt --text --version", timeout=120)
if "VeraCrypt " not in version_output:
raise TestError("version command did not print a VeraCrypt version")
test_output = console.run("veracrypt --text --test", timeout=240)
if "Self-tests of all algorithms passed" not in test_output:
raise TestError("algorithm self-test did not report success")
if not args.skip_container:
quoted_container_size = sh_quote(args.container_size)
quoted_password = sh_quote(args.password)
console.run("dd if=/dev/urandom of=/tmp/vc-random.bin bs=1M count=1", timeout=120)
console.run(
"veracrypt --text --create /tmp/openwrt-test.hc "
f"--size={quoted_container_size} "
f"--password={quoted_password} "
"--encryption=AES --hash=SHA-512 --filesystem=none "
"--volume-type=normal --random-source=/tmp/vc-random.bin "
"--quick --force --non-interactive",
timeout=360,
)
console.run("mkdir -p /mnt/veracrypt-test", timeout=60)
console.run(
"veracrypt --text --mount /tmp/openwrt-test.hc /mnt/veracrypt-test "
f"--password={quoted_password} "
"--pim=0 --keyfiles='' --protect-hidden=no --filesystem=none --non-interactive",
timeout=240,
)
list_output = console.run("veracrypt --text --list", timeout=120)
if "/dev/mapper/veracrypt" not in list_output:
raise TestError("container did not appear in veracrypt --list output")
console.run("veracrypt --text --unmount /tmp/openwrt-test.hc", timeout=180)
def parse_args():
parser = argparse.ArgumentParser(description="Boot OpenWrt in QEMU and test a VeraCrypt .ipk")
parser.add_argument("--ipk", required=True, type=Path, help="Path to veracrypt_*.ipk")
parser.add_argument(
"--package-bin-dir",
type=Path,
help="SDK bin directory containing local dependency .ipk files; defaults to the nearest bin parent of --ipk",
)
parser.add_argument("--openwrt-version", default=DEFAULT_OPENWRT_VERSION)
parser.add_argument("--target", default=DEFAULT_TARGET)
parser.add_argument("--work-dir", type=Path, default=None)
parser.add_argument("--image", type=Path, help="Use an already extracted OpenWrt raw image")
parser.add_argument("--qemu", default="qemu-system-x86_64")
parser.add_argument("--qemu-data-dir", type=Path, help="QEMU pc-bios directory for locally extracted QEMU builds")
parser.add_argument("--accel", default="tcg")
parser.add_argument("--cpu", default="max")
parser.add_argument("--memory", default="512M")
parser.add_argument("--smp", default=1, type=int)
parser.add_argument(
"--ssh-port",
type=int,
metavar="PORT",
help="Forward host TCP PORT to guest SSH; disabled by default",
)
parser.add_argument("--http-port", default=0, type=int)
parser.add_argument(
"--http-bind-address",
default="127.0.0.1",
help="Host address for the temporary package server (default: 127.0.0.1)",
)
parser.add_argument(
"--kmod-feed-url",
help="OpenWrt kmod feed URL; defaults to the official feed matching --openwrt-version and --target",
)
parser.add_argument(
"--local-kmods",
action="store_true",
help="Resolve kmod-* packages from --package-bin-dir instead of the official OpenWrt kmod feed",
)
parser.add_argument("--boot-timeout", default=180, type=int)
parser.add_argument("--container-size", default="16M")
parser.add_argument("--password", default=DEFAULT_PASSWORD)
parser.add_argument("--skip-container", action="store_true")
parser.add_argument("--keep-image", action="store_true")
return parser.parse_args()
def main():
args = parse_args()
args.ipk = args.ipk.resolve()
if not args.ipk.exists():
raise TestError(f"Package does not exist: {args.ipk}")
if args.package_bin_dir is None:
args.package_bin_dir = infer_package_bin_dir(args.ipk)
args.package_bin_dir = args.package_bin_dir.resolve()
repo_root = Path(__file__).resolve().parents[2]
if args.work_dir is None:
args.work_dir = repo_root.parent / "openwrt-veracrypt"
args.work_dir = args.work_dir.resolve()
args.work_dir.mkdir(parents=True, exist_ok=True)
package_index = build_package_index(
args.package_bin_dir,
args.ipk,
skip_local_kmods=not args.local_kmods,
)
if not args.local_kmods:
kmod_index, kmod_feed_url = official_kmod_package_index(args)
overlay_package_index(package_index, kmod_index)
print(f"Using OpenWrt kmod feed: {kmod_feed_url}")
packages = resolve_runtime_packages(package_index, DEFAULT_RUNTIME_PACKAGES)
print("Resolved OpenWrt packages:")
for index, meta in enumerate(packages):
print(f" {index:02d} {meta.package}: {meta.display_location()}")
base_image = prepare_image(args)
test_image = args.work_dir / "images" / f"{base_image.stem}-veracrypt-test.img"
test_image.parent.mkdir(parents=True, exist_ok=True)
if test_image.exists():
test_image.unlink()
shutil.copyfile(base_image, test_image)
with tempfile.TemporaryDirectory(prefix="veracrypt-ipks-", dir=args.work_dir) as package_dir:
server_root = Path(package_dir)
stage_packages(packages, server_root, args.work_dir / "package-cache")
server = start_http_server(server_root, args.http_bind_address, args.http_port)
http_port = server.server_address[1]
print(f"Serving staged packages from {server_root} on http://{args.http_bind_address}:{http_port}/")
log_path = args.work_dir / "openwrt-qemu-test.log"
proc = None
console = None
try:
proc = boot_qemu(args, test_image)
console = Console(proc, log_path)
run_guest_tests(args, console, http_port, packages)
console.send("poweroff\n")
try:
proc.wait(timeout=90)
except subprocess.TimeoutExpired:
proc.terminate()
proc.wait(timeout=30)
finally:
server.shutdown()
server.server_close()
if console:
console.close()
if proc and proc.poll() is None:
proc.terminate()
if not args.keep_image and test_image.exists():
test_image.unlink()
print()
print("OpenWrt QEMU test passed")
print(f"Log: {log_path}")
if __name__ == "__main__":
try:
main()
except TestError as exc:
print(f"Error: {exc}", file=sys.stderr)
sys.exit(1)
+2 -2
View File
@@ -27,8 +27,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+6
View File
@@ -5043,6 +5043,12 @@ namespace VeraCrypt
EfiBootInst.PrepareBootPartition();
if (!EfiBootInst.FileExists (szStdMsBootloader))
{
Error ("WINDOWS_EFI_BOOT_LOADER_MISSING", ParentWindow);
throw UserAbort (SRC_POS);
}
EfiBootInst.GetFileSize(szStdMsBootloader, loaderSize);
bootLoaderBuf.resize ((size_t) loaderSize);
EfiBootInst.ReadFile(szStdMsBootloader, &bootLoaderBuf[0], (DWORD) loaderSize);
+2 -2
View File
@@ -801,7 +801,8 @@ int EAGetLargestKeyForMode (int mode)
return key;
}
// Returns the maximum number of bytes necessary to be generated by the PBKDF2 (PKCS #5)
// Returns the maximum number of bytes necessary to be generated by PBKDF2 (PKCS #5).
// Argon2id header key material uses the fixed ARGON2_HEADER_KEYDATA_SIZE value.
int GetMaxPkcs5OutSize (void)
{
int size = 32;
@@ -1488,4 +1489,3 @@ void VcUnprotectKeys (PCRYPTO_INFO pCryptoInfo, uint64 encID)
#endif
#endif
+6
View File
@@ -44,6 +44,12 @@ extern "C" {
// Size of the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode)
#define MASTER_KEYDATA_SIZE 256
#ifndef VC_DCS_DISABLE_ARGON2
// VeraCrypt Argon2id header key material size, in bytes, for the current volume format.
// This is intentionally fixed for compatibility and must not depend on GetMaxPkcs5OutSize().
#define ARGON2_HEADER_KEYDATA_SIZE 192
#endif
// The first PRF to try when mounting
#define FIRST_PRF_ID 1
+1 -1
View File
@@ -6570,7 +6570,7 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
case ARGON2:
/* test with ARGON2 used as the PRF */
if (derive_key_argon2 ((const unsigned char*) "passphrase-1234567890", 21, (const unsigned char*)tmp_salt, 64, iterations, memoryCost, dk, MASTER_KEYDATA_SIZE, NULL) != 0)
if (derive_key_argon2 ((const unsigned char*) "passphrase-1234567890", 21, (const unsigned char*)tmp_salt, 64, iterations, memoryCost, dk, ARGON2_HEADER_KEYDATA_SIZE, NULL) != 0)
goto key_derivation_error;
break;
}
+1 -1
View File
@@ -277,7 +277,7 @@ static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
case ARGON2:
derivationResult = derive_key_argon2(workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.Memorycost, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize(), workItem->KeyDerivation.pAbortKeyDerivation);
workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.Memorycost, workItem->KeyDerivation.DerivedKey, ARGON2_HEADER_KEYDATA_SIZE, workItem->KeyDerivation.pAbortKeyDerivation);
break;
default:
+5 -1
View File
@@ -7,12 +7,16 @@ namespace VeraCrypt
SCardManager::SCardManager()
{
#ifndef TC_OPENBSD
loader->Initialize();
#endif
}
SCardManager::~SCardManager()
{
#ifndef TC_OPENBSD
loader->Finalize();
#endif
}
vector<wstring> SCardManager::GetReaders()
@@ -106,4 +110,4 @@ namespace VeraCrypt
throw InvalidEMVPath();
}
}
}
+1 -1
View File
@@ -220,7 +220,7 @@ namespace VeraCrypt
throw;
}
for(const CK_OBJECT_HANDLE & dataHandle: GetObjects(slotId, CKO_DATA))
foreach(const CK_OBJECT_HANDLE & dataHandle, GetObjects(slotId, CKO_DATA))
{
SecurityTokenKeyfile keyfile;
keyfile.Handle = dataHandle;
+17 -2
View File
@@ -448,7 +448,7 @@ KeyReady: ;
case ARGON2:
{
int derivationResult = derive_key_argon2(keyInfo->userKey, keyInfo->keyLength, keyInfo->salt,
PKCS5_SALT_SIZE, keyInfo->noIterations, keyInfo->memoryCost, dk, GetMaxPkcs5OutSize(), &abortKeyDerivation);
PKCS5_SALT_SIZE, keyInfo->noIterations, keyInfo->memoryCost, dk, ARGON2_HEADER_KEYDATA_SIZE, &abortKeyDerivation);
if (derivationResult != 0)
{
if (selected_pkcs5_prf == 0)
@@ -492,6 +492,12 @@ KeyReady: ;
if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode))
continue; // This encryption algorithm has never been available with this mode of operation
#ifndef VC_DCS_DISABLE_ARGON2
/* Only XTS mode reaches this point; both XTS keys must fit in the fixed Argon2id output. */
if (pkcs5_prf == ARGON2 && EAGetKeySize (cryptoInfo->ea) * 2 > ARGON2_HEADER_KEYDATA_SIZE)
continue;
#endif
blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea));
status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks);
@@ -1074,6 +1080,15 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, unsigned char *header,
// User selected encryption algorithm
cryptoInfo->ea = ea;
#ifndef VC_DCS_DISABLE_ARGON2
if (pkcs5_prf == ARGON2 && EAGetKeySize (ea) * 2 > ARGON2_HEADER_KEYDATA_SIZE)
{
crypto_close (cryptoInfo);
retVal = ERR_PARAMETER_INCORRECT;
goto err;
}
#endif
// User selected PRF
cryptoInfo->pkcs5 = pkcs5_prf;
cryptoInfo->noIterations = keyInfo.noIterations;
@@ -1130,7 +1145,7 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, unsigned char *header,
case ARGON2:
{
int derivationResult = derive_key_argon2(keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
PKCS5_SALT_SIZE, keyInfo.noIterations, keyInfo.memoryCost, dk, GetMaxPkcs5OutSize(), NULL);
PKCS5_SALT_SIZE, keyInfo.noIterations, keyInfo.memoryCost, dk, ARGON2_HEADER_KEYDATA_SIZE, NULL);
if (derivationResult != 0)
{
crypto_close (cryptoInfo);
+2 -2
View File
@@ -53,7 +53,7 @@ namespace VeraCrypt
RandomNumberGenerator::SetHash (newPkcs5Kdf->GetHash());
SecureBuffer newSalt (openVolume->GetSaltSize());
SecureBuffer newHeaderKey (VolumeHeader::GetLargestSerializedKeySize());
SecureBuffer newHeaderKey (VolumeHeader::GetHeaderKeyDerivationSize (newPkcs5Kdf));
shared_ptr <VolumePassword> password (Keyfile::ApplyListToPassword (newKeyfiles, newPassword, emvSupportEnabled));
@@ -286,7 +286,7 @@ namespace VeraCrypt
RandomNumberGenerator::SetHash (pkcs5Kdf->GetHash());
SecureBuffer newSalt (header->GetSaltSize());
SecureBuffer newHeaderKey (VolumeHeader::GetLargestSerializedKeySize());
SecureBuffer newHeaderKey (VolumeHeader::GetHeaderKeyDerivationSize (pkcs5Kdf));
shared_ptr <VolumePassword> passwordKey (Keyfile::ApplyListToPassword (keyfiles, password, emvSupportEnabled));
+39 -4
View File
@@ -21,6 +21,9 @@
#ifdef TC_LINUX
#include <sys/utsname.h>
#endif
#ifdef TC_OPENBSD
#include <pwd.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include "Platform/FileStream.h"
@@ -40,6 +43,26 @@ namespace VeraCrypt
static bool SamePath (const string& path1, const string& path2);
#endif
#ifdef TC_OPENBSD
static bool GetDoasUserIds (uid_t *uid, gid_t *gid)
{
const char *env = getenv ("DOAS_USER");
if (!env || !env[0])
return false;
struct passwd *pw = getpwnam (env);
if (!pw)
return false;
if (uid)
*uid = pw->pw_uid;
if (gid)
*gid = pw->pw_gid;
return true;
}
#endif
// Struct to hold terminal emulator information
struct TerminalInfo {
const char* name;
@@ -634,6 +657,12 @@ namespace VeraCrypt
catch (...) { }
}
#ifdef TC_OPENBSD
gid_t doasGid;
if (GetDoasUserIds (nullptr, &doasGid))
return doasGid;
#endif
return getgid();
}
@@ -650,6 +679,12 @@ namespace VeraCrypt
catch (...) { }
}
#ifdef TC_OPENBSD
uid_t doasUid;
if (GetDoasUserIds (&doasUid, nullptr))
return doasUid;
#endif
return getuid();
}
@@ -1405,8 +1440,8 @@ namespace VeraCrypt
while (getline(ss, token, ':'))
{
// remove any trailing slashes from the token
while (!token.empty() && token.back() == '/')
token.pop_back();
while (!token.empty() && token[token.length() - 1] == '/')
token.erase(token.length() - 1);
if (token.empty())
continue;
@@ -1424,8 +1459,8 @@ namespace VeraCrypt
free(resolvedEntry);
// remove any trailing slashes from the token
while (!entryPath.empty() && entryPath.back() == '/')
entryPath.pop_back();
while (!entryPath.empty() && entryPath[entryPath.length() - 1] == '/')
entryPath.erase(entryPath.length() - 1);
// perform check again if the resolved path is different from the original (symlink)
if (dirPath == entryPath || dirPath.find(entryPath + "/") == 0)
+21 -2
View File
@@ -253,7 +253,17 @@ namespace VeraCrypt
(options->Path.IsDevice() || options->Type == VolumeType::Hidden) ? File::OpenReadWrite : File::CreateReadWrite,
File::ShareNone);
HostSize = VolumeFile->Length();
if (!options->Path.IsDevice() && options->Type == VolumeType::Normal)
{
HostSize = options->Size;
if (options->Quick)
VolumeFile->SetLength (options->Size);
}
else
{
HostSize = VolumeFile->Length();
}
}
try
@@ -272,6 +282,9 @@ namespace VeraCrypt
{
throw UnsupportedSectorSize (SRC_POS);
}
if (HostSize % options->SectorSize != 0)
throw ParameterIncorrect (SRC_POS);
}
else
options->SectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME;
@@ -315,6 +328,12 @@ namespace VeraCrypt
if (headerOptions.VolumeDataSize < 1)
throw ParameterIncorrect (SRC_POS);
#ifndef VC_DCS_DISABLE_ARGON2
// New volumes are created in XTS mode; Argon2id header key material has a fixed format size.
if (options->VolumeHeaderKdf->IsArgon2() && options->EA->GetKeySize() * 2 > ARGON2_HEADER_KEYDATA_SIZE)
throw ParameterIncorrect (SRC_POS);
#endif
// Master data key
MasterKey.Allocate (options->EA->GetKeySize() * 2);
RandomNumberGenerator::GetData (MasterKey);
@@ -331,7 +350,7 @@ namespace VeraCrypt
headerOptions.Salt = salt;
// Header key
HeaderKey.Allocate (VolumeHeader::GetLargestSerializedKeySize());
HeaderKey.Allocate (VolumeHeader::GetHeaderKeyDerivationSize (options->VolumeHeaderKdf));
PasswordKey = Keyfile::ApplyListToPassword (options->Keyfiles, options->Password, options->EMVSupportEnabled);
int derivationResult = options->VolumeHeaderKdf->DeriveKey (HeaderKey, *PasswordKey, options->Pim, salt);
if (derivationResult != 0)
+2
View File
@@ -26,6 +26,8 @@
#if defined(__AVX2__)
#include <immintrin.h>
#include "blake2/blake2b.h"
#include "blake2/blamka-round-opt.h"
+2 -2
View File
@@ -27,8 +27,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+9 -9
View File
@@ -111,8 +111,8 @@
<Inf>
<ProviderName>
</ProviderName>
<TimeStamp>1.26.28.0</TimeStamp>
<DateStamp>04/30/2026</DateStamp>
<TimeStamp>1.26.28.1</TimeStamp>
<DateStamp>05/22/2026</DateStamp>
</Inf>
<Link>
<AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib</AdditionalDependencies>
@@ -139,8 +139,8 @@ copy $(OutDir)veracrypt.inf "$(SolutionDir)Debug\Setup Files\veracrypt.inf"</Com
<Inf>
<ProviderName>
</ProviderName>
<TimeStamp>1.26.28.0</TimeStamp>
<DateStamp>04/30/2026</DateStamp>
<TimeStamp>1.26.28.1</TimeStamp>
<DateStamp>05/22/2026</DateStamp>
</Inf>
<Link>
<AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib</AdditionalDependencies>
@@ -166,8 +166,8 @@ copy $(OutDir)veracrypt.inf "$(SolutionDir)Release\Setup Files\veracrypt.inf"</C
<Inf>
<ProviderName>
</ProviderName>
<TimeStamp>1.26.28.0</TimeStamp>
<DateStamp>04/30/2026</DateStamp>
<TimeStamp>1.26.28.1</TimeStamp>
<DateStamp>05/22/2026</DateStamp>
</Inf>
<Link>
<AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib</AdditionalDependencies>
@@ -193,15 +193,15 @@ copy $(OutDir)veracrypt.inf "$(SolutionDir)Release\Setup Files\veracrypt.inf"</C
<Inf>
<ProviderName>
</ProviderName>
<TimeStamp>1.26.28.0</TimeStamp>
<DateStamp>04/30/2026</DateStamp>
<TimeStamp>1.26.28.1</TimeStamp>
<DateStamp>05/22/2026</DateStamp>
</Inf>
<Link>
<AdditionalDependencies>fltmgr.lib;%(AdditionalDependencies);$(KernelBufferOverflowLib);$(DDK_LIB_PATH)ntoskrnl.lib;$(DDK_LIB_PATH)hal.lib;$(DDK_LIB_PATH)wmilib.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfLdr.lib;$(KMDF_LIB_PATH)$(KMDF_VER_PATH)\WdfDriverEntry.lib</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy $(OutDir)veracrypt.sys "$(SolutionDir)Debug\Setup Files\veracrypt-arm64.sys"
copy $(OutDir)veracrypt.pdb "$(SolutionDir\Debug\Setup Files\veracrypt-arm64.pdb"
copy $(OutDir)veracrypt.pdb "$(SolutionDir)Debug\Setup Files\veracrypt-arm64.pdb"
copy $(OutDir)vc143.pdb "$(SolutionDir)Debug\Setup Files\vc143-arm64.pdb"
copy $(OutDir)veracrypt.inf "$(SolutionDir)Debug\Setup Files\veracrypt.inf"</Command>
</PostBuildEvent>
+63 -2
View File
@@ -249,7 +249,7 @@ static void OnItemCompleted (EncryptedIoQueueItem *item, BOOL freeItem)
DecrementOutstandingIoCount (item->Queue);
IoReleaseRemoveLock (&item->Queue->RemoveLock, item->OriginalIrp);
if (NT_SUCCESS (item->Status))
if (NT_SUCCESS (item->Status) && !item->Flush)
{
if (item->Write)
item->Queue->TotalBytesWritten += item->OriginalLength;
@@ -630,6 +630,29 @@ static VOID IoThreadProc (PVOID threadArg)
InterlockedDecrement (&queue->IoThreadPendingRequestCount);
request = CONTAINING_RECORD (listEntry, EncryptedIoRequest, ListEntry);
if (request->Item->Flush)
{
#ifdef TC_TRACE_IO_QUEUE
Dump ("F [%I64d]\n", GetElapsedTime (&queue->LastPerformanceCounter));
#endif
if (NT_SUCCESS (request->Item->Status))
{
if (queue->HostFileHandle)
{
IO_STATUS_BLOCK ioStatus;
request->Item->Status = ZwFlushBuffersFile (queue->HostFileHandle, &ioStatus);
}
else
{
request->Item->Status = STATUS_DEVICE_NOT_READY;
}
}
HandleCompleteOriginalIrp (queue, request);
ReleasePoolBuffer (queue, request);
continue;
}
#ifdef TC_TRACE_IO_QUEUE
Dump ("%c %I64d [%I64d] roff=%I64d rlen=%d\n", request->Item->Write ? 'W' : 'R', request->Item->OriginalIrpOffset.QuadPart, GetElapsedTime (&queue->LastPerformanceCounter), request->Offset.QuadPart, request->Length);
#endif
@@ -832,6 +855,7 @@ static VOID MainThreadProc (PVOID threadArg)
item->OriginalIrp = irp;
item->TempUserMdl = NULL;
item->Status = STATUS_SUCCESS;
item->Flush = FALSE;
IoAcquireCancelSpinLock(&irql);
(PDRIVER_CANCEL)IoSetCancelRoutine(irp, NULL);
@@ -858,6 +882,13 @@ static VOID MainThreadProc (PVOID threadArg)
item->OriginalLength = irpSp->Parameters.Write.Length;
break;
case IRP_MJ_FLUSH_BUFFERS:
item->Write = FALSE;
item->Flush = TRUE;
item->OriginalOffset.QuadPart = 0;
item->OriginalLength = 0;
break;
default:
// Defer completion for invalid parameter
QueueIrpCompletionFromItem(queue, item, STATUS_INVALID_PARAMETER);
@@ -868,6 +899,32 @@ static VOID MainThreadProc (PVOID threadArg)
item->OriginalIrpOffset = item->OriginalOffset;
#endif
if (item->Flush)
{
InterlockedIncrement (&queue->IoThreadPendingRequestCount);
request = GetPoolBuffer (queue, sizeof (EncryptedIoRequest));
if (!request)
{
InterlockedDecrement (&queue->IoThreadPendingRequestCount);
QueueIrpCompletionFromItem (queue, item, STATUS_INSUFFICIENT_RESOURCES);
continue;
}
request->Item = item;
request->CompleteOriginalIrp = TRUE;
request->Offset.QuadPart = 0;
request->Data = NULL;
request->OrigDataBufferFragment = NULL;
request->Length = 0;
request->EncryptedOffset = 0;
request->EncryptedLength = 0;
ExInterlockedInsertTailList (&queue->IoThreadQueue, &request->ListEntry, &queue->IoThreadQueueLock);
KeSetEvent (&queue->IoThreadQueueNotEmptyEvent, IO_DISK_INCREMENT, FALSE);
continue;
}
// Handle misaligned read operations to work around a bug in Windows System Assessment Tool which does not follow FILE_FLAG_NO_BUFFERING requirements when benchmarking disk devices
if (queue->IsFilterDevice
&& !item->Write
@@ -1155,7 +1212,11 @@ NTSTATUS EncryptedIoQueueAddIrp (EncryptedIoQueue *queue, PIRP irp)
#ifdef TC_TRACE_IO_QUEUE
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
Dump ("* %I64d [%I64d] %c len=%d out=%d\n", irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.ByteOffset : irpSp->Parameters.Read.ByteOffset, GetElapsedTime (&queue->LastPerformanceCounter), irpSp->MajorFunction == IRP_MJ_WRITE ? 'W' : 'R', irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.Length : irpSp->Parameters.Read.Length, queue->OutstandingIoCount);
if (irpSp->MajorFunction == IRP_MJ_FLUSH_BUFFERS)
Dump ("* F [%I64d] out=%d\n", GetElapsedTime (&queue->LastPerformanceCounter), queue->OutstandingIoCount);
else
Dump ("* %I64d [%I64d] %c len=%d out=%d\n", irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.ByteOffset : irpSp->Parameters.Read.ByteOffset, GetElapsedTime (&queue->LastPerformanceCounter), irpSp->MajorFunction == IRP_MJ_WRITE ? 'W' : 'R', irpSp->MajorFunction == IRP_MJ_WRITE ? irpSp->Parameters.Write.Length : irpSp->Parameters.Read.Length, queue->OutstandingIoCount);
}
#endif
+1
View File
@@ -155,6 +155,7 @@ typedef struct
EncryptedIoQueue *Queue;
PIRP OriginalIrp;
BOOL Write;
BOOL Flush;
ULONG OriginalLength;
LARGE_INTEGER OriginalOffset;
NTSTATUS Status;
+35
View File
@@ -40,6 +40,9 @@
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#ifdef TC_OPENBSD
#include <pwd.h>
#endif
#include <sys/mman.h>
#include <sys/statvfs.h>
#include <sys/time.h>
@@ -65,6 +68,26 @@ namespace VeraCrypt
static const uint64 VC_FUSE_METADATA_SIZE = 64 * 1024;
static const uint64 VC_FUSE_STAT_BLOCK_SIZE = 512;
#ifdef TC_OPENBSD
static bool fuse_service_get_doas_user_ids (uid_t *uid, gid_t *gid)
{
const char *env = getenv ("DOAS_USER");
if (!env || !env[0])
return false;
struct passwd *pw = getpwnam (env);
if (!pw)
return false;
if (uid)
*uid = pw->pw_uid;
if (gid)
*gid = pw->pw_gid;
return true;
}
#endif
static uint64 fuse_service_ceil_div (uint64 value, uint64 divisor)
{
return (value / divisor) + ((value % divisor) ? 1 : 0);
@@ -790,6 +813,18 @@ namespace VeraCrypt
}
catch (...) { }
}
#ifdef TC_OPENBSD
else
{
uid_t doasUid;
gid_t doasGid;
if (fuse_service_get_doas_user_ids (&doasUid, &doasGid))
{
FuseService::UserId = doasUid;
FuseService::GroupId = doasGid;
}
}
#endif
static fuse_operations fuse_service_oper;
+12 -1
View File
@@ -621,7 +621,18 @@ NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp)
return STATUS_PENDING;
case IRP_MJ_FLUSH_BUFFERS:
return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
if (Extension->hDeviceFile == NULL || Extension->bReadOnly)
return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
if (!EncryptedIoQueueIsRunning (&Extension->Queue))
return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
ntStatus = EncryptedIoQueueAddIrp (&Extension->Queue, Irp);
if (ntStatus != STATUS_PENDING)
TCCompleteDiskIrp (Irp, ntStatus, 0);
return ntStatus;
}
break;
+7
View File
@@ -909,6 +909,13 @@ void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
{
RestoreTimeStamp (Extension);
}
if (!Extension->bReadOnly)
{
IO_STATUS_BLOCK ioStatus;
NTSTATUS flushStatus = ZwFlushBuffersFile (Extension->hDeviceFile, &ioStatus);
if (!NT_SUCCESS (flushStatus))
Dump ("ZwFlushBuffersFile failed before closing volume: NTSTATUS 0x%08x\n", flushStatus);
}
ZwClose (Extension->hDeviceFile);
Extension->hDeviceFile = NULL;
}
+2 -2
View File
@@ -192,8 +192,8 @@ IDR_MOUNT_RSRC_HEADER HEADER "resource.h"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+2 -2
View File
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+2 -2
View File
@@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+6 -1
View File
@@ -48,6 +48,11 @@ namespace VeraCrypt
MainFrame::MainFrame (wxWindow* parent) : MainFrameBase (parent),
#ifdef HAVE_INDICATORS
indicator (NULL),
indicator_item_showhide (NULL),
indicator_item_mountfavorites (NULL),
indicator_item_dismountall (NULL),
indicator_item_prefs (NULL),
indicator_item_exit (NULL),
#endif
ListItemRightClickEventPending (false),
SelectedItemIndex (-1),
@@ -1445,7 +1450,7 @@ namespace VeraCrypt
try
{
uint8 buf[128];
if (read (ShowRequestFifo, buf, sizeof (buf)) > 0 && Gui->IsInBackgroundMode())
if (read (ShowRequestFifo, buf, sizeof (buf)) > 0)
Gui->SetBackgroundMode (false);
}
catch (...)
+13 -1
View File
@@ -22,6 +22,9 @@
#include "Main/Main.h"
#include "Main/Application.h"
#include "Main/GraphicUserInterface.h"
#ifdef TC_LINUX
#include "Platform/Unix/Process.h"
#endif
#include "Volume/Cipher.h"
#include "PreferencesDialog.h"
@@ -132,7 +135,16 @@ namespace VeraCrypt
#if defined (TC_MACOSX)
wxDir languagesFolder(StringConverter::ToSingle (Application::GetExecutableDirectory()) + "/../Resources/languages/");
#else
wxDir languagesFolder("/usr/share/veracrypt/languages/");
wxString languagesFolderPath("/usr/share/veracrypt/languages/");
#ifdef TC_LINUX
if (Process::IsRunningUnderAppImage (StringConverter::ToSingle (wstring (Application::GetExecutablePath()))))
{
const char* appDirEnv = getenv ("APPDIR");
if (appDirEnv)
languagesFolderPath = wxString::FromUTF8 (appDirEnv) + "/usr/share/veracrypt/languages/";
}
#endif
wxDir languagesFolder(languagesFolderPath);
#endif
wxArrayString langArray;
LanguageListBox->Append("System default");
+19 -2
View File
@@ -391,6 +391,7 @@ namespace VeraCrypt
DisplayKeyInfo (false),
LargeFilesSupport (false),
QuickFormatEnabled (false),
QuickFormatEnabledByWizard (false),
SelectedFilesystemClusterSize (0),
SelectedFilesystemType (VolumeCreationOptions::FilesystemType::FAT),
SelectedVolumeHostType (VolumeHostType::File),
@@ -446,6 +447,7 @@ namespace VeraCrypt
OuterVolume = false;
LargeFilesSupport = false;
QuickFormatEnabled = false;
QuickFormatEnabledByWizard = false;
Pim = 0;
SingleChoiceWizardPage <VolumeHostType::Enum> *page = new SingleChoiceWizardPage <VolumeHostType::Enum> (GetPageParent(), wxEmptyString, true);
@@ -595,15 +597,29 @@ namespace VeraCrypt
{
shared_ptr <VolumeLayout> layout ((OuterVolume || SelectedVolumeType != VolumeType::Hidden)? (VolumeLayout*) new VolumeLayoutV2Normal() : (VolumeLayout*) new VolumeLayoutV2Hidden());
uint64 filesystemSize = layout->GetMaxDataSize (VolumeSize);
bool hiddenVolumeItself = !OuterVolume && SelectedVolumeType == VolumeType::Hidden;
bool normalFileContainer = !OuterVolume && SelectedVolumeType == VolumeType::Normal && SelectedVolumeHostType == VolumeHostType::File;
bool existingDeviceSupportedCase = SelectedVolumePath.IsDevice() && !hiddenVolumeItself;
bool quickFormatSupported = existingDeviceSupportedCase || normalFileContainer;
VolumeFormatOptionsWizardPage *page = new VolumeFormatOptionsWizardPage (GetPageParent(), filesystemSize, SectorSize,
SelectedVolumePath.IsDevice() && (OuterVolume || SelectedVolumeType != VolumeType::Hidden), OuterVolume, LargeFilesSupport);
quickFormatSupported, OuterVolume, LargeFilesSupport);
page->SetPageTitle (LangString["FORMAT_TITLE"]);
page->SetFilesystemType (SelectedFilesystemType);
if (!OuterVolume && SelectedVolumeType == VolumeType::Hidden)
if (hiddenVolumeItself)
{
QuickFormatEnabled = true;
QuickFormatEnabledByWizard = true;
}
else
{
if (!quickFormatSupported || QuickFormatEnabledByWizard)
QuickFormatEnabled = false;
QuickFormatEnabledByWizard = false;
}
page->SetQuickFormat (QuickFormatEnabled);
return page;
@@ -1332,6 +1348,7 @@ namespace VeraCrypt
SelectedFilesystemType = page->GetFilesystemType();
QuickFormatEnabled = page->IsQuickFormatEnabled();
QuickFormatEnabledByWizard = !OuterVolume && SelectedVolumeType == VolumeType::Hidden;
if (SelectedFilesystemType != VolumeCreationOptions::FilesystemType::None
&& SelectedFilesystemType != VolumeCreationOptions::FilesystemType::FAT)
+1
View File
@@ -76,6 +76,7 @@ namespace VeraCrypt
shared_ptr <VolumeInfo> MountedOuterVolume;
bool OuterVolume;
bool QuickFormatEnabled;
bool QuickFormatEnabledByWizard;
shared_ptr <EncryptionAlgorithm> SelectedEncryptionAlgorithm;
uint32 SelectedFilesystemClusterSize;
VolumeCreationOptions::FilesystemType::Enum SelectedFilesystemType;
+3 -2
View File
@@ -1037,7 +1037,6 @@ namespace VeraCrypt
if (write (showFifo, buf, 1) == 1)
{
close (showFifo);
Gui->ShowInfo (LangString["LINUX_VC_RUNNING_ALREADY"]);
Application::SetExitCode (0);
return false;
}
@@ -1872,7 +1871,9 @@ namespace VeraCrypt
BackgroundMode = state;
#ifdef HAVE_INDICATORS
gtk_menu_item_set_label ((GtkMenuItem*) ((MainFrame*) mMainFrame)->indicator_item_showhide, LangString[Gui->IsInBackgroundMode() ? "SHOW_TC" : "HIDE_TC"].mb_str());
MainFrame *mainFrame = (MainFrame*) mMainFrame;
if (mainFrame->indicator_item_showhide)
gtk_menu_item_set_label ((GtkMenuItem*) mainFrame->indicator_item_showhide, LangString[Gui->IsInBackgroundMode() ? "SHOW_TC" : "HIDE_TC"].mb_str());
#endif
}
+27 -1
View File
@@ -328,6 +328,7 @@ INSTALL_DESKTOP ?= 1
INSTALL_MIME ?= 1
INSTALL_ICONS ?= 1
INSTALL_APPIMAGE_FILES ?= 1
APPIMAGE_BUNDLE_FUSE2 ?= 1
# These override values are appended below usr and used in shell recipes.
# Keep command-line/environment overrides literal and path-like.
@@ -426,6 +427,27 @@ endif
ifneq "$(INSTALL_APPIMAGE_FILES)" "0"
rm -fr $(BASE_DIR)/Setup/Linux/veracrypt.AppDir/usr
cp -r $(BASE_DIR)/Setup/Linux/usr $(BASE_DIR)/Setup/Linux/veracrypt.AppDir/.
ifneq "$(APPIMAGE_BUNDLE_FUSE2)" "0"
@set -e; \
_appdir="$(BASE_DIR)/Setup/Linux/veracrypt.AppDir"; \
_fuse_lib="$$( (ldconfig -p 2>/dev/null || /sbin/ldconfig -p 2>/dev/null || true) | awk '/libfuse\.so\.2[[:space:]]/ { print $$NF; exit }')"; \
if [ -z "$$_fuse_lib" ]; then \
for _candidate in /lib64/libfuse.so.2 /usr/lib64/libfuse.so.2 /lib/libfuse.so.2 /usr/lib/libfuse.so.2 /lib/*/libfuse.so.2 /usr/lib/*/libfuse.so.2; do \
if [ -e "$$_candidate" ]; then _fuse_lib="$$_candidate"; break; fi; \
done; \
fi; \
if [ -n "$$_fuse_lib" ]; then \
echo "Bundling AppImage FUSE2 userspace library: $$_fuse_lib"; \
mkdir -p "$$_appdir/usr/lib"; \
cp -P "$$_fuse_lib" "$$_appdir/usr/lib/"; \
_fuse_real="$$(readlink -f "$$_fuse_lib" 2>/dev/null || true)"; \
if [ -n "$$_fuse_real" ] && [ "$$_fuse_real" != "$$_fuse_lib" ]; then \
cp "$$_fuse_real" "$$_appdir/usr/lib/"; \
fi; \
else \
echo "Warning: libfuse.so.2 not found; AppImage will rely on a host FUSE2 userspace library"; \
fi
endif
ifneq "$(INSTALL_ICONS)" "0"
ln -sf usr/share/icons/hicolor/1024x1024/apps/$(APPNAME).png $(BASE_DIR)/Setup/Linux/veracrypt.AppDir/$(APPNAME).png
endif
@@ -550,7 +572,11 @@ appimage: prepare
_appimagetool_executable_name="appimagetool-$${_appimagetool_arch_suffix}.AppImage"; \
_appimagetool_executable_path="$(BASE_DIR)/Setup/Linux/$${_appimagetool_executable_name}"; \
_appimagetool_url="https://github.com/AppImage/appimagetool/releases/download/continuous/$${_appimagetool_executable_name}"; \
_final_appimage_filename="VeraCrypt-$(TC_VERSION)-$${_final_appimage_arch_suffix}.AppImage"; \
_final_appimage_gtk_suffix=""; \
if [ "$(GTK_VERSION)" = "2" ]; then \
_final_appimage_gtk_suffix="-gtk2-legacy"; \
fi; \
_final_appimage_filename="VeraCrypt-$(TC_VERSION)$${_final_appimage_gtk_suffix}-$${_final_appimage_arch_suffix}.AppImage"; \
_final_appimage_path="$(BASE_DIR)/Setup/Linux/$${_final_appimage_filename}"; \
\
echo "Preparing AppImage for $(CPU_ARCH) (using $${_appimagetool_arch_suffix})..."; \
+11 -2
View File
@@ -17,13 +17,14 @@
#ifdef TC_WINDOWS
#include "Main/resource.h"
#else
#ifdef TC_MACOSX
#include "Application.h"
#endif
#include "Platform/File.h"
#include "Platform/StringConverter.h"
#include <stdio.h>
#include "UserPreferences.h"
#if defined(TC_LINUX)
#include "Platform/Unix/Process.h"
#endif
#endif
namespace VeraCrypt
@@ -66,6 +67,14 @@ namespace VeraCrypt
string filenamePrefix = StringConverter::ToSingle (Application::GetExecutableDirectory()) + "/../Resources/languages/Language.";
#else
string filenamePrefix("/usr/share/veracrypt/languages/Language.");
#if defined(TC_LINUX)
if (Process::IsRunningUnderAppImage (StringConverter::ToSingle (wstring (Application::GetExecutablePath()))))
{
const char* appDirEnv = getenv ("APPDIR");
if (appDirEnv)
filenamePrefix = string (appDirEnv) + "/usr/share/veracrypt/languages/Language.";
}
#endif
#endif
string filenamePost(".xml");
string filename = filenamePrefix + defaultLang + filenamePost;
+12 -2
View File
@@ -766,8 +766,6 @@ namespace VeraCrypt
}
}
options->Quick = false;
uint32 sectorSizeRem = options->Size % options->SectorSize;
if (sectorSizeRem != 0)
options->Size += options->SectorSize - sectorSizeRem;
@@ -964,6 +962,18 @@ namespace VeraCrypt
throw_err (_("Specified volume size is too small to be used with Btrfs filesystem."));
}
if (options->Quick && options->Type == VolumeType::Normal)
{
if (Preferences.NonInteractive)
{
ShowWarning (_("Quick Format is enabled. Do not use --quick for an outer volume intended to contain a hidden volume. It skips writing random data to unused volume space, reducing plausible deniability. For file containers, actual disk savings depend on host filesystem sparse-file support, and later writes can fail if host space runs out."));
}
else if (!AskYesNo (LangString["WARN_QUICK_FORMAT"], false, true))
{
throw UserAbort (SRC_POS);
}
}
// Password
if (!options->Password && !Preferences.NonInteractive)
{
+7 -3
View File
@@ -1219,7 +1219,7 @@ const FileManager fileManagers[] = {
" Inexperienced users should use the graphical user interface to create a hidden\n"
" volume. When using the text user interface, the following procedure must be\n"
" followed to create a hidden volume:\n"
" 1) Create an outer volume with no filesystem.\n"
" 1) Create an outer volume with no filesystem and without --quick.\n"
" 2) Create a hidden volume within the outer volume.\n"
" 3) Mount the outer volume using hidden volume protection.\n"
" 4) Create a filesystem on the virtual device of the outer volume.\n"
@@ -1428,8 +1428,12 @@ const FileManager fileManagers[] = {
" See also options -p and --protect-hidden.\n"
"\n"
"--quick\n"
" Do not encrypt free space when creating a device-hosted volume. This option\n"
" must not be used when creating an outer volume.\n"
" Do not encrypt free space when creating a normal file-hosted or\n"
" device-hosted volume. This option must not be used when creating an outer\n"
" volume; text mode cannot infer that a normal volume will later be\n"
" used as an outer volume. For file containers, Quick Format may create sparse\n"
" or unwritten host regions; actual disk savings depend on host filesystem\n"
" sparse-file support, and later writes can fail if host space runs out.\n"
"\n"
"--random-source=FILE\n"
" Use FILE as a source of random data (e.g., when creating a volume) instead\n"
+3 -1
View File
@@ -19,6 +19,8 @@
# NOTEST: Do not test release binary
# RESOURCEDIR: Run-time resource directory
# VERBOSE: Enable verbose messages
# WITHFUSE3: Build with FUSE3 support instead of FUSE2
# WX_CONFIGURE_EXTRA_FLAGS: Extra flags passed to wxWidgets configure
# WXSTATIC: Use static wxWidgets library
# SSSE3: Enable SSSE3 support in compiler
# SSE41: Enable SSE4.1 support in compiler
@@ -736,7 +738,7 @@ endif
WX_CONFIGURE_LEGACY_FLAGS="$$WX_CONFIGURE_LEGACY_FLAGS --enable-$$option"; \
fi; \
done; \
"$(WX_ROOT)/configure" $(WX_CONFIGURE_FLAGS) $$WX_CONFIGURE_LEGACY_FLAGS >/dev/null
"$(WX_ROOT)/configure" $(WX_CONFIGURE_FLAGS) $(WX_CONFIGURE_EXTRA_FLAGS) $$WX_CONFIGURE_LEGACY_FLAGS >/dev/null
@echo Building wxWidgets library...
cd "$(WX_BUILD_DIR)" && $(MAKE) -j 4
+2 -2
View File
@@ -587,8 +587,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+1
View File
@@ -87,6 +87,7 @@ namespace VeraCrypt
uint64 ReadAt (const BufferPtr &buffer, uint64 position) const;
void SeekAt (uint64 position) const;
void SeekEnd (int ofset) const;
void SetLength (uint64 length) const;
void Write (const ConstBufferPtr &buffer) const;
void Write (const ConstBufferPtr &buffer, size_t length) const { Write (buffer.GetRange (0, length)); }
void WriteAt (const ConstBufferPtr &buffer, uint64 position) const;
+1
View File
@@ -29,6 +29,7 @@ namespace VeraCrypt
SyncEvent ();
~SyncEvent ();
void Reset ();
void Signal ();
void Wait ();
+36 -3
View File
@@ -125,7 +125,11 @@ namespace VeraCrypt
#elif defined (TC_OPENBSD)
struct disklabel dl;
throw_sys_sub_if (ioctl (FileHandle, DIOCGPDINFO, &dl) == -1, wstring (Path));
throw_sys_sub_if (ioctl (FileHandle, DIOCGDINFO, &dl) == -1, wstring (Path));
if (dl.d_secsize == 0)
throw ParameterIncorrect (SRC_POS);
return (uint32) dl.d_secsize;
#elif defined (TC_SOLARIS)
@@ -213,8 +217,31 @@ namespace VeraCrypt
return blockCount * blockSize;
# elif TC_OPENBSD
struct disklabel dl;
throw_sys_sub_if (ioctl (FileHandle, DIOCGPDINFO, &dl) == -1, wstring (Path));
return DL_GETDSIZE(&dl);
struct stat statData;
throw_sys_sub_if (ioctl (FileHandle, DIOCGDINFO, &dl) == -1, wstring (Path));
throw_sys_sub_if (fstat (FileHandle, &statData) == -1, wstring (Path));
if (dl.d_secsize == 0)
throw ParameterIncorrect (SRC_POS);
uint64 sectors;
int partition = DISKPART (statData.st_rdev);
if (partition == RAW_PART)
{
sectors = DL_GETDSIZE (&dl);
}
else
{
if (partition < 0 || partition >= dl.d_npartitions)
throw ParameterIncorrect (SRC_POS);
sectors = DL_GETPSIZE (&dl.d_partitions[partition]);
}
if (sectors > ((uint64) -1) / dl.d_secsize)
throw ParameterIncorrect (SRC_POS);
return sectors * dl.d_secsize;
# else
uint64 mediaSize;
throw_sys_sub_if (ioctl (FileHandle, DIOCGMEDIASIZE, &mediaSize) == -1, wstring (Path));
@@ -385,6 +412,12 @@ namespace VeraCrypt
throw_sys_sub_if (lseek (FileHandle, offset, SEEK_END) == -1, wstring (Path));
}
void File::SetLength (uint64 length) const
{
if_debug (ValidateState());
throw_sys_sub_if (ftruncate (FileHandle, length) == -1, wstring (Path));
}
void File::Write (const ConstBufferPtr &buffer) const
{
if_debug (ValidateState());
+8
View File
@@ -41,6 +41,14 @@ namespace VeraCrypt
Initialized = false;
}
void SyncEvent::Reset ()
{
assert (Initialized);
ScopeLock lock (EventMutex);
Signaled = false;
}
void SyncEvent::Signal ()
{
assert (Initialized);
+26 -7
View File
@@ -6,6 +6,7 @@
for upgrades to work ; Windows Installer ignores the 4th part -->
<?define var.FullProductVersion = 1.26.28?>
<?define var.ProductName = VeraCrypt $(var.FullProductVersion)?>
<?define var.StartMenuFolderName = VeraCrypt?>
<!-- Unique GUID identifying this family of product (32-bit and 64-bit have the same) -->
<?define var.UpgradeCode = {298F5D2B-3B01-4A13-BEFD-4B3C7BE43BC6}?>
@@ -186,7 +187,7 @@
<!-- Reference APPLICATIONPROGRAMSFOLDER to create a Start Menu Shortcut -->
<!-- See https://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/create_start_menu_shortcut.html -->
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="$(var.ProductName)"/>
<Directory Id="ApplicationProgramsFolder" Name="$(var.StartMenuFolderName)"/>
</Directory>
<!-- We do not Reference QuickLaunchFolder under AppDataFolder to create a Quick Launch Shortcut -->
@@ -2440,7 +2441,7 @@
<DirectoryRef Id="ApplicationProgramsFolder">
<!-- Creating an advertised shortcut : enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated -->
<Component Id="VCShortcutStartMenu" Guid="{9CA5F425-0268-4424-8E41-A94D90F1118D}">
<Component Id="VCShortcutStartMenu" Guid="{684DA19F-50FC-43AA-89BA-1685DAC0D585}">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<Shortcut Id="VCMenuShortcut"
@@ -2456,7 +2457,7 @@
<RegistryValue
Root="HKCU"
Key="Software\VeraCrypt_MSI"
Name="VCStartMenuShortcutInstalled"
Name="VCStartMenuShortcutInstalledStable"
Type="integer"
Value="1"
KeyPath="yes"/>
@@ -2464,7 +2465,7 @@
</Component>
<!-- Creating an advertised shortcut : enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated -->
<Component Id="VCExpanderShortcutStartMenu" Guid="9BA70A97-CB6D-4ED4-A0F7-A4CF9885DC33">
<Component Id="VCExpanderShortcutStartMenu" Guid="{E0C191AE-86EB-462A-9C8A-73338EC7A153}">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<Shortcut Id="VCExpanderStartMenuShortcut"
@@ -2480,7 +2481,7 @@
<RegistryValue
Root="HKCU"
Key="Software\VeraCrypt_MSI"
Name="VCEexpanderStartMenuShortcutInstalled"
Name="VCExpanderStartMenuShortcutInstalledStable"
Type="integer"
Value="1"
KeyPath="yes"/>
@@ -2488,7 +2489,7 @@
</Component>
<!-- Creating an advertised shortcut : enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated -->
<Component Id="VCWebsiteShortcutStartMenu" Guid="{D5AA7FFE-5256-4234-AEE1-F9F1EB6ECA4A}">
<Component Id="VCWebsiteShortcutStartMenu" Guid="{00CA573B-4B04-4397-8061-CF5B5515DDBD}">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<util:InternetShortcut Id="VCWebsiteStartMenuShortcut"
@@ -2503,7 +2504,7 @@
<RegistryValue
Root="HKCU"
Key="Software\VeraCrypt_MSI"
Name="VCWebsiteStartMenuShortcutInstalled"
Name="VCWebsiteStartMenuShortcutInstalledStable"
Type="integer"
Value="1"
KeyPath="yes"/>
@@ -3444,6 +3445,12 @@
<CustomAction Id="PostInst_SetData"
Property="DoPostInstall"
Value="INSTALLDIR=[APPLICATIONROOTFOLDER]" />
<!-- Create a Custom Action which sets the CustomActionData property
for CleanupOldStartMenuFolders Deferred Custom Action. -->
<CustomAction Id="CleanupOldStartMenuFolders_SetData"
Property="CleanupOldStartMenuFolders"
Value="PROGRAMMENUFOLDER=[ProgramMenuFolder]" />
<!-- Create a Custom Action which sets the CustomActionData property
for DoPostUninstall Deferred Custom Action.
@@ -3474,6 +3481,14 @@
Return="check"
BinaryKey="VeraCryptCustomActions"
DllEntry="VC_CustomAction_PostInstall" />
<!-- Best-effort cleanup of obsolete versioned Start Menu folders from previous MSI releases. -->
<CustomAction Id="CleanupOldStartMenuFolders"
Execute="deferred"
Impersonate="no"
Return="ignore"
BinaryKey="VeraCryptCustomActions"
DllEntry="VC_CustomAction_CleanupOldStartMenuFolders" />
<!-- Create our Pre-Uninstall Custom Action.
We need to run it as deferred so that it runs
@@ -3602,6 +3617,10 @@
it will execute it twice : once when it installs new files (NOT Installed), and then when it removes unnecessary files (actual upgrade: UPGRADINGPRODUCTCODE).
Therefore, we do not need to execute it at UPGRADINGPRODUCTCODE. -->
<Custom Action="DoPostInstall" After="InstallFiles">(NOT Installed AND NOT REMOVE) OR REINSTALL</Custom>
<!-- Cleanup obsolete versioned Start Menu folders as late as possible in the install transaction. -->
<Custom Action="CleanupOldStartMenuFolders_SetData" Before="CleanupOldStartMenuFolders">(NOT Installed AND NOT REMOVE) OR REINSTALL</Custom>
<Custom Action="CleanupOldStartMenuFolders" After="PublishProduct">(NOT Installed AND NOT REMOVE) OR REINSTALL</Custom>
<!-- UNINSTALLATION ONLY CAs -->
+26 -7
View File
@@ -6,6 +6,7 @@
for upgrades to work ; Windows Installer ignores the 4th part -->
<?define var.FullProductVersion = 1.26.28?>
<?define var.ProductName = VeraCrypt $(var.FullProductVersion)?>
<?define var.StartMenuFolderName = VeraCrypt?>
<!-- Unique GUID identifying this family of product (32-bit and 64-bit have the same) -->
<?define var.UpgradeCode = {813AB9FC-2117-4961-B459-EB65028EEC93}?>
@@ -186,7 +187,7 @@
<!-- Reference APPLICATIONPROGRAMSFOLDER to create a Start Menu Shortcut -->
<!-- See https://wixtoolset.org/documentation/manual/v3/howtos/files_and_registry/create_start_menu_shortcut.html -->
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" Name="$(var.ProductName)"/>
<Directory Id="ApplicationProgramsFolder" Name="$(var.StartMenuFolderName)"/>
</Directory>
<!-- We do not Reference QuickLaunchFolder under AppDataFolder to create a Quick Launch Shortcut -->
@@ -2440,7 +2441,7 @@
<DirectoryRef Id="ApplicationProgramsFolder">
<!-- Creating an advertised shortcut : enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated -->
<Component Id="VCShortcutStartMenu" Guid="{9CA5F425-0268-4424-8E41-A94D90F1118D}">
<Component Id="VCShortcutStartMenu" Guid="{684DA19F-50FC-43AA-89BA-1685DAC0D585}">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<Shortcut Id="VCMenuShortcut"
@@ -2456,7 +2457,7 @@
<RegistryValue
Root="HKCU"
Key="Software\VeraCrypt_MSI"
Name="VCStartMenuShortcutInstalled"
Name="VCStartMenuShortcutInstalledStable"
Type="integer"
Value="1"
KeyPath="yes"/>
@@ -2464,7 +2465,7 @@
</Component>
<!-- Creating an advertised shortcut : enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated -->
<Component Id="VCExpanderShortcutStartMenu" Guid="9BA70A97-CB6D-4ED4-A0F7-A4CF9885DC33">
<Component Id="VCExpanderShortcutStartMenu" Guid="{E0C191AE-86EB-462A-9C8A-73338EC7A153}">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<Shortcut Id="VCExpanderStartMenuShortcut"
@@ -2480,7 +2481,7 @@
<RegistryValue
Root="HKCU"
Key="Software\VeraCrypt_MSI"
Name="VCEexpanderStartMenuShortcutInstalled"
Name="VCExpanderStartMenuShortcutInstalledStable"
Type="integer"
Value="1"
KeyPath="yes"/>
@@ -2488,7 +2489,7 @@
</Component>
<!-- Creating an advertised shortcut : enhances resiliency by verifying that all the components in the feature are installed when the shortcut is activated -->
<Component Id="VCWebsiteShortcutStartMenu" Guid="{D5AA7FFE-5256-4234-AEE1-F9F1EB6ECA4A}">
<Component Id="VCWebsiteShortcutStartMenu" Guid="{00CA573B-4B04-4397-8061-CF5B5515DDBD}">
<Condition>INSTALLSTARTMENUSHORTCUT</Condition>
<util:InternetShortcut Id="VCWebsiteStartMenuShortcut"
@@ -2503,7 +2504,7 @@
<RegistryValue
Root="HKCU"
Key="Software\VeraCrypt_MSI"
Name="VCWebsiteStartMenuShortcutInstalled"
Name="VCWebsiteStartMenuShortcutInstalledStable"
Type="integer"
Value="1"
KeyPath="yes"/>
@@ -3444,6 +3445,12 @@
<CustomAction Id="PostInst_SetData"
Property="DoPostInstall"
Value="INSTALLDIR=[APPLICATIONROOTFOLDER]" />
<!-- Create a Custom Action which sets the CustomActionData property
for CleanupOldStartMenuFolders Deferred Custom Action. -->
<CustomAction Id="CleanupOldStartMenuFolders_SetData"
Property="CleanupOldStartMenuFolders"
Value="PROGRAMMENUFOLDER=[ProgramMenuFolder]" />
<!-- Create a Custom Action which sets the CustomActionData property
for DoPostUninstall Deferred Custom Action.
@@ -3474,6 +3481,14 @@
Return="check"
BinaryKey="VeraCryptCustomActions"
DllEntry="VC_CustomAction_PostInstall" />
<!-- Best-effort cleanup of obsolete versioned Start Menu folders from previous MSI releases. -->
<CustomAction Id="CleanupOldStartMenuFolders"
Execute="deferred"
Impersonate="no"
Return="ignore"
BinaryKey="VeraCryptCustomActions"
DllEntry="VC_CustomAction_CleanupOldStartMenuFolders" />
<!-- Create our Pre-Uninstall Custom Action.
We need to run it as deferred so that it runs
@@ -3614,6 +3629,10 @@
it will execute it twice : once when it installs new files (NOT Installed), and then when it removes unnecessary files (actual upgrade: UPGRADINGPRODUCTCODE).
Therefore, we do not need to execute it at UPGRADINGPRODUCTCODE. -->
<Custom Action="DoPostInstall" After="InstallFiles">(NOT Installed AND NOT REMOVE) OR REINSTALL</Custom>
<!-- Cleanup obsolete versioned Start Menu folders as late as possible in the install transaction. -->
<Custom Action="CleanupOldStartMenuFolders_SetData" Before="CleanupOldStartMenuFolders">(NOT Installed AND NOT REMOVE) OR REINSTALL</Custom>
<Custom Action="CleanupOldStartMenuFolders" After="PublishProduct">(NOT Installed AND NOT REMOVE) OR REINSTALL</Custom>
<!-- UNINSTALLATION ONLY CAs -->
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -10,7 +10,7 @@ signature = "$Windows NT$"
Class = "Encryption" ;This is determined by the work this filter driver does
ClassGuid = {a0a701c0-a511-42ff-aa6c-06dc0395576f} ;This value is determined by the Class
Provider = %ProviderString%
DriverVer = 04/30/2026,1.26.28.0
DriverVer = 05/22/2026,1.26.28.1
CatalogFile = veracrypt.cat
PnpLockdown = 1
+11
View File
@@ -2,5 +2,16 @@
# Get the directory where AppRun is located
APPDIR=$(dirname "$(readlink -f "$0")")
# Prefer libraries bundled inside the AppImage. This lets the official
# AppImage carry its private FUSE2 userspace library on systems where
# libfuse.so.2 is no longer installed by default.
if [ -d "${APPDIR}/usr/lib" ]; then
if [ -n "${LD_LIBRARY_PATH:-}" ]; then
export LD_LIBRARY_PATH="${APPDIR}/usr/lib:${LD_LIBRARY_PATH}"
else
export LD_LIBRARY_PATH="${APPDIR}/usr/lib"
fi
fi
# Execute the main VeraCrypt application
exec "${APPDIR}/usr/bin/veracrypt" "$@"
+2 -2
View File
@@ -26,8 +26,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+2 -2
View File
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+233 -5
View File
@@ -2134,6 +2134,225 @@ void Tokenize(const wchar_t* szInput, std::vector<std::wstring>& szTokens)
}
}
static BOOL JoinPath(wchar_t *szPath, size_t cbPath, const wchar_t *szDirectory, const wchar_t *szFileName)
{
if (FAILED(StringCbCopyW(szPath, cbPath, szDirectory)))
return FALSE;
size_t cchPath = wcslen(szPath);
if (cchPath > 0 && szPath[cchPath - 1] != L'\\' && szPath[cchPath - 1] != L'/')
{
if (FAILED(StringCbCatW(szPath, cbPath, L"\\")))
return FALSE;
}
return SUCCEEDED(StringCbCatW(szPath, cbPath, szFileName));
}
static BOOL IsVersionedVeraCryptStartMenuFolderName(const wchar_t *szFolderName)
{
const wchar_t szPrefix[] = L"VeraCrypt ";
const wchar_t *szVersion = NULL;
BOOL bHasDigit = FALSE;
BOOL bHasDot = FALSE;
BOOL bPreviousDot = FALSE;
if (!szFolderName || _wcsnicmp(szFolderName, szPrefix, wcslen(szPrefix)) != 0)
return FALSE;
szVersion = szFolderName + wcslen(szPrefix);
if (*szVersion == L'\0')
return FALSE;
while (*szVersion)
{
if (*szVersion >= L'0' && *szVersion <= L'9')
{
bHasDigit = TRUE;
bPreviousDot = FALSE;
}
else if (*szVersion == L'.')
{
if (bPreviousDot)
return FALSE;
bHasDot = TRUE;
bPreviousDot = TRUE;
}
else
{
return FALSE;
}
++szVersion;
}
return bHasDigit && bHasDot && !bPreviousDot;
}
static void DeleteStartMenuShortcutIfExists(MSIHANDLE hInstaller, const wchar_t *szFolderPath, const wchar_t *szShortcutName)
{
wchar_t szShortcutPath[TC_MAX_PATH];
DWORD dwAttributes;
if (!JoinPath(szShortcutPath, sizeof(szShortcutPath), szFolderPath, szShortcutName))
{
MSILog(hInstaller, MSI_WARNING_LEVEL, L"Could not build Start Menu shortcut path for '%s'", szShortcutName);
return;
}
dwAttributes = GetFileAttributesW(szShortcutPath);
if (dwAttributes == INVALID_FILE_ATTRIBUTES || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
return;
MSILog(hInstaller, MSI_INFO_LEVEL, L"Removing obsolete Start Menu shortcut '%s'", szShortcutPath);
if (dwAttributes & FILE_ATTRIBUTE_READONLY)
SetFileAttributesW(szShortcutPath, dwAttributes & ~FILE_ATTRIBUTE_READONLY);
if (!DeleteFileW(szShortcutPath))
{
DWORD dwError = GetLastError();
if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_PATH_NOT_FOUND)
{
MSILog(hInstaller, MSI_WARNING_LEVEL, L"Could not remove obsolete Start Menu shortcut '%s' (error %lu)", szShortcutPath, dwError);
}
}
}
static void CleanupVersionedVeraCryptStartMenuFolder(MSIHANDLE hInstaller, const wchar_t *szFolderPath)
{
/* Delete only known VeraCrypt-created shortcuts; keep folders with any other content. */
static const wchar_t *szShortcutNames[] =
{
L"VeraCrypt.lnk",
L"VeraCryptExpander.lnk",
L"VeraCrypt Website.url",
L"VeraCrypt User's Guide.lnk",
L"VeraCrypt User Guide.lnk",
L"Uninstall VeraCrypt.lnk"
};
for (size_t i = 0; i < ARRAYSIZE(szShortcutNames); ++i)
DeleteStartMenuShortcutIfExists(hInstaller, szFolderPath, szShortcutNames[i]);
if (RemoveDirectoryW(szFolderPath))
{
MSILog(hInstaller, MSI_INFO_LEVEL, L"Removed obsolete Start Menu folder '%s'", szFolderPath);
}
else
{
DWORD dwError = GetLastError();
if (dwError == ERROR_DIR_NOT_EMPTY)
{
MSILog(hInstaller, MSI_INFO_LEVEL, L"Obsolete Start Menu folder '%s' was left in place because it contains non-VeraCrypt items", szFolderPath);
}
else if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_PATH_NOT_FOUND)
{
MSILog(hInstaller, MSI_WARNING_LEVEL, L"Could not remove obsolete Start Menu folder '%s' (error %lu)", szFolderPath, dwError);
}
}
}
static void CleanupVersionedVeraCryptStartMenuFoldersInRoot(MSIHANDLE hInstaller, const wchar_t *szProgramMenuFolder)
{
wchar_t szSearchPath[TC_MAX_PATH];
WIN32_FIND_DATAW findData;
HANDLE hFind;
if (!szProgramMenuFolder || szProgramMenuFolder[0] == L'\0')
return;
if (!JoinPath(szSearchPath, sizeof(szSearchPath), szProgramMenuFolder, L"VeraCrypt *"))
{
MSILog(hInstaller, MSI_WARNING_LEVEL, L"Could not build obsolete Start Menu folder search path for '%s'", szProgramMenuFolder);
return;
}
hFind = FindFirstFileW(szSearchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
if (dwError != ERROR_FILE_NOT_FOUND && dwError != ERROR_PATH_NOT_FOUND)
{
MSILog(hInstaller, MSI_WARNING_LEVEL, L"Could not search obsolete Start Menu folders in '%s' (error %lu)", szProgramMenuFolder, dwError);
}
return;
}
do
{
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& IsVersionedVeraCryptStartMenuFolderName(findData.cFileName))
{
wchar_t szFolderPath[TC_MAX_PATH];
if (JoinPath(szFolderPath, sizeof(szFolderPath), szProgramMenuFolder, findData.cFileName))
CleanupVersionedVeraCryptStartMenuFolder(hInstaller, szFolderPath);
else
MSILog(hInstaller, MSI_WARNING_LEVEL, L"Could not build obsolete Start Menu folder path for '%s'", findData.cFileName);
}
}
while (FindNextFileW(hFind, &findData));
FindClose(hFind);
}
static void CleanupVersionedVeraCryptStartMenuFolders(MSIHANDLE hInstaller, const wchar_t *szProgramMenuFolder)
{
wchar_t szCommonPrograms[TC_MAX_PATH];
CleanupVersionedVeraCryptStartMenuFoldersInRoot(hInstaller, szProgramMenuFolder);
if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, szCommonPrograms)))
CleanupVersionedVeraCryptStartMenuFoldersInRoot(hInstaller, szCommonPrograms);
}
EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_CleanupOldStartMenuFolders(MSIHANDLE hInstaller)
{
std::wstring szValueBuf = L"";
std::wstring szProgramMenuFolder = L"";
DWORD cchValueBuf = 0;
UINT uiStat = 0;
MSILog(hInstaller, MSI_INFO_LEVEL, L"Begin VC_CustomAction_CleanupOldStartMenuFolders");
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), (LPWSTR)TEXT(""), &cchValueBuf);
if (ERROR_MORE_DATA == uiStat)
{
++cchValueBuf; // add 1 for null termination
szValueBuf.resize(cchValueBuf);
uiStat = MsiGetProperty(hInstaller, TEXT("CustomActionData"), &szValueBuf[0], &cchValueBuf);
if (ERROR_SUCCESS == uiStat)
{
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_CleanupOldStartMenuFolders: CustomActionData = '%s'", szValueBuf.c_str());
std::vector<std::wstring> szTokens;
Tokenize(szValueBuf.c_str(), szTokens);
for (size_t i = 0; i < szTokens.size(); i++)
{
std::wstring szToken = szTokens[i];
if (wcsncmp(szToken.c_str(), L"PROGRAMMENUFOLDER=", wcslen(L"PROGRAMMENUFOLDER=")) == 0)
{
size_t index0 = szToken.find_first_of(L"=");
if (index0 != std::wstring::npos)
{
szProgramMenuFolder = szToken.substr(index0 + 1);
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_CleanupOldStartMenuFolders: PROGRAMMENUFOLDER = '%s'", szProgramMenuFolder.c_str());
}
}
}
}
}
CleanupVersionedVeraCryptStartMenuFolders(hInstaller, szProgramMenuFolder.c_str());
MSILog(hInstaller, MSI_INFO_LEVEL, L"End VC_CustomAction_CleanupOldStartMenuFolders");
return ERROR_SUCCESS;
}
/*
* Same as Setup.c, function DoInstall(), but
* without the actual installation, it only prepares the system
@@ -2390,13 +2609,22 @@ EXTERN_C UINT STDAPICALLTYPE VC_CustomAction_PostInstall(MSIHANDLE hInstaller)
if ((ERROR_SUCCESS == uiStat))
{
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostInstall: CustomActionData = '%s'", szValueBuf.c_str());
if (wcsncmp(szValueBuf.c_str(), L"INSTALLDIR=", wcslen(L"INSTALLDIR=")) == 0)
std::vector<std::wstring> szTokens;
Tokenize(szValueBuf.c_str(), szTokens);
for (size_t i = 0; i < szTokens.size(); i++)
{
size_t index0 = szValueBuf.find_first_of(L"=");
if (index0 != std::wstring::npos)
std::wstring szToken = szTokens[i];
if (wcsncmp(szToken.c_str(), L"INSTALLDIR=", wcslen(L"INSTALLDIR=")) == 0)
{
szInstallDir = szValueBuf.substr(index0 + 1);
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostInstall: INSTALLDIR = '%s'", szInstallDir.c_str());
size_t index0 = szToken.find_first_of(L"=");
if (index0 != std::wstring::npos)
{
szInstallDir = szToken.substr(index0 + 1);
MSILog(hInstaller, MSI_INFO_LEVEL, L"VC_CustomAction_PostInstall: INSTALLDIR = '%s'", szInstallDir.c_str());
}
}
}
}
+2 -2
View File
@@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,26,28,0
PRODUCTVERSION 1,26,28,0
FILEVERSION 1,26,28,1
PRODUCTVERSION 1,26,28,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
+2 -1
View File
@@ -2,6 +2,7 @@ LIBRARY VERACRYPTSETUP
EXPORTS
VC_CustomAction_PreInstall
VC_CustomAction_PostInstall
VC_CustomAction_CleanupOldStartMenuFolders
VC_CustomAction_PreUninstall
VC_CustomAction_PostUninstall
VC_CustomAction_DoChecks
VC_CustomAction_DoChecks
+18
View File
@@ -50,6 +50,12 @@ namespace VeraCrypt
return 1;
}
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
(void) pAbortKeyDerivation;
return DeriveKey (key, password, salt, iterationCount);
}
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Blake2b); }
virtual int GetIterationCount (int pim) const { return 1; }
virtual wstring GetName () const { return L"Argon2"; }
@@ -1204,14 +1210,26 @@ namespace VeraCrypt
0x30, 0x86, 0x51, 0x21, 0x69, 0x94, 0xab, 0xbf,
0xdd, 0xd6, 0x9b, 0x25, 0x92, 0x03, 0x2e, 0xfd
};
static const uint8 argon2Pim1HeaderKeyPrefix[] =
{
0x48, 0x8d, 0x71, 0xbd, 0x71, 0x6e, 0x68, 0x45,
0xaa, 0xe6, 0xe2, 0x29, 0x74, 0x18, 0x2c, 0x20,
0xe9, 0x42, 0x8d, 0x7b, 0x3d, 0x4b, 0xcf, 0x54,
0x04, 0x6c, 0x3e, 0xbe, 0x80, 0x33, 0x8f, 0x20
};
ConstBufferPtr argon2Salt (argon2SaltData, sizeof (argon2SaltData));
Buffer argon2DerivedKey (sizeof (argon2Pim1DerivedKey));
Buffer argon2HeaderKey (ARGON2_HEADER_KEYDATA_SIZE);
// PIM 1 maps to Argon2id t=3, m=64 MiB, p=1.
if (pkcs5Argon2.DeriveKey (argon2DerivedKey, password, 1, argon2Salt) != 0)
throw TestFailed (SRC_POS);
if (memcmp (argon2DerivedKey.Ptr(), argon2Pim1DerivedKey, sizeof (argon2Pim1DerivedKey)) != 0)
throw TestFailed (SRC_POS);
if (pkcs5Argon2.DeriveKey (argon2HeaderKey, password, 1, argon2Salt) != 0)
throw TestFailed (SRC_POS);
if (memcmp (argon2HeaderKey.Ptr(), argon2Pim1HeaderKeyPrefix, sizeof (argon2Pim1HeaderKeyPrefix)) != 0)
throw TestFailed (SRC_POS);
try
{
+90 -3
View File
@@ -23,9 +23,62 @@
#include "Platform/SystemLog.h"
#include "Common/Crypto.h"
#include "EncryptionThreadPool.h"
#include "Pkcs5Kdf.h"
namespace VeraCrypt
{
EncryptionThreadPool::KeyDerivationWorkItem::KeyDerivationWorkItem (shared_ptr <Pkcs5Kdf> kdf, size_t derivedKeySize)
: Completed (false), DerivedKey (derivedKeySize), Kdf (kdf), Processed (false), Result (0)
{
}
EncryptionThreadPool::KeyDerivationWorkItem::~KeyDerivationWorkItem ()
{
}
void EncryptionThreadPool::BeginKeyDerivation (KeyDerivationWorkItem &keyDerivationWorkItem, const VolumePassword &password, int pim, const ConstBufferPtr &salt, SyncEvent &completionEvent, SyncEvent &noOutstandingWorkItemEvent, SharedVal <size_t> &outstandingWorkItemCount, long volatile *abortFlag)
{
if (!ThreadPoolRunning)
throw NotInitialized (SRC_POS);
ScopeLock lock (EnqueueMutex);
WorkItem *workItem = &WorkItemQueue[EnqueuePosition++];
if (EnqueuePosition >= QueueSize)
EnqueuePosition = 0;
while (workItem->State != WorkItem::State::Free)
{
WorkItemCompletedEvent.Wait();
}
keyDerivationWorkItem.Completed.Set (false);
keyDerivationWorkItem.ItemException.reset();
keyDerivationWorkItem.Processed = false;
keyDerivationWorkItem.Result = 0;
workItem->Type = WorkType::DeriveKey;
workItem->KeyDerivation.AbortFlag = abortFlag;
workItem->KeyDerivation.CompletionEvent = &completionEvent;
workItem->KeyDerivation.NoOutstandingWorkItemEvent = &noOutstandingWorkItemEvent;
workItem->KeyDerivation.OutstandingWorkItemCount = &outstandingWorkItemCount;
workItem->KeyDerivation.Password = &password;
workItem->KeyDerivation.Pim = pim;
workItem->KeyDerivation.Salt = salt.Get();
workItem->KeyDerivation.SaltSize = salt.Size();
workItem->KeyDerivation.WorkItem = &keyDerivationWorkItem;
{
ScopeLock outstandingWorkItemLock (KeyDerivationCompletionMutex);
if (outstandingWorkItemCount.Increment() == 1)
noOutstandingWorkItemEvent.Reset();
}
workItem->State.Set (WorkItem::State::Ready);
WorkItemReadyEvent.Signal();
}
void EncryptionThreadPool::DoWork (WorkType::Enum type, const EncryptionMode *encryptionMode, uint8 *data, uint64 startUnitNo, uint64 unitCount, size_t sectorSize)
{
size_t fragmentCount;
@@ -272,21 +325,54 @@ namespace VeraCrypt
workItem->Encryption.Mode->EncryptSectorsCurrentThread (workItem->Encryption.Data, workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.SectorSize);
break;
case WorkType::DeriveKey:
{
KeyDerivationWorkItem *keyDerivationWorkItem = workItem->KeyDerivation.WorkItem;
if (workItem->KeyDerivation.AbortFlag && *workItem->KeyDerivation.AbortFlag)
keyDerivationWorkItem->Result = ERR_USER_ABORT;
else
keyDerivationWorkItem->Result = keyDerivationWorkItem->Kdf->DeriveKey (keyDerivationWorkItem->DerivedKey, *workItem->KeyDerivation.Password, workItem->KeyDerivation.Pim, ConstBufferPtr (workItem->KeyDerivation.Salt, workItem->KeyDerivation.SaltSize), workItem->KeyDerivation.AbortFlag);
}
break;
default:
throw ParameterIncorrect (SRC_POS);
}
}
catch (Exception &e)
{
workItem->FirstFragment->ItemException.reset (e.CloneNew());
if (workItem->Type == WorkType::DeriveKey)
workItem->KeyDerivation.WorkItem->ItemException.reset (e.CloneNew());
else
workItem->FirstFragment->ItemException.reset (e.CloneNew());
}
catch (exception &e)
{
workItem->FirstFragment->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e)));
if (workItem->Type == WorkType::DeriveKey)
workItem->KeyDerivation.WorkItem->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e)));
else
workItem->FirstFragment->ItemException.reset (new ExternalException (SRC_POS, StringConverter::ToExceptionString (e)));
}
catch (...)
{
workItem->FirstFragment->ItemException.reset (new UnknownException (SRC_POS));
if (workItem->Type == WorkType::DeriveKey)
workItem->KeyDerivation.WorkItem->ItemException.reset (new UnknownException (SRC_POS));
else
workItem->FirstFragment->ItemException.reset (new UnknownException (SRC_POS));
}
if (workItem->Type == WorkType::DeriveKey)
{
workItem->KeyDerivation.WorkItem->Completed.Set (true);
workItem->KeyDerivation.CompletionEvent->Signal();
{
ScopeLock outstandingWorkItemLock (KeyDerivationCompletionMutex);
if (workItem->KeyDerivation.OutstandingWorkItemCount->Decrement() == 0)
workItem->KeyDerivation.NoOutstandingWorkItemEvent->Signal();
}
workItem->State.Set (WorkItem::State::Free);
WorkItemCompletedEvent.Signal();
continue;
}
if (workItem != workItem->FirstFragment)
@@ -321,6 +407,7 @@ namespace VeraCrypt
Mutex EncryptionThreadPool::EnqueueMutex;
Mutex EncryptionThreadPool::DequeueMutex;
Mutex EncryptionThreadPool::KeyDerivationCompletionMutex;
SyncEvent EncryptionThreadPool::WorkItemReadyEvent;
SyncEvent EncryptionThreadPool::WorkItemCompletedEvent;
+35
View File
@@ -18,6 +18,9 @@
namespace VeraCrypt
{
class Pkcs5Kdf;
class VolumePassword;
class EncryptionThreadPool
{
public:
@@ -31,6 +34,8 @@ namespace VeraCrypt
};
};
struct KeyDerivationWorkItem;
struct WorkItem
{
struct State
@@ -60,9 +65,37 @@ namespace VeraCrypt
uint64 UnitCount;
size_t SectorSize;
} Encryption;
struct
{
long volatile *AbortFlag;
SyncEvent *CompletionEvent;
SyncEvent *NoOutstandingWorkItemEvent;
SharedVal <size_t> *OutstandingWorkItemCount;
const VolumePassword *Password;
int Pim;
const uint8 *Salt;
size_t SaltSize;
KeyDerivationWorkItem *WorkItem;
} KeyDerivation;
};
};
struct KeyDerivationWorkItem
{
KeyDerivationWorkItem (shared_ptr <Pkcs5Kdf> kdf, size_t derivedKeySize);
~KeyDerivationWorkItem ();
SharedVal <bool> Completed;
SecureBuffer DerivedKey;
unique_ptr <Exception> ItemException;
shared_ptr <Pkcs5Kdf> Kdf;
bool Processed;
int Result;
};
// Caller-owned references and pointers must remain valid until noOutstandingWorkItemEvent is signaled.
static void BeginKeyDerivation (KeyDerivationWorkItem &keyDerivationWorkItem, const VolumePassword &password, int pim, const ConstBufferPtr &salt, SyncEvent &completionEvent, SyncEvent &noOutstandingWorkItemEvent, SharedVal <size_t> &outstandingWorkItemCount, long volatile *abortFlag);
static void DoWork (WorkType::Enum type, const EncryptionMode *mode, uint8 *data, uint64 startUnitNo, uint64 unitCount, size_t sectorSize);
static bool IsRunning () { return ThreadPoolRunning; }
static void Start ();
@@ -78,6 +111,8 @@ namespace VeraCrypt
static volatile size_t DequeuePosition;
static volatile size_t EnqueuePosition;
static Mutex EnqueueMutex;
// Orders KDF outstanding-count transitions against no-outstanding event updates.
static Mutex KeyDerivationCompletionMutex;
static list < shared_ptr <Thread> > RunningThreads;
static volatile bool StopPending;
static size_t ThreadCount;
+72 -10
View File
@@ -30,7 +30,18 @@ namespace VeraCrypt
int Pkcs5Kdf::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const
{
return DeriveKey (key, password, salt, GetIterationCount(pim));
return DeriveKey (key, password, pim, salt, nullptr);
}
int Pkcs5Kdf::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const
{
return DeriveKey (key, password, salt, GetIterationCount(pim), pAbortKeyDerivation);
}
int Pkcs5Kdf::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
(void) pAbortKeyDerivation;
return DeriveKey (key, password, salt, iterationCount);
}
wstring Pkcs5Kdf::GetDerivationFailureMessage (int result) const
@@ -88,65 +99,105 @@ namespace VeraCrypt
#ifndef WOLFCRYPT_BACKEND
int Pkcs5HmacBlake2s_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacBlake2s_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
int Pkcs5HmacBlake2s::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacBlake2s::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_blake2s (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
#endif
int Pkcs5HmacSha256_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacSha256_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
int Pkcs5HmacSha256::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacSha256::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_sha256 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
int Pkcs5HmacSha512::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacSha512::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_sha512 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_sha512 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
#ifndef WOLFCRYPT_BACKEND
int Pkcs5HmacWhirlpool::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacWhirlpool::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_whirlpool (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_whirlpool (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
int Pkcs5HmacStreebog::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacStreebog::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
#ifndef VC_DCS_DISABLE_ARGON2
int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const
{
return DeriveKey (key, password, pim, salt, nullptr);
}
int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const
{
int iterationCount;
int memoryCost;
get_argon2_params (pim, &iterationCount, &memoryCost);
ValidateParameters (key, password, salt, iterationCount);
return derive_key_argon2 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, memoryCost, key.Get(), (int) key.Size(), NULL);
return derive_key_argon2 (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, memoryCost, key.Get(), (int) key.Size(), pAbortKeyDerivation);
}
int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
@@ -158,6 +209,12 @@ namespace VeraCrypt
throw ParameterIncorrect (SRC_POS);
}
int Pkcs5Argon2::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
(void) pAbortKeyDerivation;
return DeriveKey (key, password, salt, iterationCount);
}
wstring Pkcs5Argon2::GetDerivationFailureMessage (int result) const
{
return L"Argon2 key derivation failed: " + StringConverter::ToWide (argon2_error_message (result));
@@ -173,9 +230,14 @@ namespace VeraCrypt
#endif
int Pkcs5HmacStreebog_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const
{
return DeriveKey (key, password, salt, iterationCount, nullptr);
}
int Pkcs5HmacStreebog_Boot::DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const
{
ValidateParameters (key, password, salt, iterationCount);
derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), NULL);
derive_key_streebog (password.DataPtr(), (int) password.Size(), salt.Get(), (int) salt.Size(), iterationCount, key.Get(), (int) key.Size(), pAbortKeyDerivation);
return 0;
}
#endif
+12
View File
@@ -28,7 +28,9 @@ namespace VeraCrypt
virtual ~Pkcs5Kdf ();
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const = 0;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const = 0;
static shared_ptr <Pkcs5Kdf> GetAlgorithm (const wstring &name);
static shared_ptr <Pkcs5Kdf> GetAlgorithm (const Hash &hash);
static Pkcs5KdfList GetAvailableAlgorithms ();
@@ -63,6 +65,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacBlake2s_Boot () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Blake2s); }
virtual int GetDefaultPim () const { return 98; }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : (pim * 2048); }
@@ -81,6 +84,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacBlake2s () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Blake2s); }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 500000 : (15000 + (pim * 1000)); }
virtual wstring GetName () const { return L"HMAC-BLAKE2s-256"; }
@@ -99,6 +103,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacSha256_Boot () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Sha256); }
virtual int GetDefaultPim () const { return 98; }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : (pim * 2048); }
@@ -117,6 +122,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacSha256 () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Sha256); }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 500000 : (15000 + (pim * 1000)); }
virtual wstring GetName () const { return L"HMAC-SHA-256"; }
@@ -134,6 +140,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacSha512 () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Sha512); }
virtual int GetIterationCount (int pim) const { return (pim <= 0 ? 500000 : (15000 + (pim * 1000))); }
virtual wstring GetName () const { return L"HMAC-SHA-512"; }
@@ -151,6 +158,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacWhirlpool () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Whirlpool); }
virtual int GetIterationCount (int pim) const { return (pim <= 0 ? 500000 : (15000 + (pim * 1000))); }
virtual wstring GetName () const { return L"HMAC-Whirlpool"; }
@@ -168,6 +176,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacStreebog () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Streebog); }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 500000 : (15000 + (pim * 1000)); }
virtual wstring GetName () const { return L"HMAC-Streebog"; }
@@ -186,7 +195,9 @@ namespace VeraCrypt
virtual ~Pkcs5Argon2 () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, int pim, const ConstBufferPtr &salt, long volatile *pAbortKeyDerivation) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual wstring GetDerivationFailureMessage (int result) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Blake2b); }
virtual int GetDefaultPim () const { return 12; }
@@ -212,6 +223,7 @@ namespace VeraCrypt
virtual ~Pkcs5HmacStreebog_Boot () { }
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount) const;
virtual int DeriveKey (const BufferPtr &key, const VolumePassword &password, const ConstBufferPtr &salt, int iterationCount, long volatile *pAbortKeyDerivation) const;
virtual shared_ptr <Hash> GetHash () const { return shared_ptr <Hash> (new Streebog); }
virtual int GetDefaultPim () const { return 98; }
virtual int GetIterationCount (int pim) const { return pim <= 0 ? 200000 : pim * 2048; }
+144 -40
View File
@@ -11,18 +11,27 @@
*/
#include "Crc32.h"
#include "EncryptionThreadPool.h"
#include "EncryptionModeXTS.h"
#ifdef WOLFCRYPT_BACKEND
#include "EncryptionModeWolfCryptXTS.h"
#endif
#include "Pkcs5Kdf.h"
#include "Pkcs5Kdf.h"
#include "VolumeHeader.h"
#include "VolumeException.h"
#include "Common/Crypto.h"
namespace VeraCrypt
{
static void DrainKeyDerivationWorkItems (SyncEvent &noOutstandingWorkItemEvent, size_t enqueuedWorkItemCount, bool &workItemsDrained)
{
if (enqueuedWorkItemCount > 0 && !workItemsDrained)
{
noOutstandingWorkItemEvent.Wait();
workItemsDrained = true;
}
}
VolumeHeader::VolumeHeader (uint32 size)
{
Init();
@@ -99,14 +108,83 @@ namespace VeraCrypt
throw PasswordEmpty (SRC_POS);
ConstBufferPtr salt (encryptedData.GetRange (SaltOffset, SaltSize));
SecureBuffer header (EncryptedHeaderDataSize);
SecureBuffer headerKey (GetLargestSerializedKeySize());
if (!kdf && EncryptionThreadPool::IsRunning() && keyDerivationFunctions.size() > 1)
{
typedef EncryptionThreadPool::KeyDerivationWorkItem KeyDerivationWorkItem;
list < shared_ptr <KeyDerivationWorkItem> > keyDerivationWorkItems;
SharedVal <size_t> outstandingWorkItemCount (0);
SyncEvent keyDerivationCompletedEvent;
SyncEvent noOutstandingWorkItemEvent;
long volatile abortKeyDerivation = 0;
size_t enqueuedWorkItemCount = 0;
size_t processedWorkItemCount = 0;
bool workItemsDrained = false;
try
{
foreach (shared_ptr <Pkcs5Kdf> pkcs5, keyDerivationFunctions)
{
shared_ptr <KeyDerivationWorkItem> keyDerivationWorkItem (new KeyDerivationWorkItem (pkcs5, GetHeaderKeyDerivationSize (pkcs5)));
keyDerivationWorkItems.push_back (keyDerivationWorkItem);
EncryptionThreadPool::BeginKeyDerivation (*keyDerivationWorkItem, password, pim, salt, keyDerivationCompletedEvent, noOutstandingWorkItemEvent, outstandingWorkItemCount, &abortKeyDerivation);
++enqueuedWorkItemCount;
}
while (processedWorkItemCount < keyDerivationWorkItems.size())
{
bool processed = false;
foreach (shared_ptr <KeyDerivationWorkItem> keyDerivationWorkItem, keyDerivationWorkItems)
{
if (!keyDerivationWorkItem->Processed && keyDerivationWorkItem->Completed.Get())
{
keyDerivationWorkItem->Processed = true;
++processedWorkItemCount;
processed = true;
if (keyDerivationWorkItem->ItemException.get())
{
// KDF exceptions are fatal setup/runtime errors; candidate failures are reported via Result.
abortKeyDerivation = 1;
DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained);
keyDerivationWorkItem->ItemException->Throw();
}
if (keyDerivationWorkItem->Result != 0)
continue;
if (DecryptWithHeaderKey (encryptedData, keyDerivationWorkItem->Kdf, keyDerivationWorkItem->DerivedKey, encryptionAlgorithms, encryptionModes))
{
abortKeyDerivation = 1;
DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained);
return true;
}
}
}
if (processedWorkItemCount < keyDerivationWorkItems.size() && !processed)
keyDerivationCompletedEvent.Wait();
}
}
catch (...)
{
abortKeyDerivation = 1;
DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained);
throw;
}
DrainKeyDerivationWorkItems (noOutstandingWorkItemEvent, enqueuedWorkItemCount, workItemsDrained);
return false;
}
foreach (shared_ptr <Pkcs5Kdf> pkcs5, keyDerivationFunctions)
{
if (kdf && (kdf->GetName() != pkcs5->GetName()))
continue;
SecureBuffer headerKey (GetHeaderKeyDerivationSize (pkcs5));
int derivationResult = pkcs5->DeriveKey (headerKey, password, pim, salt);
if (derivationResult != 0)
{
@@ -116,50 +194,66 @@ namespace VeraCrypt
throw ExternalException (SRC_POS, pkcs5->GetDerivationFailureMessage (derivationResult));
}
foreach (shared_ptr <EncryptionMode> mode, encryptionModes)
if (DecryptWithHeaderKey (encryptedData, pkcs5, headerKey, encryptionAlgorithms, encryptionModes))
return true;
}
return false;
}
bool VolumeHeader::DecryptWithHeaderKey (const ConstBufferPtr &encryptedData, shared_ptr <Pkcs5Kdf> pkcs5, const ConstBufferPtr &headerKey, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes)
{
SecureBuffer header (EncryptedHeaderDataSize);
foreach (shared_ptr <EncryptionMode> mode, encryptionModes)
{
#ifdef WOLFCRYPT_BACKEND
bool xtsMode = typeid (*mode) == typeid (EncryptionModeWolfCryptXTS);
#else
bool xtsMode = typeid (*mode) == typeid (EncryptionModeXTS);
#endif
if (!xtsMode)
{
#ifdef WOLFCRYPT_BACKEND
if (typeid (*mode) != typeid (EncryptionModeWolfCryptXTS))
#else
if (typeid (*mode) != typeid (EncryptionModeXTS))
#endif
mode->SetKey (headerKey.GetRange (0, mode->GetKeySize()));
if (mode->GetKeySize() > headerKey.Size())
continue;
mode->SetKey (headerKey.GetRange (0, mode->GetKeySize()));
}
foreach (shared_ptr <EncryptionAlgorithm> ea, encryptionAlgorithms)
foreach (shared_ptr <EncryptionAlgorithm> ea, encryptionAlgorithms)
{
if (!ea->IsModeSupported (mode))
continue;
size_t requiredHeaderKeySize = xtsMode ? ea->GetKeySize() * 2 : LegacyEncryptionModeKeyAreaSize + ea->GetKeySize();
if (requiredHeaderKeySize > headerKey.Size())
continue;
if (xtsMode)
{
if (!ea->IsModeSupported (mode))
continue;
ea->SetKey (headerKey.GetRange (0, ea->GetKeySize()));
#ifdef WOLFCRYPT_BACKEND
ea->SetKeyXTS (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize()));
#endif
#ifndef WOLFCRYPT_BACKEND
if (typeid (*mode) == typeid (EncryptionModeXTS))
{
ea->SetKey (headerKey.GetRange (0, ea->GetKeySize()));
#else
if (typeid (*mode) == typeid (EncryptionModeWolfCryptXTS))
{
ea->SetKey (headerKey.GetRange (0, ea->GetKeySize()));
ea->SetKeyXTS (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize()));
#endif
mode = mode->GetNew();
mode->SetKey (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize()));
}
else
{
ea->SetKey (headerKey.GetRange (LegacyEncryptionModeKeyAreaSize, ea->GetKeySize()));
}
mode = mode->GetNew();
mode->SetKey (headerKey.GetRange (ea->GetKeySize(), ea->GetKeySize()));
}
else
{
ea->SetKey (headerKey.GetRange (LegacyEncryptionModeKeyAreaSize, ea->GetKeySize()));
}
ea->SetMode (mode);
ea->SetMode (mode);
header.CopyFrom (encryptedData.GetRange (EncryptedHeaderDataOffset, EncryptedHeaderDataSize));
ea->Decrypt (header);
header.CopyFrom (encryptedData.GetRange (EncryptedHeaderDataOffset, EncryptedHeaderDataSize));
ea->Decrypt (header);
if (Deserialize (header, ea, mode))
{
EA = ea;
Pkcs5 = pkcs5;
return true;
}
if (Deserialize (header, ea, mode))
{
EA = ea;
Pkcs5 = pkcs5;
return true;
}
}
}
@@ -319,6 +413,16 @@ namespace VeraCrypt
Pkcs5 = newPkcs5Kdf;
}
size_t VolumeHeader::GetHeaderKeyDerivationSize (shared_ptr <Pkcs5Kdf> kdf)
{
#ifndef VC_DCS_DISABLE_ARGON2
if (kdf && kdf->IsArgon2())
return ARGON2_HEADER_KEYDATA_SIZE;
#endif
return GetLargestSerializedKeySize();
}
size_t VolumeHeader::GetLargestSerializedKeySize ()
{
size_t largestKey = EncryptionAlgorithm::GetLargestKeySize (EncryptionAlgorithm::GetAvailableAlgorithms());
+2
View File
@@ -68,6 +68,7 @@ namespace VeraCrypt
uint32 GetFlags () const { return Flags; }
VolumeTime GetHeaderCreationTime () const { return HeaderCreationTime; }
uint64 GetHiddenVolumeDataSize () const { return HiddenVolumeDataSize; }
static size_t GetHeaderKeyDerivationSize (shared_ptr <Pkcs5Kdf> kdf);
static size_t GetLargestSerializedKeySize ();
shared_ptr <Pkcs5Kdf> GetPkcs5Kdf () const { return Pkcs5; }
uint16 GetRequiredMinProgramVersion () const { return RequiredMinProgramVersion; }
@@ -79,6 +80,7 @@ namespace VeraCrypt
bool IsMasterKeyVulnerable () const { return XtsKeyVulnerable; }
protected:
bool DecryptWithHeaderKey (const ConstBufferPtr &encryptedData, shared_ptr <Pkcs5Kdf> pkcs5, const ConstBufferPtr &headerKey, const EncryptionAlgorithmList &encryptionAlgorithms, const EncryptionModeList &encryptionModes);
bool Deserialize (const ConstBufferPtr &header, shared_ptr <EncryptionAlgorithm> &ea, shared_ptr <EncryptionMode> &mode);
template <typename T> T DeserializeEntry (const ConstBufferPtr &header, size_t &offset) const;
template <typename T> T DeserializeEntryAt (const ConstBufferPtr &header, const size_t &offset) const;