You are looking at the ASN.1 encoding of private (and public) keys; the 00 values you see are an artifact of how ASN.1 encodes integers.
ASN.1 is a method for describing data structures, and has ways to represents all sorts of data types. It wasn't designed with public keys (or cryptography) in mind; it was intended for more general use, initially telecommunications. When it encodes an integer, it has the ability to represent a negative integer.
When we use the BER encoding rules for ASN.1 (which is how ASN.1 are usually encoded in practice), here is how it may represent an integer:
<Tag> <Length> <Value of the integer>
where:
<Tag>
: 02
is the magic value for "this is an integer"
<Length>
: 81 81
is a variable sized length field that says how many bytes are in the binary value
<Value of the integer>
: 00 da ff ... 5f f1
is the binary encoded integer value, in signed big endian form
This is called a Tag-Length-Value encoding or TLV in short.
Now, the rules say that if the most significant bit of the <Value of the integer>
field is a 1
, the encoded integer is negative (using two's-complement encoding); if it is 0
then the integer is positive (or zero).
Here are the implications of that; if we were to encode the modulus you state as a 256 byte binary value, we would have the binary value as da ff 24 ... 5f f1
. However, if we were to use that as the representation, the decoder would look at the most significant bit of the first byte (da
), see that the most significant bit is 1
, and interpret that as a negative integer.
In this case, it is required to encode this as a 257 byte binary value, and have the binary value include a leading 0
, that is, as 00 da ff 24 ... 5f f1
. In this case, the decoder would look at the most significant bit of the first byte (00
in this case), see that the most significant bit is 0
, and interpret that as a positive integer. And, since adding a leading zero doesn't change the represented value, the decoded integer would be the one we want.
This happens whenever the encoded integer is a multiple of 8 bits in length.
We typically select RSA modulus sizes which are powers of two or small multiples thereof (1024, 1536, 2048, 3072, etc), and so this typically happens there.
And, when we select the primes, we typically split the primes evenly. For example, when we generate a 2048-bit RSA key, we would typically select two 1024 bit primes; these primes are hence typically multiples of 8 bits in length. And at least one, usually both, must be towards the higher end of the noninclusive range $(2^{1023}, 2^{1024})$ to ensure $n$ is over $2^{2047}$.
The other CRT parameters ($d \bmod p-1$, $d \bmod q-1$, $q^{-1} \bmod p$) are for practical purposes random numbers up to nearly $p$ or $q$, so given the typical values for $p$ and $q$ above, roughly 1/3 of the time these are the same number of bits (1024) and need the extra 00
, roughly 2/3 of the time they are 1 to 7 bits smaller and need the same number of octets but no extra 00
or 8 bits smaller and need one less octet for the magnitude plus the 00
, and roughly 1/400 of the time they are small enough to need fewer octets.
This rule about an 'extra' 00
applies to both BER and DER, a commonly used subset of BER; see 8.3.2 in X.690. BER gives a choice to include 'redundant' information while DER does not; DER only allows one well defined encoding for a specific type and value combination.
One case where the 00
is typically not included is the public exponent $e$. The most common value for that is 65537, or 01 00 01
in binary. The leading bit here is 0
, and so a leading 00
byte is not required; hence the typical encoding for this exponent is 02 03 01 00 01
.