Verifying a CD/DVD against an ISO image

One way of verifying that a CD/DVD matches an ISO image is to calculate a hash sum (e.g. SHA-256) of both the CD/DVD and the ISO image and compare them afterwards.

For the ISO image this could look like that...

$ sha256sum original.iso

...and for the optical drive:

$ sha256sum /dev/cdrom

Though you might get matching hash sums in many cases you won't. The reason why both commands might give different results is, that the ISO image was padded with null bytes when it was burned on the CD/DVD.

TL;DR

If you don't want to read the whole article, I made a simple script which does the verification. You can get it on GitHub.

Why a null byte padding?

CDs and DVDs structure their data into sectors. Each sector stores 2048 bytes of data (see Wikipedia). For CDs a sector is the minimum storage unit. If the size of an CD ISO image is not an (integral) multiple of 2048 bytes, it needs to be aligned by filling up with padding bytes. For DVDs it is a bit different. Here 16 sectors build a block (see here [page 23,25]) and data needs to be block aligned. So the minimum storage unit is not a sector but a block. That means the size of a DVD must be an multiple of 2048 bytes * 16 (= 32KB block).

All sources I found seem to indicate that always null bytes are used for the padding, although I couldn't find a standard which explicitly says that.

So a padded image would look like that (head and tail are not official terms here):

        head                tail
+-----------------------------------+
|  Original ISO image | null bytes  |
+-----------------------------------+

How to compare them?

So how can we compare a padded CD/DVD with the original ISO? First of all it is helpful to create a copy of the CD/DVD first. dd can be used for that.

$ dd if=/dev/cdrom of=copy.iso bs=2M

Then you compare the size of the original ISO with the copy.

$ stat -c %s original.iso

and

$ stat -c %s copy.iso

If the sizes don't match, we assume the ISO was padded (see above). So we need to make sure that (1) the 'head' of copy.iso is the same as original.iso and (2) the 'tail' are only null bytes.

For (1) we can use the head command with the -c switch to fetch the first n bytes, where n is the size of the original ISO. Then we calculate the hash sum of that. If that hash sum matches the original ISO, we know this part was burned on the CD/DVD correctly. The following command does that.

$ head -c $(stat -c %s original.iso) copy.iso | sha256sum

If the hash sums match we also want to verify that the padding only contains null bytes. We use hash sums again. First we calculate the hash sum of the padding of copy.iso like that (note this time we use tail to get a number of bytes from the end of the ISO image)...

$ diff=$(( $(stat -c %s copy.iso) - $(stat -c %s original.iso) ))
$ tail -c $diff copy.iso | sha256sum

...and then we generate $diff null bytes and also calculate the hash sum. If both match, we know the padding is correct too and we are finished.

$ printf '\0%.0s' $(seq $diff) | sha256sum 

I wrote a script which glues all the parts together. It takes the original ISO image as first argument. The second optional argument is your CD/DVD drive (the script assumes /dev/sr0 if you don't pass a second argument since /dev/cdrom is a symlink which doesn't exist on some Linux distributions).
Note that you might need to adjust the variable iso_copy at the beginning of the script to a different path. You need to do that if you don't have enough space under /tmp for the ISO copy. Check with df -h first.

comments (2) - add comment

mw
@Chris: Thanks a lot for your comment. :) I'm glad I could help!
Thanks very much for this helpful page and script. I'm glad I can now verify a DVD using sha256sum - I had wondered why it didn't work as expected in the past. I appreciate your clear explanations, and also your privacy policy.