Skip to content

Commit 587239d

Browse files
committedMar 24, 2022
Merge #731: Change SHA256 byte counter from size_t to uint64_t
f8d9174 Add SHA256 bit counter tests (Tim Ruffing) 9b514ce Add test vector for very long SHA256 messages (Tim Ruffing) 8e3dde1 Simplify struct initializer for SHA256 padding (Tim Ruffing) eb28464 Change SHA256 byte counter from size_t to uint64_t (Tim Ruffing) Pull request description: This avoids that the SHA256 implementation would produce wrong paddings and thus wrong digests for messages of length >= 2^32 bytes on 32-bit platforms. This is not exploitable in any way since the SHA256 API is an internal API and we never call it with that long messages. This also simplifies the struct initializer for the padding. Since missing elements are initialized with zeros, this change is purely syntactical. ACKs for top commit: sipa: utACK f8d9174 jonasnick: ACK f8d9174 Tree-SHA512: 4fba64b255ef34bb144e4ac6d796798d620d6a7a0f3be409a46b98a8aedb129be19a6816b07caa4d1a3862a01769b42ce70240690fddc6231d591e6c06252750
2 parents e0508ee + f8d9174 commit 587239d

File tree

3 files changed

+139
-13
lines changed

3 files changed

+139
-13
lines changed
 

‎src/hash.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
typedef struct {
1414
uint32_t s[8];
1515
uint32_t buf[16]; /* In big endian */
16-
size_t bytes;
16+
uint64_t bytes;
1717
} secp256k1_sha256;
1818

1919
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);

‎src/hash_impl.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,12 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
149149
}
150150

151151
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
152-
static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
152+
static const unsigned char pad[64] = {0x80};
153153
uint32_t sizedesc[2];
154154
uint32_t out[8];
155155
int i = 0;
156+
/* The maximum message size of SHA256 is 2^64-1 bits. */
157+
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
156158
sizedesc[0] = BE32(hash->bytes >> 29);
157159
sizedesc[1] = BE32(hash->bytes << 3);
158160
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));

‎src/tests.c

+135-11
Original file line numberDiff line numberDiff line change
@@ -451,42 +451,165 @@ void run_ctz_tests(void) {
451451

452452
/***** HASH TESTS *****/
453453

454-
void run_sha256_tests(void) {
455-
static const char *inputs[8] = {
454+
void run_sha256_known_output_tests(void) {
455+
static const char *inputs[] = {
456456
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
457457
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
458458
"For this sample, this 63-byte string will be used as input data",
459-
"This is exactly 64 bytes long, not counting the terminating byte"
459+
"This is exactly 64 bytes long, not counting the terminating byte",
460+
"aaaaa",
460461
};
461-
static const unsigned char outputs[8][32] = {
462+
static const unsigned int repeat[] = {
463+
1, 1, 1, 1, 1, 1, 1, 1, 1000000/5
464+
};
465+
static const unsigned char outputs[][32] = {
462466
{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55},
463467
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
464468
{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50},
465469
{0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d},
466470
{0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30},
467471
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
468472
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},
469-
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}
473+
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8},
474+
{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0},
470475
};
471-
int i;
472-
for (i = 0; i < 8; i++) {
476+
unsigned int i, ninputs;
477+
478+
/* Skip last input vector for low iteration counts */
479+
ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1;
480+
CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++;
481+
482+
for (i = 0; i < ninputs; i++) {
473483
unsigned char out[32];
474484
secp256k1_sha256 hasher;
485+
unsigned int j;
486+
/* 1. Run: simply write the input bytestrings */
487+
j = repeat[i];
475488
secp256k1_sha256_initialize(&hasher);
476-
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
489+
while (j > 0) {
490+
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
491+
j--;
492+
}
477493
secp256k1_sha256_finalize(&hasher, out);
478494
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
495+
/* 2. Run: split the input bytestrings randomly before writing */
479496
if (strlen(inputs[i]) > 0) {
480497
int split = secp256k1_testrand_int(strlen(inputs[i]));
481498
secp256k1_sha256_initialize(&hasher);
482-
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
483-
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
499+
j = repeat[i];
500+
while (j > 0) {
501+
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
502+
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
503+
j--;
504+
}
484505
secp256k1_sha256_finalize(&hasher, out);
485506
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
486507
}
487508
}
488509
}
489510

511+
/** SHA256 counter tests
512+
513+
The tests verify that the SHA256 counter doesn't wrap around at message length
514+
2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the
515+
implementation of the counter and it catches multiple natural 32-bit overflows
516+
(e.g., counting bits, counting bytes, counting blocks, ...).
517+
518+
The test vectors have been generated using following Python script which relies
519+
on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2).
520+
521+
```
522+
from sha256 import sha256
523+
from copy import copy
524+
525+
def midstate_c_definition(hasher):
526+
ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n'
527+
ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}'
528+
return ret
529+
530+
def output_c_literal(hasher):
531+
return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}'
532+
533+
MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno'
534+
assert(len(MESSAGE) == 64)
535+
BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)]
536+
537+
midstates = []
538+
digests = []
539+
hasher = sha256()
540+
for i in range(BYTE_BOUNDARIES[-1] + 1):
541+
if i in BYTE_BOUNDARIES:
542+
midstates.append(midstate_c_definition(hasher))
543+
hasher_copy = copy(hasher)
544+
hasher_copy.update(MESSAGE)
545+
digests.append(output_c_literal(hasher_copy))
546+
hasher.update(MESSAGE)
547+
548+
for x in midstates:
549+
print(x + ',')
550+
551+
for x in digests:
552+
print(x + ',')
553+
```
554+
*/
555+
void run_sha256_counter_tests(void) {
556+
static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno";
557+
static const secp256k1_sha256 midstates[] = {
558+
{{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda},
559+
{0x00}, 0xfffc0},
560+
{{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26},
561+
{0x00}, 0x1fffc0},
562+
{{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1},
563+
{0x00}, 0x3fffc0},
564+
{{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6},
565+
{0x00}, 0x7fffc0},
566+
{{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c},
567+
{0x00}, 0xffffc0},
568+
{{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2},
569+
{0x00}, 0x1ffffc0},
570+
{{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c},
571+
{0x00}, 0x3ffffc0},
572+
{{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0},
573+
{0x00}, 0x7ffffc0},
574+
{{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad},
575+
{0x00}, 0xfffffc0},
576+
{{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023},
577+
{0x00}, 0x1fffffc0},
578+
{{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1},
579+
{0x00}, 0x3fffffc0},
580+
{{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec},
581+
{0x00}, 0x7fffffc0},
582+
{{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162},
583+
{0x00}, 0xffffffc0},
584+
{{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a},
585+
{0x00}, 0x1ffffffc0},
586+
};
587+
static const unsigned char outputs[][32] = {
588+
{0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15},
589+
{0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb},
590+
{0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e},
591+
{0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9},
592+
{0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7},
593+
{0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07},
594+
{0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76},
595+
{0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0},
596+
{0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8},
597+
{0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6},
598+
{0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e},
599+
{0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b},
600+
{0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34},
601+
{0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e},
602+
};
603+
unsigned int i;
604+
for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) {
605+
unsigned char out[32];
606+
secp256k1_sha256 hasher = midstates[i];
607+
secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input));
608+
secp256k1_sha256_finalize(&hasher, out);
609+
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
610+
}
611+
}
612+
490613
void run_hmac_sha256_tests(void) {
491614
static const char *keys[6] = {
492615
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
@@ -6964,7 +7087,8 @@ int main(int argc, char **argv) {
69647087
run_modinv_tests();
69657088
run_inverse_tests();
69667089

6967-
run_sha256_tests();
7090+
run_sha256_known_output_tests();
7091+
run_sha256_counter_tests();
69687092
run_hmac_sha256_tests();
69697093
run_rfc6979_hmac_sha256_tests();
69707094
run_tagged_sha256_tests();

0 commit comments

Comments
 (0)
Please sign in to comment.