This shows you the differences between two versions of the page.
ac:laboratoare:05 [2018/09/26 21:47] tiberiu.iorgulescu |
ac:laboratoare:05 [2022/11/03 17:05] (current) marios.choudary |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ===== Lab 05 - PKI and TLS ===== | ||
+ | |||
<hidden> | <hidden> | ||
- | ===== Lab 05 - Public key encryption ===== | + | ==== Task 0: Implement DH + AES-GCM encryption === |
- | In this lab we'll do some cool exercises using public key encryption methods for key exchange and data encryption. | + | Implement DH + AES-GCM encryption starting from the code from previous lab (see bonus 2). |
- | Before starting the labs, download openssl 1.1.0 from [[https://www.openssl.org/source/openssl-1.1.0c.tar.gz|here]]. | + | Use the secret key to encrypt some data and check that the other party can decrypt it. You can use |
- | Save the file to some local folder accessible by you, then compile it and install it to some folder. | + | the code available [[https://paste.ubuntu.com/p/4XZpMtt9ZZ/ | here]] for AES-GCM. |
- | Open the unpacked folder from bash, and run the following commands: | + | |
- | <code bash> | + | |
- | linux$ ./config --prefix=/home/student/local --openssldir=/home/student/local/openssl | + | |
- | linux$ make | + | |
- | linux$ make test | + | |
- | linux$ make install | + | |
- | </code> | + | |
- | (in case of trouble, check also the instructions at the end of [[https://ocw.cs.pub.ro/courses/sasc/laboratoare/08|lab 8]]). | + | |
- | + | ||
- | While the tools are building/compiling you may start working on some of the exercises. | + | |
- | + | ||
- | + | ||
- | ==== Exercise 1: Diffie-Hellman key exchange (4p) ==== | + | |
- | + | ||
- | As we discussed in class, Diffie and Hellman proposed the first public key exchange mechanism such that | + | |
- | two parties, that did not share any previous secret could establish a common secret. This allows | + | |
- | the parties to have a shared key that only they know (except if there is an active man in the middle attack, | + | |
- | which is usually solved by using TLS/certificates, but we shall not focus on that here). | + | |
- | + | ||
- | Download the lab code from {{:ic:laboratoare:lab_dhe.zip|here}}. After unzipping, you'll find the source code | + | |
- | for a client (dhe.c) and a server (dhe_server.c), along with a Makefile and fixed Diffie-Hellman p and g params in the files dhparam.pem. | + | |
- | + | ||
- | <note> | + | |
- | Update the Makefile with the paths relevant to your installation folders | + | |
- | </note> | + | |
- | + | ||
- | The client and server have a similar structure. Each of them should build a public key, then send it to the other party, receive the public key from the other party and finally compute the secret key. Your task is to complete the missing parts. For this, consult the openssl documentation [[https://www.openssl.org/docs/man1.1.0/crypto/|here]]. Since they are similar, focus only on one of them and then do similarly on the other one. | + | |
- | + | ||
- | The makefile should help you build both. Just type 'make all'. | + | |
- | After completing the necessary todo's in the file, you can start the server by typing 'make start_server' and the | + | |
- | client with 'make start_client'. | + | |
- | + | ||
- | If all goes well, you should see the same secret key on both client and server. | + | |
- | + | ||
- | <hidden> | + | |
- | The solution is {{:ic:laboratoare:lab_dhe_solved.zip|here}}. | + | |
</hidden> | </hidden> | ||
- | === Bonus 1 === | + | ==== Public Key Infrastructure ==== |
- | Perform the DH key exchange between two teams, sending the public key values over the network and verify that you get the same secret key. | + | In cryptography, a PKI is an arrangement that binds public keys with respective identities of entities (like people and organizations). The binding is established through a process of registration and issuance of certificates at and by a certificate authority (CA). |
- | === Bonus 2 === | + | PKI is a system for the creation, storage, and distribution of digital certificates which are used to verify that a particular public key belongs to a certain entity. The PKI creates digital certificates which map public keys to entities, securely stores these certificates in a central repository and revokes them if needed. The roles of root certificate, intermediate certificate and end-entity certificate as in the chain of trust can be seen in the picture below: |
- | Use the secret key to encrypt some data (see previous labs) and check that the other party can decrypt it. | + | {{ :ac:laboratoare:chain-of-trust.png?500 |Chain of trust}} |
- | ==== Exercise 2: RSA parity oracle (4p) ==== | + | === Task 1: Investigate certficates for ocw.cs.pub.ro === |
- | Generate a 1024 bit RSA key pair. | + | Using your browser's 'View Certificate' functionality, try to find information about the certificate presented by https://ocw.cs.pub.ro. We are interested in: |
+ | * issuer | ||
+ | * validity dates | ||
+ | * subject (CN: Common Name) | ||
+ | * public key | ||
- | Write an oracle function that uses the private key to answer the question "is the plaintext of this message even or odd" (is the last bit of the message 0 or 1). Imagine for instance a server that accepted RSA-encrypted messages and checked the parity of their decryption to validate them, and spat out an error if they were of the wrong parity. | + | Export server and issuer certificates, or download them from here: {{:ac:laboratoare:certificates.tar}}. We will use ''openssl'' command line tool to investigate certificate files. |
- | + | <note tip> | |
- | Anyways: function returning true or false based on whether the decrypted plaintext was even or odd, and nothing else. | + | You can download a website certificate with this command: |
- | + | <code> | |
- | Take the following string and un-Base64 it in your code (without looking at it!) and encrypt it to the public key, creating a ciphertext: | + | true | openssl s_client -connect ocw.cs.pub.ro:443 2>/dev/null | openssl x509 > ocwcspubro.crt |
- | <note> | + | </code> |
- | VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ== | + | </note> |
+ | <note tip> | ||
+ | You can connect to a HTTPS website using: | ||
+ | <code> | ||
+ | openssl s_client -showcerts -connect ocw.cs.pub.ro:443 | ||
+ | </code> | ||
</note> | </note> | ||
- | With your oracle function, you can trivially decrypt the message. | + | * Display whole certificate |
+ | <code> | ||
+ | $ openssl x509 -in ocwcspubro.crt -noout -text | ||
+ | $ openssl x509 -in TERENASSLCA3.crt -noout -text | ||
+ | </code> | ||
- | Here's why: | + | * Display certificate attributes |
- | * RSA ciphertexts are just numbers. You can do trivial math on them. You can for instance multiply a ciphertext by the RSA-encryption of another number; the corresponding plaintext will be the product of those two numbers. | + | <code> |
- | * If you double a ciphertext (multiply it by (2**e)%n), the resulting plaintext will be either even or odd, depending on whether the multiplication result was larger than the modulus or not. | + | $ openssl x509 -in ocwcspubro.crt -noout -dates |
- | * If the plaintext after doubling is even, doubling the plaintext didn't wrap the modulus --- the modulus is a prime number. | + | $ openssl x509 -in ocwcspubro.crt -noout -issuer |
+ | $ openssl x509 -in ocwcspubro.crt -noout -subject | ||
+ | $ openssl x509 -in ocwcspubro.crt -noout -pubkey | ||
+ | </code> | ||
- | That means the plaintext is less than half the modulus. | + | In order to download the lasters version of TERENASSLCA3.crt, you need to check CA Issuers - URI field of ocw's certificate. |
+ | If you download it, it might be in DER format (binary). You can convert it with the following command: | ||
+ | <code> | ||
+ | openssl x509 -inform der -in TERENASSLCA3.crt -out TERENASSLCA3pem.crt | ||
+ | </code> | ||
- | You can repeatedly apply this heuristic, once per bit of the message, checking your oracle function each time. | + | * Using the certificate of the issuer, we can verify server certificate |
+ | <code> | ||
+ | $ openssl verify -CAfile TERENASSLCA3.crt ocwcspubro.crt | ||
+ | </code> | ||
- | Your decryption function starts with bounds for the plaintext of [0,n]. | + | ==== TLS ==== |
- | Each iteration of the decryption cuts the bounds in half; either the upper bound is reduced by half, or the lower bound is. | + | The Transport Layer Security protocol aims primarily to provide privacy and data integrity between two communicating computer applications. When secured by TLS, connections between a client (e.g., a web browser) and a server (e.g., wikipedia.org) have one or more of the following properties: |
+ | * The connection is private because symmetric cryptography is used to encrypt the data transmitted. The keys for this symmetric encryption are based on a shared secret negotiated at the start of the session. | ||
+ | * The identity of the communicating parties can be authenticated using public-key cryptography and digital certificates. | ||
+ | * The connection ensures integrity because each message transmitted includes a message integrity check using a message authentication code. | ||
- | After log2(n) iterations, you have the decryption of the message. | + | The TLS protocol comprises two layers: the TLS record protocol and the TLS handshake protocol. TLS handshake protocol (both RSA key exchange and Diffie-Hellman key exchange) can be seen in the pictures below: |
- | Print the upper bound of the message as a string at each iteration; you'll see the message decrypt "hollywood style". | + | * {{:ac:laboratoare:ssl-rsa-handshake.jpeg?500}} |
+ | * {{:ac:laboratoare:ssl-dh-handshake.jpeg?500}} | ||
- | Decrypt the string (after encrypting it to a hidden private key) above. | ||
- | {{:ic:laboratoare:parity_oracle.zip}} | + | === Task 2: Investigate the TLS cryptographic parameters === |
- | ==== Exercise 3: Merkle's puzzles (4p) ==== | + | Use your browser to inspect the TLS version and cryptoparameters of popular websites: google.com, amazon.com, microsoft.com. Report any differences. |
- | Alice wants to share a secret with Bob, but she knows that if she explicitly tells it to Bob, Eve somehow will find out (she hears everything). So she and Bob establish a small game which helps them think about the same secret, without saying it. The game goes like this: | + | * Can you tell what is the root certificate, the intermediate certificate and the target/server certificate ? |
- | * Alice sends to Bot a list of puzzles. A puzzle looks like this: | + | * How do you differentiate a root certificate from an intermediate certificate ? |
- | $\mathsf{Puzzle}_i = \mathsf{AES}(\mathsf{key} = 0^{14} \| i, \mathsf{plaintext = Puzzle} \| i \| secret_i)$ | + | === Task 3: Investigate the TLS handshake protocol === |
- | where $secret_i$ represents the $i$-th secret Alice generated (represents 8 randomly generated bytes) and which should be figured out by Bob. | + | |
- | * Bob receives the puzzles and randomly chooses one. He knows the first 14 bytes of the key are 0, so he tries to brute-force the rest of the key until he finds a plain text starting with "Puzzle". This way, he knows Alice's secret (the last part of the plain text). | + | |
- | * Bob sends the index of the puzzle that he solved, in order to let Alice know which secret they agreed on. | + | |
- | In the end, both Alice and Bob share the same secret, and Eve has no clue about it. | + | |
- | Your job is to implement this mechanism starting from the following skeleton: | + | Using Wireshark, investigate the two traffic captures ({{:ac:laboratoare:traffic-captures.tar}}). In both cases try to find: |
- | <file python merkle.py> | + | * How many ciphersuite does the client support? |
- | import random | + | * What could be the purpose of Extension: server_name? |
- | import string | + | * What were the negotiated algorithms? |
- | from Crypto.Cipher import AES | + | * What information is sent in cleartext? It is critical? How would a downgrade attack be performed? |
- | import os | + | |
- | | + | |
- | def aes_enc(k, m): | + | |
- | """ | + | |
- | Encrypt a message m with a key k in ECB mode using AES as follows: | + | |
- | c = AES(k, m) | + | |
- | Args: | + | <note important>The property that compromise of long-term keys does not compromise past session keys is called **Forward Secrecy**. DH key exchange has this property, while RSA key exchange does not.</note> |
- | m should be a bytestring multiple of 16 bytes (i.e. a sequence of characters such as 'Hello...' or '\x02\x04...') | + | |
- | k should be a bytestring of length exactly 16 bytes. | + | |
- | Return: | + | <hidden> |
- | The bytestring ciphertext c | + | ==== Task 3-5: Create your own CA ==== |
- | """ | + | |
- | aes = AES.new(k) | + | |
- | c = aes.encrypt(m) | + | |
- | return c | + | - Create directories for CA and for server files <code>mkdir ca-files server-files</code> |
+ | - Create CA private key and certificate (''cd ca-files/'') | ||
+ | - create CA configuration file <code> | ||
+ | $ cat root-ca.conf | ||
+ | [ req ] | ||
+ | distinguished_name = req_distinguished_name | ||
+ | prompt = no | ||
- | def aes_dec(k, c): | + | [ req_distinguished_name ] |
- | """ | + | C = RO |
- | Decrypt a ciphertext c with a key k in ECB mode using AES as follows: | + | ST = Bucharest |
- | m = AES(k, c) | + | L = Bucharest |
+ | O = UPB Root | ||
+ | CN = UPB Root CA | ||
+ | emailAddress = root@root-ca.org | ||
+ | </code> | ||
+ | - create CA private key and certificate <code>openssl req -config root-ca.conf -new -x509 -sha256 -newkey rsa:2048 -nodes -keyout root-ca.key -days 365 -out root-ca.cert</code> | ||
+ | - inspect CA certificate <code>openssl x509 -in root-ca.cert -text -noout</code> | ||
+ | - Create server private key and Certificate Signing Request (''cd server-files/'') | ||
+ | - generate server private key <code>openssl genrsa -out server.key 2048</code> | ||
+ | - create a Certificate Signing Request config file <code>$ cat server-csr.conf | ||
+ | [ req ] | ||
+ | distinguished_name = req_distinguished_name | ||
+ | prompt = no | ||
- | Args: | + | [ req_distinguished_name ] |
- | c should be a bytestring multiple of 16 bytes (i.e. a sequence of characters such as 'Hello...' or '\x02\x04...') | + | C = RO |
- | k should be a bytestring of length exactly 16 bytes. | + | ST = Bucharest |
+ | L = Bucharest | ||
+ | O = Applied Cryptography Course | ||
+ | CN = applied-cryptography.org | ||
+ | emailAddress = office@applied-cryptography.org</code> | ||
+ | - create a Certificate Signing Request <code>openssl req -config server-csr.conf -new -sha256 -key server.key -out server.csr</code> | ||
+ | - inspect the CSR <code>openssl req -in server.csr -noout -text</code> | ||
+ | - Submit CSR to be signed by the CA and obtain the server certificate | ||
+ | - move CSR to CA folder <code>mv server.csr && cd ../ca-files/</code> | ||
+ | - sign the CSR and obtain the server certificate <code> | ||
+ | echo "01" > root-ca.srl | ||
+ | openssl x509 -in server.csr -out server.cert -req -CA root-ca.cert -CAkey root-ca.key -days 365 -CAserial root-ca.srl | ||
+ | </code> | ||
+ | - inspect and verify server certificate <code> | ||
+ | openssl x509 -in server.cert -text -noout | ||
+ | openssl verify -CAfile root-ca.cert server.cert | ||
+ | </code> | ||
+ | - move certificate to server files folder <code>mv server.cert ../server-files/</code> | ||
+ | - Install Apache and activate SSL module | ||
+ | - install Apache server<code> | ||
+ | sudo apt-get update | ||
+ | sudo apt-get install apache2 | ||
+ | </code> | ||
+ | - activate Apache SSL module <code>sudo a2enmod ssl</code> | ||
+ | - enable the default HTTPS site <code>sudo a2ensite default-ssl</code> | ||
+ | - point applied-cryptography.org to 127.0.0.1 <code>echo "127.0.0.1 applied-cryptography.org" | sudo tee -a /etc/hosts</code> | ||
+ | - restart server and inspect HTTPS website (https://applied-cryptography.org, notice the error occured) <code>sudo service apache2 restart</code> | ||
+ | - Configure Apache to use our certificate | ||
+ | - copy certificate and private key <code> | ||
+ | sudo cp server.key /etc/ssl/private/ | ||
+ | sudo cp server.cert /etc/ssl/certs/ | ||
+ | </code> | ||
+ | - install our certificate and private key on the server <code> | ||
+ | sudo vim /etc/apache2/sites-available/default-ssl.conf | ||
+ | # update SSLCertificate paths | ||
+ | </code> | ||
+ | - restart the server <code>sudo service apache2 restart</code> | ||
+ | - visit https://applied-cryptography.org, notice the error occured | ||
+ | - install CA certificate in Firefox <code>navigate to Menu > Preferences > Advanced > Certificates > View Certificates | ||
+ | click Import and choose root-ca.cert | ||
+ | </code> | ||
+ | - revisit https://applied-cryptography.org (you probably need to launch an incognito window) | ||
- | Return: | + | <note warning>Keeping ''root-ca.key'' private is **very important**. Describe what an attacker with access to private key can do. What about ''server.key''?</note> |
- | The bytestring message m | + | |
- | """ | + | |
- | aes = AES.new(k) | + | |
- | m = aes.decrypt(c) | + | |
- | return m | + | </hidden> |
- | + | ||
- | alice_keys = [] | + | |
- | bob_key = [] | + | |
- | + | ||
- | # TODO This is Alice. She generates 2^16 random keys and 2^16 puzzles. | + | |
- | # A puzzle has the following formula: | + | |
- | # puzzle[i] = aes_enc(key = 0..0 + i, plaintext ="Puzzle" + chr(i) + chr(j) + alice_keys[i]) | + | |
- | # This function shall fill in the alice_keys list and shall return a list of 2^16 puzzles. | + | |
- | def gen_puzzles(): | + | |
- | # TODO | + | |
- | + | ||
- | # TODO This is Bob. He tries to solve one random puzzle. His purpose is to solve one random puzzle | + | |
- | # offered by Alice. | + | |
- | # This function shall fill in the bob_key list with the secret discovered by Bob. | + | |
- | # The function shall return the index of the chosen puzzle. | + | |
- | def solve_puzzle(puzzles): | + | |
- | # TODO | + | |
- | + | ||
- | def main(): | + | |
- | # Alice generates some puzzles | + | |
- | puzzles = gen_puzzles() | + | |
- | # Bob solves one random puzzle and discovers the secret | + | |
- | x = solve_puzzle(puzzles) | + | |
- | print "Bob's secret key: " + bob_key[0] | + | |
- | # Alice receives the puzzle index from Bob and now knows the secret | + | |
- | print "Alice's secret key: " + alice_keys[x] | + | |
- | # The secret should be the same, even if it was not explicitly shared | + | |
- | if bob_key[0] == alice_keys[x]: | + | |
- | print ":)" | + | |
- | else: | + | |
- | print ":(" | + | |
- | + | ||
- | if __name__ == "__main__": | + | |
- | main() | + | |
- | + | ||
- | </file> | + | |
- | + | ||
- | <hidden> | + | |
- | The solution is {{:ic:laboratoare:lab11_sol.zip|here}}. | + | |
- | </hidden> /* do not delete this */ | + |