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

Tests: cover the security-critical paths of the crypto and platform layers.#1850
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 — 1133 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 handling, 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.

Merge order

Please merge #1844 first. Both PRs touch src/Volume/EncryptionTest.{cpp,h}; the changes are
independent, but #1844 declares its method before TestCiphers while this branch inserts
after it. A plain git apply of #1844 onto this branch fails on the header context, while
git apply -3, a merge or a rebase all succeed. Merging #1844 first avoids the question. I
will rebase this branch afterwards.

Coverage

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

File before after
Volume/Hash.cpp 0.00 % 96.88 %
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 % 58.95 %
Volume/VolumeInfo.cpp 3.16 % 73.68 %
Platform/FileCommon.cpp 23.26 % 86.05 %
Core/MountOptions.cpp 27.12 % 85.59 %
Platform/Memory.cpp 41.18 % 91.18 %
Volume/VolumePassword.cpp 45.83 % 100.00 %
Volume/Pkcs5Kdf.cpp 50.48 % 70.48 %
Volume/Cipher.cpp 73.24 % 83.57 %
Platform/Buffer.cpp 75.76 % 83.84 %
Volume/EncryptionAlgorithm.cpp 78.28 % 93.43 %
Volume/VolumeHeader.cpp 81.37 % 83.01 %
Volume/EncryptionModeXTS.cpp 91.39 % 93.38 %
Platform/StringConverter.cpp 43.29 % 61.90 %

17 files improved, five of them starting from zero.

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 the new test itself reports it. 27 injected defects in
total, 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 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 — Docker ubuntu:24.04, GCC 13, distribution wxWidgets 3.2, make NOGUI=1. 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 — 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 59 %. 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.

@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.

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