So im generating 2048 RSA keypair. But when i look at the private key the lenght is only 1232 bytes. Does this have anything to do with the 2048 or is the 2048 just the modulus size?
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.
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.
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).
#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?
Related
I want to verify a message signed by my trezor hardware wallet.
Basically I have these information.
.venv/bin/trezorctl btc get-public-node -n 0
Passphrase required:
Confirm your passphrase:
node.depth: 1
node.fingerprint: ea66f037
node.child_num: 0
node.chain_code: e02030f2a7dfb474d53a96cb26febbbe3bd3b9756f4e0a820146ff1fb4e0bd99
node.public_key: 026b4cc594c849a0d9a124725997604bc6a0ec8f100b621b1eaed4c6094619fc46
xpub: xpub69cRfCiJ5BVzesfFdsTgEb29SskY74wYfjTRw5kdctGN2xp1HF4udTP21t68PAQ4CBq1Rn3wAsWr84wiDiRmmSZLwkEkv4qK5T5Y7EXebyQ
$ .venv/bin/trezorctl btc sign-message 'aaa' -n 0
Please confirm action on your Trezor device
Passphrase required:
Confirm your passphrase:
message: aaa
address: 17DB2Q3oZVkQAffkpFvF4cwsXggu39iKdQ
signature: IHQ7FDJy6zjwMImIsFcHGdhVxAH7ozoEoelN2EfgKZZ0JVAbvnGN/w8zxiMivqkO8ijw8fXeCMDt0K2OW7q2GF0=
I wanted to use python3-ecdsa. When I want to verify the signature with any valid public key, I get an AssertionError: (65, 64), because the base64.b64decode of the signature is 65 bytes, but should be 64.
When I want to load the node.public_key into a ecdsa.VerifyingKey, I get an AssertionError: (32, 64), because the bytes.fromhex return 32 bytes, but every example I found uses 64 bytes for the public key.
Probably I need to convert the bip32 xpub to a public key, but I really dont know how.
Solutiion
python-ecdsa needs to be at version 0.14 or greater to handle compressed format of the public key.
import ecdsa
import base64
import hashlib
class DoubleSha256:
def __init__(self, *args, **kwargs):
self._m = hashlib.sha256(*args, **kwargs)
def __getattr__(self, attr):
if attr == 'digest':
return self.double_digest
return getattr(self._m, attr)
def double_digest(self):
m = hashlib.sha256()
m.update(self._m.digest())
return m.digest()
def pad_message(message):
return "\x18Bitcoin Signed Message:\n".encode('UTF-8') + bytes([len(message)]) + message.encode('UTF-8')
public_key_hex = '026b4cc594c849a0d9a124725997604bc6a0ec8f100b621b1eaed4c6094619fc46'
public_key = bytes.fromhex(public_key_hex)
message = pad_message('aaa')
sig = base64.b64decode('IHQ7FDJy6zjwMImIsFcHGdhVxAH7ozoEoelN2EfgKZZ0JVAbvnGN/w8zxiMivqkO8ijw8fXeCMDt0K2OW7q2GF0=')
vk = ecdsa.VerifyingKey.from_string(public_key, curve=ecdsa.SECP256k1)
print(vk.verify(sig[1:], message, hashfunc=DoubleSha256))
Public-key. Mathematically an elliptic curve public key is a point on the curve. For the elliptic curve used by Bitcoin, secp256k1, as well as other X9-style (Weierstrass form) curves, there are (in practice) two standard representations originally established by X9.62 and reused by many others:
uncompressed format: consists of one octet with value 0x04, followed by two blocks of size equal to the curve order size containing the (affine) X and Y coordinates. For secp256k1 this is 1+32x2 = 65 octets
compressed format: consists of one octet with value 0x02 or 0x03 indicating the parity of the Y coordinate, followed by a block of size equal tot he curve order containing the X coordinate. For secp256k1 this is 1+32 = 33 octets
The public key output by your trezor is the second form, 0x02 + 32 octets = 33 octets. Not 32.
I've never seen an X9EC library (ECDSA and/or ECDH) that doesn't accept at least the standard uncompressed form, and usually both. It is conceivable your python library expects only the uncompressed form without the leading 0x04, but if so this gratuitous and rather risky nonstandardness, unless a very good explanation is provided in the doc or code, would make me suspicious of its quality. If you do need to convert the compressed form to uncompressed you must implement the curve equation, which for secp256k1 can be found in standard references, not to mention many implementations. Compute x^3 + a*x + b, take the square root in F_p, and choose either the positive or negative value that has the correct parity (agreeing with the leading byte here 0x02).
The 'xpub' is a base58check encoding of a hierarchical deterministic key, which is not just an EC(DSA) key but adds metadata for the key derivation process. If you base58 decode it and remove the check, you get (in hex):
0488B21E01EA66F03700000000E02030F2A7DFB474D53A96CB26FEBBBE3BD3B9756F4E0A820146FF1FB4E0BD99026B4CC594C849A0D9A124725997604BC6A0EC8F100B621B1EAED4C6094619FC46good
which breaks down exactly as your display showed:
0488B21E fixed prefix
01 .depth
EA66F037 .fingerprint
00000000 .child_num
E02030F2A7DFB474D53A96CB26FEBBBE3BD3B9756F4E0A820146FF1FB4E0BD99 .chain_code
026B4CC594C849A0D9A124725997604BC6A0EC8F100B621B1EAED4C6094619FC46 .public_key
Confirming this, the ripemd160 of sha256 of (the bytes that are shown in hex as) 026B4CC594C849A0D9A124725997604BC6A0EC8F100B621B1EAED4C6094619FC46 is (the bytes shown in hex as) 441e1d2adf9ff2a6075d71d0d8782228e0df47f8, and prefixing the version byte 00 for mainnet to that and base58check encoding gives the address 17DB2Q3oZVkQAffkpFvF4cwsXggu39iKdQ as shown.
Signature. Mathematically an X9.62-type ECDSA signature is two integers, called r and s. There are two different standards for representing them, and Bitcoin uses both with variations:
ASN.1 DER format. DER is a general purpose encoding that contains 'tag' and 'length' metadata and variable length data depending on the numeric values, here r and s; for secp256k1 in general this encoding is usually 70 to 72 octets but occasionally less. However, to avoid certain 'malleability' attacks current Bitcoin requires use of 's' values less than half the curve order, commonly called 'low-s', which reduces the maximum length of the ASN.1 DER encoding to 71 octets. Bitcoin uses this for transaction signatures, and adds a 'sighash' byte immediately following it (in the 'scriptsig' aka redeem script) indicating certain options on how the signature was computed (and thus should be verified).
'plain' or P1363 format. This is fixed length and consists simply of the r and s values as fixed-length blocks; for secp256k1 this is 64 octets. Bitcoin uses this for message signatures but it adds a 'recovery' byte' to the beginning that allows determining the publickey from the message and signature if necessary, making the total 65 octets.
See https://bitcoin.stackexchange.com/questions/38351/ecdsa-v-r-s-what-is-v/38909 and https://bitcoin.stackexchange.com/questions/12554/why-the-signature-is-always-65-13232-bytes-long .
If your python library is designed for general purpose ECDSA, not Bitcoin, and wants a 64-byte signature, that almost certainly is the 'plain' format which corresponds to the Bitcoin message signature (here decoded from base64) with the first byte removed.
Let’s say I take 256 bits from a CSPRNG and assume it is perfectly 256 bits of entropy. Call this rand.
Then let’s say I take the sha256 of the ASCII text “password”. Call this hash.
Now we XOR rand and hash. Call this mixed.
Is the entropy of mixed less than that of rand?
If so, is there a formula for calculating its entropy?
Example below: What is the entropy of mixed as a function of rand and weak_hash
#!/usr/bin/python3
import hashlib, os
def main():
rand = int(os.urandom(32).hex(),16)
weak_hash = int(hashlib.sha256(b'password').digest().hex(),16)
mixed = ("%064x" % (rand ^ weak_hash))
print(mixed)
main()
You are describing a one-time-pad. If the key stream: the output of the CSPRNG is fully random then the ciphertext will be indistinguishable from random as well.
Of course the output of CSPRNG is not fully random. However, if the CSPRNG is well seeded with enough entropy then you'd have the same security as a stream cipher, which mimics a one time pad.
So the output (mixed) will be as random as the CSPRNG, as long as the CSPRNG doesn't get into a previously encountered state. That should basically only happen if the entropy source fails.
I'm using python and cryptography.io to sign and verify messages. I can get a DER-encoded bytes representation of a signature with:
cryptography_priv_key.sign(message, hash_function)
...per this document: https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ec/
A DER-encoded ECDSA Signature from a 256-bit curve is, at most, 72 bytes; see: ECDSA signature length
However, depending on the values of r and s, it can also be 70 or 71 bytes. Indeed, if I examine length of the output of this function, it varies from 70-72. Do I have that right so far?
I can decode the signature to ints r and s. These are both apparently 32 bytes, but it's not clear to me whether that will always be so.
Is it safe to cast these two ints to bytes and send them over the wire, with the intention of encoding them again on the other side?
The simple answer is, yes, they will always be 32 bytes.
The more complete answer is that it depends on the curve. For example, a 256-bit curve has an order of 256-bits. Similarly, a 128-bit curve only has an order of 128-bits.
You can divide this number by eight to find the size of r and s.
It gets more complicated when curves aren't divisible by eight, like secp521r1 where the order is a 521-bit number.
In this case, we round up. 521 / 8 is 65.125, thus it requires that we free 66 bytes of memory to fit this number.
It is safe to send them over the wire and encode them again as long as you keep track of which is r and s.
Does RSA2048 key modulus have to be exactly 2048 bits long, or does it mean at least 2048 bits and it can be for example 2080 bits long?
The key size of RSA is defined to be the size in bits of the modulus. The RSA private exponent may actually be shorter than the modulus. So yes, the modulus has to be 2048 bits long, otherwise you'd have a different key size.
One implication is that the highest order bit is always set to one. With RSA it is very important to keep in mind that all values are stored as unsigned integers.
I would like to know which drawbacks are there if the public exponent (e) is not coprime with the Euler phi (phi(N)) in RSA. That is to say GCD(e, phi(n)) != 1.
As far as I know the drawback is that in this way we are not sure that there exists a d such that e*d = 1 mod phi. Are there any other drawbacks?
A modular multiplicative inverse of a mod n exists if and only if gcd(a, n)= 1. So, yes, they must be coprime.
Generally, just use 65537 as your public key exponent. There are no advantages for choosing a random e, and 65537 is sufficient large to protect against Coppersmith's Attack and has some qualities that make it particularly efficient for square and multiply algorithms to work with.
Let us take a example: N=65 and e=3.
Then, if we encrypt the plaintext 2, we get 2^3 mod 65 = 8
However, if we encrypt the plaintext 57, we get 57^3 mod 65 = 8
Hence, if we get the ciphertext 8, we have no way of determining whether that corresponds to the plaintext 2 or 57 (or 32, for that matter); all three plaintexts would convert into that one ciphertext value.
Making sure e and ϕ(N) are relatively prime ensures this doesn't happen.