Differences

This shows you the differences between two versions of the page.

Link to this comparison view

isc:labs:09 [2024/11/30 19:33]
dimitrie.valu Fix redundancy
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 19: Line 19:
 </​code>​ </​code>​
  
-If you run ''​%%cat private.pem%%'',​ you will see how the private key is stored in PEM format. PEM is a base64-encoded format that is used to store cryptographic keys and certificates;​ there are [[https://​myarch.com/​public-private-key-file-formats|other formats as well]], however PEM is the most common one for X.509 certificates,​ CSRs, and cryptographic keys.+If you run ''​%%cat private.pem%%'',​ you will see how the private key is stored in PEM format. PEM is a base64-encoded format that is used to store cryptographic keys and certificates;​ there are [[https://​myarch.com/​public-private-key-file-formats |other formats as well]], however PEM is the most common one for X.509 certificates,​ CSRs, and cryptographic keys.
  
 Now, generate a public key from the private key: Now, generate a public key from the 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.
  
-Generate a certificate signing request (CSR) using the following command:+=== [10p] Create a CA === 
 + 
 +Create a self-signed certificate using the following command: 
 + 
 +<code bash> 
 +openssl req -new -x509 -key private.pem -out ca.pem -days 365 
 +</​code>​ 
 + 
 +This command generates a new certificate signing request (CSR) and a new self-signed certificate. The ''​%%-x509%%''​ option specifies that the output is a self-signed certificate. The ''​%%-days%%''​ option specifies the number of days the certificate is valid for. You can view the contents of the certificate using the following command: 
 + 
 +<code bash> 
 +openssl x509 -in ca.pem -text -noout 
 +</​code>​ 
 + 
 +What are the differences between the certificate you generated and the one you extracted from a website? Write down the answer in the text file. 
 + 
 +<ifauth @isc> 
 +<​hidden>​ 
 + 
 +The certificate you generated is self-signed,​ while the one you extracted from a website is signed by a Certificate Authority. 
 + 
 +</​hidden>​ 
 +</​ifauth>​ 
 + 
 +=== [10p] Sign a certificate === 
 + 
 +Now that you have a CA, you can sign a certificate with it. Generate a certificate signing request (CSR) using the following command:
  
 <code bash> <code bash>
Line 171: Line 301:
  
 <code bash> <code bash>
-openssl x509 -req -days 365 -in request.csr -signkey ​private.pem -out cert.pem+openssl x509 -req -in request.csr -CA ca.pem -CAkey ​private.pem ​-CAcreateserial ​-out cert.pem ​-days 365
 </​code>​ </​code>​
  
Line 180: Line 310:
 </​code>​ </​code>​
  
-What are the differences between the CSR and the certificate? Write down the answer ​in the text file.+Now, take {{ :​isc:​labs:​isc_request.txt |this CSR}} (the extension is ''​%%.txt%%''​ to bypass OCW restrictions :)) ) and sign it using your CA. Display ​the signed ​certificate's contents and save the output ​in your text file.
  
 <ifauth @isc> <ifauth @isc>
 <​hidden>​ <​hidden>​
  
-The CSR contains information about the entity that is requesting the certificate,​ and the certificate includes that and added bits, such as the following:+The command to sign the CSR is the following:
  
 <code bash> <code bash>
-Serial Number and Signature Algorithm +openssl x509 -req -in isc_request.txt -CA ca.pem -CAkey private.pem -CAcreateserial -out cert.pem -days 365 
-Issuer +</​code>​ 
-Validity+ 
 +As a result, you can check for the following subject field in the text file: 
 + 
 +<​code>​ 
 +Subject: C = RO, ST = Bucharest, L = Bucharest, O = UNSTPB, 
 +OU = "ACS, CTI", CN = Introducere in Securitate Cibernetica
 </​code>​ </​code>​
  
Line 197: 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 223: Line 358:
 By convention, port 80 is reserved for HTTP traffic, and port 443 is reserved for HTTPS; we're using port 1337 here to avoid conflicts with other services that might be running on your machine. By convention, port 80 is reserved for HTTP traffic, and port 443 is reserved for HTTPS; we're using port 1337 here to avoid conflicts with other services that might be running on your machine.
 </​note>​ </​note>​
 +
 +=== [15p] HTTP vs HTTPS ===
  
 Run ''​%%curl http://​127.0.0.1:​1337%%''​ in another terminal. What do you see? What happens if you run ''​%%curl https://​127.0.0.1:​1337%%''​ (changed ''​%%http%%''​ to ''​%%https%%''​) and why? Run ''​%%curl http://​127.0.0.1:​1337%%''​ in another terminal. What do you see? What happens if you run ''​%%curl https://​127.0.0.1:​1337%%''​ (changed ''​%%http%%''​ to ''​%%https%%''​) and why?
Line 236: Line 373:
 {{ :​isc:​labs:​tls.png?​nolink&​400 |}} {{ :​isc:​labs:​tls.png?​nolink&​400 |}}
  
-Take a look at [[https://​tls12.xargs.org/​|this]] and identify what the first 5 bytes within the server'​s mangled output signify, only using the information from that website - no need to go more in-depth. Note what you found into your text file.+Take a look at [[https://​tls12.xargs.org/​ |this]] and identify what the first 5 bytes within the server'​s mangled output signify, only using the information from that website - no need to go more in-depth. Note what you found into your text file.
  
 <ifauth @isc> <ifauth @isc>
Line 246: Line 383:
 </​ifauth>​ </​ifauth>​
  
-Now modify the script to run the server over HTTPS. To do that, add the ''​%%ssl_context%%''​ argument to the ''​%%app.run%%''​ function call, with the following parameters:+=== [15p] HTTPS server ===
  
-  * ''​%%certfile%%''​ - the path to the certificate file +Download {{ :​isc:​labs:​isc_lab09.zip |this .zip file}} and extract its contents. There, you will find multiple files; for now, try and verify if the ''​%%isc_signed_cert.crt%%'' ​is valid using the following command:
-  * ''​%%keyfile%%'' ​the path to the private key file+
  
-<ifauth @isc+<code bash> 
-<hidden>+openssl verify isc_signed_cert.crt 
 +</code>
  
-You need to modify ​the last line in the script ​to look like this:+Why did it fail? OpenSSL references a default directory containing trusted CA certificates when verifying a certificate. Copy ''​%%isc_ca.crt%%'' ​to ''​%%/​usr/​local/​share/​ca-certificates%%''​ and run the following command ​to update the CA certificates:
  
-<​code ​python+<​code ​bash
-app.run(ssl_context=('​cert.pem',​ '​key.pem'​),​ port=1337)+update-ca-certificates
 </​code>​ </​code>​
  
-</​hidden>​ +Now verify the certificate again. Has the output changed? Save the output in your text file.
-</​ifauth>​+
  
 +You can also manually specify a CA file for verification:​
  
-Now 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.+<code bash> 
 +openssl verify -CAfile isc_ca.crt isc_signed_cert.crt 
 +</​code>​ 
 + 
 +Modify your Python script to run the server over HTTPS. To do that, add the ''​%%ssl_context%%''​ argument to the ''​%%app.run%%''​ function call, with the following parameters:​ 
 + 
 +  * ''​%%certfile%%''​ - the path to the client'​s signed certificate (''​%%isc_signed_cert.crt%%''​) 
 +  * ''​%%keyfile%%''​ - the path to the client'​s private key file (''​%%client_key.pem%%''​) 
 + 
 +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>
 <​hidden>​ <​hidden>​
 +
 +You need to modify the last line in the script to look like this:
 +
 +<code python>
 +app.run(ssl_context=('​isc_signed_cert.crt',​ '​client_key.pem'​),​ port=1337)
 +</​code>​
 +
 +And then modify it to look like this:
 +
 +<code python>
 +app.run(ssl_context=('​correct_signed_cert.crt',​ '​client_key.pem'​),​ port=1337)
 +</​code>​
  
 You need to use ''​%%--insecure%%''​ or ''​%%-k%%''​ to ignore certificate validation: You need to use ''​%%--insecure%%''​ or ''​%%-k%%''​ to ignore certificate validation:
Line 273: Line 431:
 <code bash> <code bash>
 curl -k https://​127.0.0.1:​1337 curl -k https://​127.0.0.1:​1337
 +curl --insecure https://​127.0.0.1:​1337
 </​code>​ </​code>​
 +
 +</​hidden>​
 +</​ifauth>​
 +
 +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>
 +<​hidden>​
 +
 +This time, the ''​%%curl%%''​ command should successfully return ''​%%Hello World!%%''​.
  
 </​hidden>​ </​hidden>​
Line 282: 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?​
  
isc/labs/09.1732988005.txt.gz · Last modified: 2024/11/30 19:33 by dimitrie.valu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0