Repository navigation
Speed up PE checksum calculation - #513
Open
francoisgirinon-netizen wants to merge 2 commits into
Open
francoisgirinon-netizen wants to merge 2 commits into
francoisgirinon-netizen wants to merge 2 commits into
Conversation
Sum the 16-bit words of the file in a 64-bit accumulator and fold the result once, instead of folding after every word. The one's complement sum is mathematically the same, and the result is unchanged. pe_calc_realchecksum() no longer copies each 64 KB block through a memory BIO before summing it. Verified against the previous algorithm on 200000 random and edge case inputs (all zero, all 0xFF, odd lengths, any header size, any chunking), and the signed and unsigned output files are byte identical. On a 3.7 GB PE file, verify takes 15% less time and remove-signature 15%.
Sign PE files with overlays of odd and even sizes and of different contents, and compare the CheckSum field with the checksum computed by a Python implementation of the documented algorithm. A wrong fold or a wrong exclusion of the CheckSum field in pe_checksum_sum() and pe_checksum_fold() makes every case fail.
Owner
|
Is the performance improvement significant compared to the time already used for comparing cryptographic hash? 15% does not seem like a significant justification. My point: "if it ain't broke, don't fix it". |
Contributor
Author
|
Measured on the largest PE file that can be verified (4,294,960,000 bytes, SHA-256, file in cache, old and new builds run alternately):
For reference, The change is covered by tests that compare the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request Type
Related Issue
Issue number: N/A
Current Behavior
The PE checksum is a one's complement sum of the 16-bit words of the file. It is
computed with a carry fold after every word, and
pe_calc_realchecksum()copieseach 64 KB block through a memory BIO before summing it. On a 3.7 GB PE file this
makes
verifyandremove-signatureslower than necessary.New Behavior
The 16-bit words are added in a 64-bit accumulator and folded once at the end.
The one's complement sum is mathematically the same, so the checksum is unchanged.
pe_calc_realchecksum()sums the mapped input directly, without the BIO copy.On a 3.7 GB PE file
verifytakes 15% less time andremove-signature15%.Scope of Changes
pe.c: addpe_checksum_sum()andpe_checksum_fold(), used bype_calc_checksum()andpe_calc_realchecksum().The 64-bit accumulator cannot overflow: a file is limited to 4 GB, so at most
2^31 words of at most 0xFFFF are added.
tests/check_pe_checksum.py,cmake/CMakeTest.cmake: tests of theCheckSumfield.Testing
Existing tests
New tests added
Manual testing
ctest: 387/387 passed on Linux x86-64 (OpenSSL 3.5), withoutLARGE_FILE_TESTS.New tests
checksum_*: signtests/files/unsigned.exewith an overlay of 1, 3, 65537or 300001 bytes (filled with 0x00, 0x7F or 0xFF) and compare the
CheckSumfield ofthe signed file with
tests/check_pe_checksum.py, an independent implementation ofthe documented algorithm. They also pass on the previous algorithm. With a wrong fold
or a wrong exclusion of the
CheckSumfield inpe_checksum_sum()/pe_checksum_fold(),every case fails.
The result was compared with the previous algorithm on 200000 random and edge case
inputs (all zero, all 0xFF, odd lengths, any header size, any chunking).
The signed and unsigned output files are byte identical.
Not tested: Windows, macOS, 32-bit builds.
Additional Notes
License Declaration