1

I need to calculate a CRC16 of N-bytes (5 in the example, for the sake of simplicity) extracted from a binary file of size M (a pair of Kb, not so relevant for my scopes).

printf "offset\tvalue\tcrc16\n";
#Read N bytes from file and copy in the container
for my $counter (0 .. 5- 1)
{
    my $oneByte;
    read(FH, $oneByte, 1) or die "Error reading $inFile!";
    my $ctx2 = Digest::CRC->new( type => 'crc16' );
    my $digest2 = ($ctx2->add($oneByte))->hexdigest;
    # PRINT for debugging
    printf "0x%04X\t0x%02X\t0x", $counter, ord $oneByte;
    print $digest2, "\n";
}

Considering this binary input

enter image description here

I obtain the result:

enter image description here

The script is performing byte-by-byte CRC16 (correct by the way), but I need the CRC16 of the full binary stream of 5 bytes (the expected value should be 0x6CD6). Where am I wrong in the script?

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174

2 Answers2

2

Calling hexdigest or digest or b64digest clears the buffer and begins the next digest from scratch. (If you were computing digests of several files/streams, you wouldn't want the data from one stream to affect the digest of a separate stream).

So wait until the stream is completely read to call digest

... {
    ...
    $ctx2->add($oneByte);
}
print "digest = ", $ctx2->hexdigest, "\n";

Or to help in debugging, save the stream and redigest the stream after each new byte

my $manyBytes = "";
... {
    ...
    $manyBytes .= $oneByte;
    $digest2 = $ctx2->add($manyBytes)->hexdigest;
    ...
}
mob
  • 117,087
  • 18
  • 149
  • 283
  • Re "*clears the buffer and begins the next digest*", True, but it's more relevant that the OP creates a whole new object. That also resets the digest ;) – ikegami Jul 08 '21 at 18:01
  • Thank you very much @mob! I have put the digest calculation out from for() loop and now the CRC16 is correctly calculated over the desired byte stream of elements. – Andrea Mocci Jul 09 '21 at 09:42
1

You can use ->add. You can either pass the whole string at once, chunk by chunk, or character by character.

$ perl -M5.010 -MDigest::CRC -e'
   my $d = Digest::CRC->new( type => "crc16" );
   $d->add("\x49\x34\x49\x31\x31");
   say $d->hexdigest;
'
6cd6

$ perl -M5.010 -MDigest::CRC -e'
   my $d = Digest::CRC->new( type => "crc16" );
   $d->add($_) for "\x49", "\x34", "\x49", "\x31", "\x31";
   say $d->hexdigest;
'
6cd6

As shown, use a single object, and add every byte before calling ->digest (etc) as this resets the process.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Thanks Ikegami, but your suggestions is bit not optimized; actually I have to calculate the CRC16 over more than 500kb of data. If I have to do `$d->add("\x49\x34\x49\x31\x31......(500kb - 1)");` the code I a bit unreadable and not optimized – Andrea Mocci Jul 09 '21 at 09:16
  • Eh? You would continue to read it from the file like you do now... Why did you think I was suggesting you hard-code the file??? – ikegami Jul 09 '21 at 13:36