Private key length bytes

Solution 1:

The size of a RSA key is expressed in bits, not bytes. 2048 bits are 256 bytes.

A bare-bone RSA private key consists in two integers, the modulus (a big composite integer, its length in bits is the "RSA key length") and the private exponent (another big integer, which normally has the same size than the modulus). However, the modulus and the private exponent have a bit of internal structure, and knowing details about that structure allows for faster implementations (by a factor of about 4). Hence, RSA private keys usually include some more data.

Namely, if the modulus is n and is the product of two prime numbers p and q, then the private key includes:

  • the modulus n (256 bytes for a 2048-bit key)
  • the public exponent e (small, often 65537, i.e. can be encoded over 3 or 4 bytes)
  • the private exponent d (about 256 bytes)
  • the factors p and q (128 bytes each)
  • d reduced modulo p-1 (128 bytes)
  • d reduced modulo q-1 (128 bytes)
  • 1/q mod p (the inverse of q modulo p; 128 bytes)

for a grand total of about 1160 bytes. Then there is a bit of overhead for the encoding, because all those integers could have lengths slightly different (for instance, nothing really requires that p and q have the exact same size; also, e could be greater than that). The standard structure uses ASN.1, which implies a few extra bytes here and there. It is also common to wrap the structure into a bigger structure which also identifies the key as being a key for RSA. 1232 bytes is compatible with a 2048-bit RSA key encoded in PKCS#8 format.

For details on RSA, have a look at PKCS#1.

Solution 2:

Don't forget that 2048 is the length of the modulus in bits, but your measurement of the private key is in bytes. The private key is the modulus and the multiplicative inverse of the public exponent, and depending upon the toolkit you're using, it might also store your CN, DN, (for x509 keys) or subkeys (for GPG keys), so just comparing sizes may not be useful.

Solution 3:

Other than the required values (of which the modulus is one, as @sarnold points out) and the fact that you are quite literally comparing bits and bytes, some implementations also compute a few other values up front and store them along with the key, as an optimization. For example, I am not certain but I believe I read that some implementations store the product (p-1)(q-1) (recall that the modulus n is actually the product pq, where p and q are prime).

Solution 4:

@Thomas Pornin, I use both ssh-keygen and openssl genpkey to generate a keypair, each with 2048 keysize, and then print the content, it is like this:

Private-Key: (2048 bit)
modulus:
    00:bd:92:7f:da:4f:8f:b0:33:23:0f:d7:f4:12:39:
    5d:4d:32:48:1b:6e:de:2d:a5:b9:83:7f:d2:f2:dc:
    39:c5:f3:6f:6a:5f:8a:9d:21:9c:01:51:a7:22:99:
    70:0d:03:2e:12:63:f2:44:5f:a7:6e:cc:df:44:d9:
    8b:b2:7e:fd:8c:c3:ae:62:3e:1e:7e:7a:89:1d:94:
    de:86:24:36:d6:f8:23:32:aa:4d:dc:c7:44:87:9d:
    68:a5:31:f4:ff:a3:ff:9d:01:57:c9:82:9b:9b:e1:
    1c:0f:45:2b:0f:f2:ce:95:4c:13:fb:e9:99:19:82:
    64:97:18:77:13:bb:a9:8c:1f:a1:02:cf:92:1a:4d:
    13:16:55:8d:06:a8:32:8b:43:80:12:a4:98:77:a7:
    cb:7b:4f:e7:be:4e:eb:7b:52:1f:04:49:c9:03:5a:
    5b:70:f8:db:c7:8c:99:62:32:cd:3f:fc:70:7f:5e:
    de:e9:52:04:f6:19:df:c7:21:bd:28:d8:31:e1:43:
    27:ff:ce:43:3a:83:9e:97:69:93:35:46:1f:7f:1d:
    4a:43:7f:7f:be:fd:62:c6:f8:a3:9e:07:df:75:4b:
    08:4a:47:59:e6:b3:e2:d8:40:29:d4:de:88:54:f5:
    6b:e6:e8:77:d5:71:73:c0:1c:0e:8a:b1:ad:25:82:
    79:05
publicExponent: 65537 (0x10001)
privateExponent:
    42:98:a7:9f:9a:d9:a0:8d:a6:60:97:7d:df:b5:15:
    48:dc:44:26:97:01:28:4a:12:ec:d6:47:d6:17:75:
    98:4b:d7:b5:27:d1:3b:38:26:64:f4:39:61:d7:43:
    5c:de:e4:1d:83:cd:05:26:11:5c:c4:4e:1f:12:c9:
    97:b0:33:04:73:6d:dc:87:74:10:fc:9d:14:ae:4a:
    aa:17:28:c8:c6:2d:1f:4c:62:c4:0f:a0:cc:7f:88:
    d6:97:c1:38:d9:75:1f:c3:ec:02:17:86:f0:f0:d8:
    f9:a8:53:e3:6b:6a:15:5a:bf:9e:7c:c6:d3:06:52:
    ae:1d:e3:1f:24:8b:00:75:33:ee:aa:b0:69:52:a4:
    07:41:60:35:34:67:10:ac:40:b3:5b:70:d7:a7:9c:
    c5:aa:08:2e:f5:7b:64:4f:8d:ff:ca:f9:2e:5e:4c:
    a9:ef:74:74:18:9b:14:c5:96:ce:70:43:18:ff:2d:
    25:d6:5a:15:15:11:dc:e9:6e:98:ea:b0:1d:73:d0:
    73:e2:5c:e7:f9:b8:03:a8:8d:1f:81:ca:87:97:b5:
    82:3a:f2:71:15:0c:34:1f:63:8d:b8:03:99:6f:e7:
    4d:c0:b7:c9:9a:63:60:10:af:7a:5b:db:df:aa:a3:
    81:8e:6c:44:b0:77:ee:33:0c:00:e1:67:a8:e1:8d:
    61
...
...

So, the private exponent is the 256bytes(2048bits), not the modulus, isn't it?