What am I doing wrong?
carloseduedu opened this issue · 3 comments
Hi, Bitlogik, good Morning
First of all, I want to congratulate you on your contribution. I'm trying to run the script (I installed all dependencies) my virtualbox configuration: Linux lll 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 GNU/Linux)
But the error below occurs:
lll@lll:~/lattice-attack$ python3 gen_input.py && python3 lattice_attack.py
Loading files ...
18000 files detected for 6000 signatures
Filtering signatures traces
File data.json written with all data.
----- Lattice ECDSA Attack -----
Loading data from file data.json
Traceback (most recent call last):
File "lattice_attack.py", line 259, in
lattice_attack_cli(arg.f, arg.l)
File "lattice_attack.py", line 230, in lattice_attack_cli
if not ecdsa_lib.check_publickey(q_target, curve_string):
File "/home/lll/lattice-attack/ecdsa_lib.py", line 118, in check_publickey
publickey_obj.public_key()
TypeError: public_key() missing 1 required positional argument: 'backend'
Could you help me verify what's wrong? Thanks.
This is typical to an outdated cryptography library dependency. This library at some point in time, removed the mandatory backend argument, to make it optional, and many methods are now loading the default backend automatically. What's your version installed ? The recommended is at least version 3.4.1.
Install an updated cryptography version, which can be done by installing the lattice-attack "properly" : python3 -m pip install .
This may require all building tools installed for compilation.
Or alternatively, patch to add the required backend, as it was used to be provided in old versions.
from cryptography.hazmat.backends import default_backend
default_openssl_backend = default_backend()
...
publickey_obj.public_key(default_openssl_backend)
We don't guarantee this line is the only one requiring the added backend argument.
Choose one way or the other, if you can easily install a newest cryptography lib, or patch manually to be compatible with old version.
Hello Bitlogick, thank you very much for your feedback. Following your line of reasoning worked for me, I actually had the Crypto library out of date. It was necessary to update the rust and the pip version (as you instructed) after that I updated the library with: python3 -m pip install -U cryptography.
Thank you very much for your help!
I still have doubts on how to calculate (get) the LSB and where to get the signatures (or if the script will calculate them from the public key and messages)... But this is perhaps a matter of studying the material provided as a basis of study. If you can give me some more light on how to feed the data.json file it would also be of great value to my studies. Thank you and have a good week!
Great it works.
The JSON format is documented in the README, and in the Python master file. You can also see the example provided, which build a JSON data file from an external different format.
The input JSON format is the following :
{
"curve": "SECP256K1",
"public_key": [pubx, puby],
"message": [a,b,c,...], // In case same message for all signatures
"known_type": "LSB"/"MSB",
"known_bits": n_bits,,
"signatures": [ {"r": intR, "s": intS, "kp": leakednoncepart }, {...}, ... ]
}
All data are provided as integers : r, s, kp, pubx, puby, n_bits, ...
The public key needs to be decompressed to x,y.
The message can be provided as a unique message (will be hashed) for all the signatures, as a byte array format in the "message" key. Or as a hash (already hashed) for each signatures with {"hash": hashValue, "r": intR, "s": intS, "kp": leakednoncepart } for each signature. hashValue is the integer from the hash.
That means that it is your part to decode the input source you have, and to build an input JSON data file. Usually the data are provided in a serialized binary format (X9.62, DER, ASN1,...), and the data needs to be decoded and converted to their corresponding integer values in order to build the input JSON. All these was done for a specific example here. Can you tell what is the dataset you have, the formats inside?
In the input format, for each signature, "kp" is the known part of the private internal nonce. k is not the private key, but the secret ephemeral ECDSA nonce. There are 2 cases : LSB (you know the end) and MSB (you know the start). 2^known_bits is a upper bound for kp : kp is between 0 and 2^knownbits -1. In practice, if you know the parity, means you know the last bit : LSB. If you know the number length, means you know the number of leading zeros : MSB (and kp will be only 0 for the shortests ones).
When LSB "kp" has to be provided as it is. If MSB, "kp" must be "shifted" to the end, reduced like the LSB.
Example if the LSB known for "k" is 0b000101 for a given signature, you know k ends with these bits.
-> { "hash": xyz, "r": xxx, "s": xxx, "kp": 5 } # or also can be written as 0b000101 or 0x05, whatever integer notation you want.
Example if the MSB known for "k" is 0b000101 for a given signature, you know k starts with these bits.
-> { "hash": xyz, "r": xxx, "s": xxx, "kp": 5 }
Same, but these bits are at the beginning of the integer, the "heavy" power. "kp" is kind of shifted by SIZE-(2^KNOWN_BITS), example : 256 - 6 bits, if EC256 with 6 bits known. You only provide the known part in both ways. The type provided is discriminated by the "known_type" key in the JSON data : "LSB" or "MSB".
When I refer start or end, this is in a "human reading" point of view, left to right, big powers at the left. It can depends of the endianess in use. Think of it as integer encoded in binary. That's why the LSB and MSB naming is more adequate. With integers provided, there's no issue about endianess.
You can't mix MSB and LSB, it is one way or the other in a single run.
Hope this software will help you in your project.