Skip to content

Commit e72f495

Browse files
Addressing #50, optimization and fix of tohex() (#53)
* This optimizes tohex() a fair bit * Also fixes the link I missed in November to the old osslsignicode project page in the README * Made the unit tests for hashes case-insensitive; this should capture the spirit of the string representation of strings better. Where it _truly_ matters, a case-sensitive check can explicitly be used. * Added checks against the expected (string) length for the known hashes * Replaced a number of the literal hashes given in the unit tests. It turns out the old tohex() was not just slower but also had a defect which caused leading '0' in the hexadecimal representation of bytes to disappear. The resulting strings also had irregular sizes. Below a list of the wrong and correct string representation (duplicates included): 6663dd7c24fa84fce7f16eb2689952c06cfa22 6663dd7c24fa84fce7f16e0b02689952c06cfa22 2559e91a60953a5e16f965f5f88953a2cca5425 2559e91a60953a5e16f9650f5f88953a2cca5425 f1c260304ec64414a97e10cb19dd4c755f9e7079f85feb38ee7ff9f938db99 f10c2600304ec64414a97e10cb19dd4c755f9e7079f85feb38ee7ff9f938db99 ddc5b39c429212745eb86a67eaa331032cc5a0dafaf6e28ec9aaf189c408d ddc5b39c4292120745eb86a67eaa331032cc05a0dafaf6e28ec9aa0f189c408d 6f7ac8c1754fad04fba2a552a122e7 6f7ac8c17504fad04fba2a552a122e07 4ba4c91418e28cb63b97cfde1cff95a91139 4ba40c91418e28cb630b97cfde1cff0905a91139 e260f8a57faa823453bd9552506878fcbfb33203d9b606cb9a27e605a8d7b e260f8a57faa823453bd95525068780fcbfb0332003d9b606cb9a27e605a8d7b 6663dd7c24fa84fce7f16eb2689952c06cfa22 6663dd7c24fa84fce7f16e0b02689952c06cfa22 ea13992f99840f76dcac225dd1262edcec3254511b250a6d1e98d99fc48f815 ea013992f99840f76dcac225dd1262edcec3254511b250a6d1e98d99fc48f815 ea235b77d552633c5a38974cef0e2b5 ea0235b77d552633c5a38974cef0e2b5 2559e91a60953a5e16f965f5f88953a2cca5425 2559e91a60953a5e16f9650f5f88953a2cca5425 5c823491c5991914aec971d9456d93d6cf2b8ee7e0ed7abcb7731d8ec073c0 5c823491c5991914aec971d9456d93d6cf2b8ee7e0ed7abc0b77031d8ec073c0
1 parent 104388d commit e72f495

File tree

4 files changed

+46
-23
lines changed

4 files changed

+46
-23
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ Other available solutions are deficient:
2727

2828
* WINE implements most of `Wintrust`, but is a massive (and arguably non-native) dependency
2929
for a single task.
30-
* [`osslsigncode`](https://sourceforge.net/projects/osslsigncode/) can add signatures and check
31-
timestamps, but is long-abandoned and CLI-focused.
30+
* [`osslsigncode`](https://github.com/mtrojnar/osslsigncode) can add signatures and check
31+
timestamps, but is CLI-focused.
3232

3333
## Beware!
3434

src/uthenticode.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,21 @@ static inline std::size_t round(std::size_t x, std::size_t factor) {
6565
* @return the hex string
6666
*/
6767
static inline std::string tohex(std::uint8_t *buf, std::size_t len) {
68-
if (buf == nullptr) {
68+
constexpr static char lookup_table[] = "0123456789ABCDEF";
69+
70+
if (!buf || !len) {
6971
return {};
7072
}
7173

72-
std::stringstream ss;
73-
ss << std::hex << std::setw(2) << std::setfill('0');
74+
std::string hexstr;
75+
hexstr.reserve(len * 2); // each byte creates two hex digits
7476

75-
for (std::size_t i = 0; i < len; ++i) {
76-
ss << static_cast<int>(buf[i]);
77+
for (auto i = 0; i < len; i++) {
78+
hexstr += lookup_table[buf[i] >> 4];
79+
hexstr += lookup_table[buf[i] & 0xF];
7780
}
7881

79-
return ss.str();
82+
return hexstr;
8083
}
8184

8285
/**

test/signeddata-test.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ TEST_F(Auth32Test, SignedData_properties) {
1818

1919
auto checksum = signed_data->get_checksum();
2020
ASSERT_EQ(std::get<uthenticode::checksum_kind>(checksum), uthenticode::checksum_kind::SHA1);
21-
ASSERT_EQ(std::get<std::string>(checksum), "6663dd7c24fa84fce7f16eb2689952c06cfa22");
21+
auto const checksumstr = std::get<std::string>(checksum);
22+
ASSERT_EQ(checksumstr.size(), 40);
23+
ASSERT_STRCASEEQ(checksumstr.c_str(), "6663dd7c24fa84fce7f16e0b02689952c06cfa22");
2224

2325
ASSERT_EQ(signed_data->get_nested_signed_data(), std::nullopt);
2426
}
@@ -36,7 +38,9 @@ TEST_F(Auth32PlusTest, SignedData_properties) {
3638

3739
auto checksum = signed_data->get_checksum();
3840
ASSERT_EQ(std::get<uthenticode::checksum_kind>(checksum), uthenticode::checksum_kind::SHA1);
39-
ASSERT_EQ(std::get<std::string>(checksum), "2559e91a60953a5e16f965f5f88953a2cca5425");
41+
auto const checksumstr = std::get<std::string>(checksum);
42+
ASSERT_EQ(checksumstr.size(), 40);
43+
ASSERT_STRCASEEQ(checksumstr.c_str(), "2559e91a60953a5e16f9650f5f88953a2cca5425");
4044

4145
ASSERT_EQ(signed_data->get_nested_signed_data(), std::nullopt);
4246
}
@@ -59,8 +63,10 @@ TEST_F(AuthNest32Test, SignedData_properties_nested) {
5963

6064
auto checksum = nested_signed_data->get_checksum();
6165
ASSERT_EQ(std::get<uthenticode::checksum_kind>(checksum), uthenticode::checksum_kind::SHA256);
62-
ASSERT_EQ(std::get<std::string>(checksum),
63-
"f1c260304ec64414a97e10cb19dd4c755f9e7079f85feb38ee7ff9f938db99");
66+
auto const checksumstr = std::get<std::string>(checksum);
67+
ASSERT_EQ(checksumstr.size(), 64);
68+
ASSERT_STRCASEEQ(checksumstr.c_str(),
69+
"f10c2600304ec64414a97e10cb19dd4c755f9e7079f85feb38ee7ff9f938db99");
6470
}
6571

6672
TEST_F(AuthNest32PlusTest, SignedData_properties_nested) {
@@ -81,6 +87,8 @@ TEST_F(AuthNest32PlusTest, SignedData_properties_nested) {
8187

8288
auto checksum = nested_signed_data->get_checksum();
8389
ASSERT_EQ(std::get<uthenticode::checksum_kind>(checksum), uthenticode::checksum_kind::SHA256);
84-
ASSERT_EQ(std::get<std::string>(checksum),
85-
"ddc5b39c429212745eb86a67eaa331032cc5a0dafaf6e28ec9aaf189c408d");
90+
auto const checksumstr = std::get<std::string>(checksum);
91+
ASSERT_EQ(checksumstr.size(), 64);
92+
ASSERT_STRCASEEQ(checksumstr.c_str(),
93+
"ddc5b39c4292120745eb86a67eaa331032cc05a0dafaf6e28ec9aa0f189c408d");
8694
}

test/uthenticode-test.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,41 +57,53 @@ TEST_F(NoAuthTest, calculate_checksum) {
5757
EXPECT_TRUE(unk.empty());
5858

5959
auto md5 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::MD5);
60-
EXPECT_EQ(md5, "6f7ac8c1754fad04fba2a552a122e7");
60+
EXPECT_EQ(md5.size(), 32);
61+
EXPECT_STRCASEEQ(md5.c_str(), "6f7ac8c17504fad04fba2a552a122e07");
6162

6263
auto sha1 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::SHA1);
63-
EXPECT_EQ(sha1, "4ba4c91418e28cb63b97cfde1cff95a91139");
64+
EXPECT_EQ(sha1.size(), 40);
65+
EXPECT_STRCASEEQ(sha1.c_str(), "4ba40c91418e28cb630b97cfde1cff0905a91139");
6466

6567
auto sha256 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::SHA256);
66-
EXPECT_EQ(sha256, "e260f8a57faa823453bd9552506878fcbfb33203d9b606cb9a27e605a8d7b");
68+
EXPECT_EQ(sha256.size(), 64);
69+
EXPECT_STRCASEEQ(sha256.c_str(),
70+
"e260f8a57faa823453bd95525068780fcbfb0332003d9b606cb9a27e605a8d7b");
6771
}
6872

6973
TEST_F(Auth32Test, calculate_checksum) {
7074
auto unk = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::UNKNOWN);
7175
EXPECT_TRUE(unk.empty());
7276

7377
auto md5 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::MD5);
74-
EXPECT_EQ(md5, "64c29391b57679b2973ac562cf64685d");
78+
EXPECT_EQ(md5.size(), 32);
79+
EXPECT_STRCASEEQ(md5.c_str(), "64c29391b57679b2973ac562cf64685d");
7580

7681
auto sha1 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::SHA1);
77-
EXPECT_EQ(sha1, "6663dd7c24fa84fce7f16eb2689952c06cfa22");
82+
EXPECT_EQ(sha1.size(), 40);
83+
EXPECT_STRCASEEQ(sha1.c_str(), "6663dd7c24fa84fce7f16e0b02689952c06cfa22");
7884

7985
auto sha256 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::SHA256);
80-
EXPECT_EQ(sha256, "ea13992f99840f76dcac225dd1262edcec3254511b250a6d1e98d99fc48f815");
86+
EXPECT_EQ(sha256.size(), 64);
87+
EXPECT_STRCASEEQ(sha256.c_str(),
88+
"ea013992f99840f76dcac225dd1262edcec3254511b250a6d1e98d99fc48f815");
8189
}
8290

8391
TEST_F(Auth32PlusTest, calculate_checksum) {
8492
auto unk = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::UNKNOWN);
8593
EXPECT_TRUE(unk.empty());
8694

8795
auto md5 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::MD5);
88-
EXPECT_EQ(md5, "ea235b77d552633c5a38974cef0e2b5");
96+
EXPECT_EQ(md5.size(), 32);
97+
EXPECT_STRCASEEQ(md5.c_str(), "ea0235b77d552633c5a38974cef0e2b5");
8998

9099
auto sha1 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::SHA1);
91-
EXPECT_EQ(sha1, "2559e91a60953a5e16f965f5f88953a2cca5425");
100+
EXPECT_EQ(sha1.size(), 40);
101+
EXPECT_STRCASEEQ(sha1.c_str(), "2559e91a60953a5e16f9650f5f88953a2cca5425");
92102

93103
auto sha256 = uthenticode::calculate_checksum(pe, uthenticode::checksum_kind::SHA256);
94-
EXPECT_EQ(sha256, "5c823491c5991914aec971d9456d93d6cf2b8ee7e0ed7abcb7731d8ec073c0");
104+
EXPECT_EQ(sha256.size(), 64);
105+
EXPECT_STRCASEEQ(sha256.c_str(),
106+
"5c823491c5991914aec971d9456d93d6cf2b8ee7e0ed7abc0b77031d8ec073c0");
95107
}
96108

97109
TEST(verify, handles_nullptr) {

0 commit comments

Comments
 (0)