This shows you the differences between two versions of the page.
isc:labs:09 [2024/12/01 00:25] dimitrie.valu |
isc:labs:09 [2024/12/02 22:07] (current) dimitrie.valu |
||
---|---|---|---|
Line 11: | Line 11: | ||
Note: the files you create will be used throughout the lab, so keep them handy unless stated otherwise. If you <del>delete</del> lose them, no problem, just create them again. | Note: the files you create will be used throughout the lab, so keep them handy unless stated otherwise. If you <del>delete</del> lose them, no problem, just create them again. | ||
- | ==== [20p] 0. Init ==== | + | ==== [5p] 0. Init ==== |
You've learned about public and private keys in the Cryptography lab, and you learned to generate private and public keys during the OpenStack setup. We will go a bit more in-depth - run the following command to generate a private key: | You've learned about public and private keys in the Cryptography lab, and you learned to generate private and public keys during the OpenStack setup. We will go a bit more in-depth - run the following command to generate a private key: | ||
Line 65: | Line 65: | ||
- | ==== [30p] 1. Investigate ==== | + | ==== [15p] 1. Construct ==== |
+ | |||
+ | Now that you have seen how to generate a keypair and use it to sign and verify a message from the command line, we will delve a bit deeper and do it programatically. We will construct an RSA key manually, export the private and public keys into files, sign a message, and verify the signature. | ||
+ | |||
+ | Install the PyCryptodome library by running ''%%pip install pycryptodome%%'' and solve the TODOs below. Make sure to save the output of the public key in your text file. | ||
+ | |||
+ | <note tip> | ||
+ | For RSA key generation, check out [[https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation |this Wikipedia article]] and [[https://asecuritysite.com/rsa/rsa |Bill Buchanan's tutorial]]. | ||
+ | |||
+ | For PyCryptodome's RSA API, check out the [[https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html |relevant documentation]]. | ||
+ | |||
+ | For signing and verifying messages, check out the relevant [[https://pycryptodome.readthedocs.io/en/latest/src/signature/pkcs1_v1_5.html |PyCryptodome documentation]]. | ||
+ | </note> | ||
+ | |||
+ | <code python> | ||
+ | from Crypto.PublicKey import RSA | ||
+ | from Crypto.Signature import pkcs1_15 | ||
+ | from Crypto.Hash import SHA256 | ||
+ | |||
+ | # e is the public exponent, it generally is 65537 by convention. | ||
+ | e = 65537 | ||
+ | |||
+ | # p and q are our secret two large prime numbers that are used in the generation of the RSA key. | ||
+ | p=10419935087756538088231008384871562040994908014661490082254127473816665841052170054492993091501556530959730347212080475120972015619902594355421427060481753 | ||
+ | q=11407307180430314273628852150740394587698189511945724632696575057978981037275333897647756309351469051358504590035493592824013771486348241061659599880138241 | ||
+ | |||
+ | # TODO 1: Compute N, phi, and d, and construct your RSA key, starting from the given p, q, and e. | ||
+ | ... | ||
+ | |||
+ | # TODO 2: Print the private and public keys in PEM format, then save them into a file each. | ||
+ | # Add the public key's output to your text file. | ||
+ | ... | ||
+ | |||
+ | # TODO 3: Concatenate, hash and sign the following two messages using your private key. | ||
+ | # This ensures that the signature is unique to the two messages, so the receiver can | ||
+ | # authenticate the sender. This is usually done over a network, and the values signed are | ||
+ | # concatenated Diffie Hellman keys, or a hash of the message and a timestamp. | ||
+ | message1 = b"sal" | ||
+ | message2 = b"boss" | ||
+ | ... | ||
+ | |||
+ | # TODO 4: Print the signature in hexadecimal format. | ||
+ | ... | ||
+ | |||
+ | # TODO 5: Verify the signature using the public key. | ||
+ | ... | ||
+ | </code> | ||
+ | |||
+ | <ifauth @isc> | ||
+ | <hidden> | ||
+ | <code python> | ||
+ | from Crypto.PublicKey import RSA | ||
+ | from Crypto.Signature import pkcs1_15 | ||
+ | from Crypto.Hash import SHA256 | ||
+ | |||
+ | # e is the public exponent, it generally is 65537 by convention. | ||
+ | e = 65537 | ||
+ | |||
+ | # p and q are our secret two large prime numbers that are used in the generation of the RSA key. | ||
+ | p=10419935087756538088231008384871562040994908014661490082254127473816665841052170054492993091501556530959730347212080475120972015619902594355421427060481753 | ||
+ | q=11407307180430314273628852150740394587698189511945724632696575057978981037275333897647756309351469051358504590035493592824013771486348241061659599880138241 | ||
+ | |||
+ | # TODO 1: Compute N, phi, and d, and construct your RSA key, starting from the given p, q, and e. | ||
+ | N = p * q | ||
+ | phi = (p-1)*(q-1) | ||
+ | d = pow(e, -1, phi) | ||
+ | rsa_key = RSA.construct((N, e, d)) | ||
+ | |||
+ | # TODO 2: Print the private and public keys in PEM format, then save them into a file each. | ||
+ | # Add the public key's output to your text file. | ||
+ | print(f"{rsa_key.export_key().decode()}\n\n{rsa_key.publickey().export_key().decode()}\n") | ||
+ | |||
+ | with open("key_private.pem", "wb") as f: | ||
+ | f.write(rsa_key.export_key()) | ||
+ | print("Private key saved to key_private.pem") | ||
+ | with open("key_public.pem", "wb") as f: | ||
+ | f.write(rsa_key.publickey().export_key()) | ||
+ | print("Public key saved to key_public.pem\n") | ||
+ | |||
+ | # TODO 3: Concatenate, hash and sign the following two messages using your private key. | ||
+ | # This ensures that the signature is unique to the two messages, so the receiver can | ||
+ | # authenticate the sender. This is usually done over a network, and the values signed are | ||
+ | # concatenated Diffie Hellman keys, or a hash of the message and a timestamp. | ||
+ | message1 = b"sal" | ||
+ | message2 = b"boss" | ||
+ | message = message1 + message2 | ||
+ | |||
+ | hash1 = SHA256.new(message) | ||
+ | signature = pkcs1_15.new(rsa_key).sign(hash1) | ||
+ | |||
+ | # TODO 4: Print the signature in hexadecimal format. | ||
+ | print(signature.hex()) | ||
+ | |||
+ | # TODO 5: Verify the signature using the public key. | ||
+ | try: | ||
+ | verifier = pkcs1_15.new(rsa_key.publickey()) | ||
+ | verifier.verify(hash1, signature) | ||
+ | print("Signature is valid") | ||
+ | except (ValueError, TypeError): | ||
+ | print("Signature is invalid") | ||
+ | </code> | ||
+ | </hidden> | ||
+ | </ifauth> | ||
+ | |||
+ | ==== [30p] 2. Investigate ==== | ||
=== [15p] Remote certificates === | === [15p] Remote certificates === | ||
Line 152: | Line 256: | ||
</ifauth> | </ifauth> | ||
- | ==== [20p] 2. Create ==== | + | ==== [20p] 3. Create ==== |
Now that you've familiarized yourself with how certificates look, let's create our own Certificate Authority (CA) and sign a certificate with it. We will use the private key you generated in the first task. | Now that you've familiarized yourself with how certificates look, let's create our own Certificate Authority (CA) and sign a certificate with it. We will use the private key you generated in the first task. | ||
Line 228: | Line 332: | ||
- | ==== [30p] 3. Develop ==== | + | ==== [30p] 4. Develop ==== |
Run ''%%pip install flask%%'' to install Flask, a Python web framework that we will use to implement a simple web server over both HTTP and HTTPS. You will most likely use it or an alternative in the future, so it's good to get acquainted with it - it's very accessible for prototyping and running your own infrastructure. | Run ''%%pip install flask%%'' to install Flask, a Python web framework that we will use to implement a simple web server over both HTTP and HTTPS. You will most likely use it or an alternative in the future, so it's good to get acquainted with it - it's very accessible for prototyping and running your own infrastructure. | ||
Line 306: | Line 410: | ||
* ''%%keyfile%%'' - the path to the client's private key file (''%%client_key.pem%%'') | * ''%%keyfile%%'' - the path to the client's private key file (''%%client_key.pem%%'') | ||
- | Now try to run ''%%curl https://127.0.0.1:1337%%''. What do you see? Find a way to run ''%%curl%%'' on the HTTPS server - first, change the URL to start with the correct protocol. Now what happens? Find a way to overcome this issue by using a specific ''%%curl%%'' command flag. Note the command into your text file. | + | Now try to run ''%%curl http://127.0.0.1:1337%%''. What do you see? Find a way to run ''%%curl%%'' on the HTTPS server - first, change the URL to start with the correct protocol. Now what happens? Find a way to overcome this issue by using a specific ''%%curl%%'' command flag. Note the command into your text file. |
<ifauth @isc> | <ifauth @isc> | ||
Line 333: | Line 437: | ||
</ifauth> | </ifauth> | ||
- | Instead of bypassing the check, let's use a certificate that is set up for us. Check out the ''%%correct_signed_cert.crt%%'' file - it is valid because it uses the correct domain name (''%%127.0.0.1%%'') as its Common Name. Modify the script to use it and start the server again. Now, try to run ''%%curl https://127.0.0.1:1337%%''. What do you see? Save the output in your text file. | + | Instead of bypassing the check, let's use a certificate that is set up for us. Take a look at the ''%%correct_signed_cert.crt%%'' file - it is valid because it uses the correct domain name (''%%127.0.0.1%%'') as its Common Name. Modify the script to use it and start the server again. Now, try to run ''%%curl https://127.0.0.1:1337%%''. What do you see? Save the output in your text file. |
<ifauth @isc> | <ifauth @isc> | ||
Line 347: | Line 451: | ||
Use ''%%tcpdump%%'' to capture traffic between a client and the server over both HTTP and HTTPS. Take a screenshot of the different outputs and use them as proof of solving. | Use ''%%tcpdump%%'' to capture traffic between a client and the server over both HTTP and HTTPS. Take a screenshot of the different outputs and use them as proof of solving. | ||
- | ==== 4. Terminate ==== | + | ==== 5. Terminate ==== |
Now that you have wrapped your shell around the fundamentals of securing our daily communication, we've come full circle to the question... what would the world look like without cryptography? | Now that you have wrapped your shell around the fundamentals of securing our daily communication, we've come full circle to the question... what would the world look like without cryptography? | ||