Skip to content

Tests: cover the security-critical paths of the crypto and platform layers. - #1850

Open
bernardladenthin wants to merge 1 commit into
veracrypt:masterfrom
bernardladenthin:encryption-edge-case-tests
Open

bernardladenthin wants to merge 1 commit into
veracrypt:masterfrom
bernardladenthin:encryption-edge-case-tests

Conversation

@bernardladenthin

@bernardladenthin bernardladenthin commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds 14 test blocks to the existing self-test suites. No production code is touched and no
existing test is modified — 1100 lines, additions only, across 6 files:

File Blocks added
src/Volume/EncryptionTest.cpp / .h 8 — API rejection paths, hash wrappers, KDF selection, volume-header rejection, password comparison and cache, keyfile mixing, VolumeInfo round trip, volume layouts
src/Platform/PlatformTest.cpp / .h 4 — Buffer/SecureBuffer/Memory, StringConverter, file operations, exception transport
src/Main/UserInterface.cpp / .h 2 — random number generator, MountOptions round trip

The tests target paths the existing known-answer tests never reach, because those only ever
take the success path: rejection of bad parameters, uninitialised state, out-of-range access,
and the serialisation round trips that cross the IPC boundary to the privileged core service.

Rebased

Rebased on master @ fe33e447 after #1844 was merged, without conflicts. Since this PR was
opened, CoreTest::VolumePasswordTest arrived upstream and covers the password size limit and
the serialised round trip, so those two parts of TestPasswordHandling were removed instead of
testing the same thing twice. What remains there is the comparison of two different passwords
and the password cache. All coverage figures and the password rows of the detection proof
below were measured again on the rebased branch.

Coverage

Measured A/B in a single binary — same build, the new test calls commented out for the
baseline — using gcov. Base is master @ fe33e447.

File before after
Volume/VolumeLayout.cpp 0.00 % 95.14 %
Volume/VolumePasswordCache.cpp 0.00 % 94.44 %
Core/RandomNumberGenerator.cpp 0.00 % 84.51 %
Volume/Keyfile.cpp 0.00 % 57.73 %
Volume/Hash.cpp 13.54 % 96.88 %
Volume/VolumeInfo.cpp 3.19 % 73.40 %
Platform/FileCommon.cpp 23.26 % 86.05 %
Core/MountOptions.cpp 27.35 % 85.47 %
Platform/Memory.cpp 79.41 % 91.18 %
Volume/VolumePassword.cpp 92.16 % 98.04 %
Volume/Pkcs5Kdf.cpp 50.48 % 70.48 %
Volume/Cipher.cpp 73.24 % 83.57 %
Platform/Buffer.cpp 77.78 % 83.84 %
Volume/EncryptionAlgorithm.cpp 78.28 % 93.43 %
Volume/VolumeHeader.cpp 81.90 % 83.49 %
Volume/EncryptionModeXTS.cpp 91.39 % 93.38 %
Platform/StringConverter.cpp 40.41 % 57.96 %

17 files improved, four of them starting from zero. The tests that arrived upstream in the
meantime raised several baselines (VolumePassword.cpp, Memory.cpp, Hash.cpp).

Coverage was produced without modifying any build file, using the existing hooks in
src/Makefile:

make NOGUI=1 NOTEST=1 \
     TC_EXTRA_CFLAGS="--coverage -O0" \
     TC_EXTRA_CXXFLAGS="--coverage -O0" \
     TC_EXTRA_LFLAGS="--coverage"

A note for anyone repeating this: use gcov directly. Both lcov and gcovr mis-attribute
results here, because each subproject is built through make -C and the working directory
recorded in the .gcno files cannot be resolved afterwards. lcov reported one file at 8.7 %
where the true figure is 91.4 %, and produced merged totals lower than the individual runs.

Detection proof

Coverage alone does not show that a test would catch anything, so every block was verified by
injecting a defect and confirming that a test reports it. 27 injected defects when the PR was
opened; the password defects were injected again after the rebase. Among them:

Injected defect Reported by
Buffer::Erase no longer wipes BufferTest
Buffer::GetRange skips its bounds check BufferTest
Memory::Compare inverts its ordering BufferTest
keyfile contributes nothing to the password pool TestKeyfileApplication
base password dropped from the keyfile pool TestKeyfileApplication
empty keyfile silently accepted TestKeyfileApplication
MountOptions loses the protection mode in transit TestMountOptionsSerialization
password truncated in transit CoreTest::VolumePasswordTest (upstream; the duplicate block was removed)
password comparison ignores the last byte TestPasswordHandling
password cache grows without bound TestPasswordHandling
password cache stops deduplicating TestPasswordHandling
RNG returns constant data TestRandomNumberGenerator
RNG usable before Start() TestRandomNumberGenerator
oversized RNG request not rejected TestRandomNumberGenerator
File::Copy truncates the copy FileTest
ReadCompleteBuffer accepts short reads FileTest
exception subject dropped on the IPC path ExceptionTransportTest
cipher accepts block operations before a key is set TestEdgeCases
SetKey accepts a wrong-length key TestEdgeCases
hash accepts empty input TestHashClasses
KDF lookup matches any name TestKdfSelection
volume layout reports a data area past the end of the host TestVolumeLayouts

One side effect worth mentioning: the random number generator carries its own pool-mixing
known-answer self-test inside Start(). That self-test previously ran only when the graphical
or the text interface started the generator — --test never started it, so it never ran under
CI. It does now.

Verification environment

Linux — when the PR was opened: Docker ubuntu:24.04, GCC 13, distribution wxWidgets 3.2,
make NOGUI=1. After the rebase: Docker debian:trixie (amd64, GCC 14) for the build (0 warnings),
three --test runs and the coverage and defect runs above; and Alpine 3.22 i386 (musl) with this
branch merged with the pending i386/sparc64 build fixes: 0 warnings, three --test runs. The
repository is mounted read-only and copied into the container before building, so no build
artefacts touch the working tree. The self-tests were run twice to confirm repeatability, and
the temporary files created by the keyfile and file tests are removed even when an assertion
fires.

Windows — when the PR was opened, Visual Studio 2022 17.14.37, MSVC 14.44.35228, Windows SDK 10.0.26100.0,
WDK 10.0.26100. Each affected translation unit was compiled in user mode at /W4 and in
kernel mode at /W4 /WX, matching the TreatWarningAsError setting in Driver.vcxproj.

None of the six changed files appears in any .vcxproj, so the Windows build cannot be
affected by this change. The compile checks were run regardless.

Limitations

  • Volume/VolumeHeader.cpp moves by only 1.6 pp. Its remaining uncovered part is the
    decrypt-attempt loop, which needs a real encrypted volume — out of scope for a unit test.
  • Volume/Keyfile.cpp stops at 58 %. The remaining branches are the security-token and
    directory-enumeration paths, which need a token or a populated directory.
  • The repository has no Windows CI job, so the Windows half of these tests runs only when
    Format, Mount or ExpandVolume actually start, not automatically.

AI assistance

These tests were written with the assistance of Anthropic's Claude Opus. Every claim in this
description — the coverage figures, the injected-defect results, the build and warning output
— was produced by running the builds and measurements described above rather than estimated.
The changes are additive and confined to test code; review of the assertions themselves is of
course still welcome.

Assisted by Claude Opus 5.5

@bernardladenthin

Copy link
Copy Markdown
Contributor Author

Please merge #1844 before this PR. Both touch src/Volume/EncryptionTest.{cpp,h}, and while
the changes are independent (different functions, no overlapping assertions), applying them in
the other order requires a three-way merge — a plain git apply of #1844 will fail against
this branch's header. Merging #1844 first avoids that entirely; I will rebase this branch on
the updated master afterwards.

@bernardladenthin
bernardladenthin force-pushed the encryption-edge-case-tests branch from 92aa8d8 to db77f3c Compare October 14, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant