When I enter the command-line
openssl dhparam -text 1024 the resulting safe-prime is 1032 bits instead of 1024 bits. It seems like the 1st byte is always 0. Why is this?
Look at each of the fields; the primes, the exponents, all of them. Now try again, and again, and again. You'll notice some inconsistency as to whether an initial zero byte is present. Sometimes it is, sometimes it's not. The pattern is this: if the first bit of the first "real" byte is set -- that is, if the first hex character is less than 8 -- then there won't be an initial zero displayed (or stored), but if it's 8 or higher, then a zero byte will be prepended.
This makes it pretty clear that the problem they're solving is sign interpretation. With signed values, the first bit is the sign of the number; adding an initial zero removes any ambiguity.
To see what's actually stored (not displayed) look at this:
You'll see that the while only 64 or 32 bytes are displayed, you'll see
As for 32-bit DH keys, look at this:
So, that looks like only 4 bytes even though the initial bit is set. But let's look at the asn1parse:
So for this 32-bit prime, 5 bytes are stored even though you only saw 4 bytes displayed.
The reason you didn't see the zero byte this time is that since the stored value is only 32-bits, it can be displayed as a simple unsigned integer, and therefore OpenSSL's display library accordingly shows you the decimal value and the hex value in parens instead of just showing you a string of hex bytes separated by colons. But the initial zero is still there, as we saw in the asn1 output.
You really get a 1024-bit prime: a 1024-bit prime is an integer whose value is greater than 21023 but lower than 21024. That's what OpenSSL returns you. However, when it comes to storing that integer into a file, some encoding convention must be used to turn that integer into bytes. OpenSSL uses ASN.1 with the DER (Distinguished Encoding Rules).
In ASN.1, the type is
If the highest bit in the 1024 bit value is set, a 0 byte is prepended because without that the number would be interpreted as a negative number.