Subject: | sha256-hash(a x 256) neq sha256-hash(a x 16 x 16) |
Date: | Mon, 29 Jan 2007 09:25:43 -0500 |
To: | bug-SHA256 [...] rt.cpan.org |
From: | Jonathan <ohcamacnahtanoj [...] comcast.net> |
Problem: The perl code below prints out
"02d7160d 77e18c64 47be80c2 e355c7ed 43885452 71702c50 253b0914
c65ce5fe"
"69f0a9fc 8364d2f7 887ab151 c3fce25e 82a084e0 3b297efa 48cefbaa
87689d3d"
instead of printing out
"02d7160d 77e18c64 47be80c2 e355c7ed 43885452 71702c50 253b0914
c65ce5fe"
"02d7160d 77e18c64 47be80c2 e355c7ed 43885452 71702c50 253b0914
c65ce5fe"
Versions of everything
Digest::SHA256: v0.01b
PERL: 5.8.3, i386-linux-thread-multi
Machine: 32-bit i686 linux system.
Code:
#!/usr/bin/perl -w
use strict;
use Digest::SHA256;
#Sample program to show how Digest::SHA256 is flawed.
my $ctx = Digest::SHA256::new(256);
#Add 256 bytes of "a", 16 bytes at a time.
for(1..16){
$ctx->add("a" x 16);
}
print("The hash of 'a' x 256 (as obtained through 'a' x 16 x 16) is\n "
. $ctx->hexdigest() . "\n\n");
$ctx->reset();
#Add 256 bytes all at once.
$ctx->add("a" x 256);
print("The hash of 'a' x 256 (as obtained through 'a' x 256 x 1) is\n "
. $ctx->hexdigest() . "\n\n");
Writing a C version, and stepping through with GDB, the problem appears
to be
line 175:
clo = TRUNC32(sha_info->count_lo + ((Uint8) count << 3));
The problem is the cast to Uint8, which truncates most of the length
information
when the size of each chunk is > 255 bytes. Replacing this cast with a
something
that preserves more information, such as Uint32, fixes the problem. If
overflow
is the reason for the cast, then it could be replaced with
clo = TRUNC32(sha_info->count_lo + ( (count & 0x1FFFFFFF) << 3));
And the next line,
sha_info->count_hi += (Uint8) count >> 29;
is probably also wrong, although I can't test it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //for memset()
#include "sha.h"
int main(int argc, char ** argv){
char data [300];
int i;
memset(data, 'a', 299);
data[299] = 0;
SHA_INFO sha_struct;
sha_init(&sha_struct);
for(i = 0; i < 8; i++){
sha_update(&sha_struct, data, 16);
}
sha_final(&sha_struct);
printf("The hash of 'a' x 128 (as obtained through 'a' x 16 x 8) is\n ");
sha_print(&sha_struct);
printf("\n");
sha_init(&sha_struct);
sha_update(&sha_struct, data, 128);
sha_final(&sha_struct);
printf("The hash of 'a' x 128 (as obtained through 'a' x 128 x 1)is\n ");
sha_print(&sha_struct);
printf("\n");
sha_init(&sha_struct);
for(i = 0; i < 16; i++){
sha_update(&sha_struct, data, 16);
}
sha_final(&sha_struct);
printf("The hash of 'a' x 256 (as obtained through 'a' x 16 x 16) is\n ");
sha_print(&sha_struct);
printf("\n");
sha_init(&sha_struct);
sha_update(&sha_struct, data, 256);
sha_final(&sha_struct);
printf("The hash of 'a' x 256 (as obtained through 'a' x 256 x 1) is\n ");
sha_print(&sha_struct);
printf("\n");
return 0;
}
#!/usr/bin/perl -w
use strict;
use Digest::SHA256;
#Sample program to show how Digest::SHA256 is flawed.
my $ctx = Digest::SHA256::new(256);
#Add 128 bytes of "a", 16 bytes at a time.
for(1..8){
$ctx->add("a" x 16);
}
print("The hash of 'a' x 128 (as obtained through 'a' x 16 x 8) is\n "
. $ctx->hexdigest() . "\n\n");
$ctx->reset();
#Add 128 bytes all at once.
$ctx->add("a" x 128);
print("The hash of 'a' x 128 (as obtained through 'a' x 128 x 1) is\n "
. $ctx->hexdigest() . "\n\n");
#Note how the 2 values are identical.
$ctx->reset();
#Add 256 bytes of "a", 16 bytes at a time.
for(1..16){
$ctx->add("a" x 16);
}
print("The hash of 'a' x 256 (as obtained through 'a' x 16 x 16) is\n "
. $ctx->hexdigest() . "\n\n");
$ctx->reset();
#Add 256 bytes all at once.
$ctx->add("a" x 256);
print("The hash of 'a' x 256 (as obtained through 'a' x 256 x 1) is\n "
. $ctx->hexdigest() . "\n\n");
#Note the difference.