This shows you the differences between two versions of the page.
ic:laboratoare:09 [2019/11/09 20:16] dan.dragan |
ic:laboratoare:09 [2020/11/05 17:54] (current) acosmin.maria |
||
---|---|---|---|
Line 3: | Line 3: | ||
==== Exercise 1 ==== | ==== Exercise 1 ==== | ||
- | In this first exercise we'll see how to compute hashes using the OpenSSL command line interface. | + | In this exercise we'll use the command line to compute an HMAC, with SHA-1 as the hashing algorithm. |
- | + | ||
- | You can interact with the OpenSSL utilities in two ways: | + | |
- | * directly from bash, by using the ''openssl'' command followed by the desired command and parameters | + | |
- | * from the OpenSSL console, by using the ''openssl'' command without additional arguments. You can close the console by calling ''quit'' or ''exit''. | + | |
- | + | ||
- | If the manual pages are correctly installed, you can consult the documentation via ''man <command_name>'' (e.g. ''man md5''). | + | |
- | + | ||
- | + | ||
- | Hashes are often used to check the integrity of downloaded files. We will now use OpenSSL to compute the MD5 and SHA-1 hashes of this page. | + | |
- | + | ||
- | Download this page by running: | + | |
- | + | ||
- | <code> | + | |
- | linux$ wget http://ocw.cs.pub.ro/courses/sasc/laboratoare/09 -O sasc.html | + | |
- | </code> | + | |
- | + | ||
- | + | ||
- | Use OpenSSL to compute the MD5 and SHA-1 hashes of the newly downloaded file; print the output in hexadecimal. | + | |
- | + | ||
- | To check your results, you can use ''md5sum'' or ''sha1sum'' as an alternative way of computing the same hashes. | + | |
- | + | ||
- | ==== Exercise 2 ==== | + | |
- | + | ||
- | In this second exercise we'll use the command line to compute an HMAC, with SHA-1 as the hashing algorithm. | + | |
Recall from the lecture that for HMAC to be secure, we need to sample a random key $k \gets \mathcal{K}$. | Recall from the lecture that for HMAC to be secure, we need to sample a random key $k \gets \mathcal{K}$. | ||
Line 34: | Line 10: | ||
For this exercise, use OpenSSL commands to: | For this exercise, use OpenSSL commands to: | ||
- | - generate a 16 byte random key | + | - generate a 16 byte random key; |
- | - use the key to compute the SHA-1 HMAC of the page downloaded in the previous exercise | + | - use the key to compute the SHA-1 HMAC of the following message: "Laborator IC"; |
+ | - use the same key to compute the SHA-1 HMAC of the following message: "Laborator IC!". Notice the difference between the messages - a single character (e.g "!"). Observe that the message authentication codes are completely different. | ||
- | ==== Exercise 3 ==== | + | ==== Exercise 2 ==== |
In this exercise you will implement the Birthday attack on SHA-1 from the previous lab using OpenSSL. The goal is to obtain a collision in the first four bytes of the hash. | In this exercise you will implement the Birthday attack on SHA-1 from the previous lab using OpenSSL. The goal is to obtain a collision in the first four bytes of the hash. | ||
Line 72: | Line 49: | ||
</note> | </note> | ||
- | <hidden>The solution is {{:ic:laboratoare:lab9_sol.zip|here}}.</hidden> | + | |
+ | |||
+ | ==== Exercise 3 ==== | ||
+ | |||
+ | Before you start solving the exercises below, download the {{:ic:laboratoare:aesgcm.zip|lab archive from here}}. | ||
+ | |||
+ | The archive contains the source code for Exercise 4, but sadly it is encrypted. Luckily, we forgot to remove the password file from the archive. | ||
+ | |||
+ | Use ''openssl'' commands to decrypt the source file. | ||
+ | |||
+ | <note hint> | ||
+ | The file is encrypted using AES-256 in CBC mode. | ||
+ | </note> | ||
+ | |||
+ | ==== Exercise 4 ==== | ||
+ | |||
+ | <hidden> | ||
+ | |||
+ | <note hint> | ||
+ | The problem has been fixed, so no more code for students! | ||
+ | </note> | ||
+ | |||
+ | In case you didn't manage to solve Exercise 3 (more recent versions of openssl are not compatible with respect to the encryption/decryption using password), here is the lab starting code: | ||
+ | |||
+ | <code> | ||
+ | |||
+ | #include <openssl/evp.h> | ||
+ | #include <openssl/err.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <stdint.h> | ||
+ | #include <stdio.h> | ||
+ | #include <string.h> | ||
+ | |||
+ | void hexdump(unsigned char * string, int length) { | ||
+ | int i; | ||
+ | for (i = 0; i < length; i++) { | ||
+ | printf("%02x", string[i]); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | int aes_gcm_encrypt(unsigned char * ptext, | ||
+ | int plen, | ||
+ | unsigned char * key, | ||
+ | unsigned char * iv, | ||
+ | unsigned char ** ctext, | ||
+ | int * clen) { | ||
+ | |||
+ | EVP_CIPHER_CTX * ctx; | ||
+ | |||
+ | /* TODO Create new EVP Context */ | ||
+ | |||
+ | /* TODO Initialize context using 256-bit AES-GCM, Encryption operation */ | ||
+ | /* TODO Initialize Key and IV for the new context */ | ||
+ | |||
+ | /* TODO Encrypt data */ | ||
+ | |||
+ | /* TODO Finalize encryption context (computes and appends auth tag) */ | ||
+ | |||
+ | /* TODO Print tag */ | ||
+ | |||
+ | /* TODO Destroy context */ | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int aes_gcm_decrypt(unsigned char * ctext, | ||
+ | int clen, | ||
+ | unsigned char * key, | ||
+ | unsigned char * iv, | ||
+ | unsigned char ** ptext, | ||
+ | int * plen) { | ||
+ | |||
+ | EVP_CIPHER_CTX * ctx; | ||
+ | |||
+ | /* TODO Create new EVP Context */ | ||
+ | |||
+ | /* TODO Initialize context using 256-bit AES-GCM, Decryption operation */ | ||
+ | /* TODO Initialize Key and IV for the new context */ | ||
+ | |||
+ | /* TODO Submit tag data */ | ||
+ | |||
+ | /* TODO Decrypt data */ | ||
+ | |||
+ | /* TODO Finalize decryption context (verifies auth tag) */ | ||
+ | |||
+ | /* TODO Destroy context */ | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int main(int argc, char * argv[]) { | ||
+ | ERR_load_crypto_strings(); | ||
+ | |||
+ | unsigned char key[] = "0123456789abcdef0123456789abcdef"; /* 256-bit key */ | ||
+ | unsigned char iv[] = "0123456789ab"; /* 96-bit IV */ | ||
+ | |||
+ | unsigned char * ptext = (unsigned char *)"Hello, SSLWorld!\n"; | ||
+ | int plen = strlen((const char *)ptext); | ||
+ | |||
+ | unsigned char * ctext; | ||
+ | int clen; | ||
+ | |||
+ | printf("Plaintext = %s\n", ptext); | ||
+ | printf("Plaintext (hex) = "); hexdump(ptext, plen); printf("\n"); | ||
+ | |||
+ | aes_gcm_encrypt(ptext, plen, key, iv, &ctext, &clen); | ||
+ | printf("Ciphertext (hex) = "); hexdump(ctext, clen - 16); printf("\n"); | ||
+ | |||
+ | unsigned char * ptext2; | ||
+ | int plen2; | ||
+ | aes_gcm_decrypt(ctext, clen, key, iv, &ptext2, &plen2); | ||
+ | printf("Done decrypting!\n"); | ||
+ | |||
+ | ptext2[plen2] = '\0'; | ||
+ | printf("Plaintext = %s\n", ptext2); | ||
+ | |||
+ | if (memcmp(ptext, ptext2, strlen((const char *)ptext)) == 0) { | ||
+ | printf("Ok!\n"); | ||
+ | } else { | ||
+ | printf("Not ok :(\n"); | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | </hidden> | ||
+ | |||
+ | In this exercise we'll use OpenSSL to encrypt and decrypt with AES-128-GCM. Unfortunately, AES-GCM is not supported by the command line utilities of OpenSSL so we'll have to implement it ourselves. | ||
+ | |||
+ | Open the file you decrypted in the previous exercise and inspect the code. There are two functions that need to be implemented: ''aes_gcm_encrypt'' and ''aes_gcm_decrypt''. We have included hints to guide you through the code. | ||
+ | |||
+ | The main program initializes a dummy key and a dummy IV; a long message is then encrypted and decrypted. The encryption should automatically include the authentication tag at the end, and the decryption should return an error if the verification of the tag fails. | ||
+ | |||
+ | If you do not change keys and the implementation is ok, the ciphertext you obtain should be equal to our own. Otherwise, some of the tests will fail. | ||
+ | |||
+ | |||
+ | |||
+ | Below we have included an example of encryption with RC2 (taken from the OpenSSL man pages). The AES-GCM encryption implementation is quite similar - the authentication tag is automatically appended when finalizing the encryption context. | ||
+ | |||
+ | <code C> | ||
+ | int do_crypt(FILE *in, FILE *out, int do_encrypt) { | ||
+ | /* Allow enough space in output buffer for additional block */ | ||
+ | inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH]; | ||
+ | int inlen, outlen; | ||
+ | /* Bogus key and IV: we'd normally set these from | ||
+ | * another source. | ||
+ | */ | ||
+ | unsigned char key[] = "0123456789"; | ||
+ | unsigned char iv[] = "12345678"; | ||
+ | /* Don't set key or IV because we will modify the parameters */ | ||
+ | EVP_CIPHER_CTX_init(&ctx); | ||
+ | EVP_CipherInit_ex(&ctx, EVP_rc2(), NULL, NULL, NULL, do_encrypt); | ||
+ | EVP_CIPHER_CTX_set_key_length(&ctx, 10); | ||
+ | /* We finished modifying parameters so now we can set key and IV */ | ||
+ | EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt); | ||
+ | |||
+ | for(;;) { | ||
+ | inlen = fread(inbuf, 1, 1024, in); | ||
+ | if(inlen <= 0) break; | ||
+ | if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen)) { | ||
+ | /* Error */ | ||
+ | EVP_CIPHER_CTX_cleanup(&ctx); | ||
+ | return 0; | ||
+ | } | ||
+ | fwrite(outbuf, 1, outlen, out); | ||
+ | } | ||
+ | if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen)) { | ||
+ | /* Error */ | ||
+ | EVP_CIPHER_CTX_cleanup(&ctx); | ||
+ | return 0; | ||
+ | } | ||
+ | fwrite(outbuf, 1, outlen, out); | ||
+ | EVP_CIPHER_CTX_cleanup(&ctx); | ||
+ | return 1; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <note hint> | ||
+ | You may need to change the the LDFLAGS in Makefile: | ||
+ | LDFLAGS=-lcrypto -ldl | ||
+ | </note> | ||
+ | |||
+ | <note tip> | ||
+ | See the open ssl manual [[https://www.openssl.org/docs/man1.1.0/crypto/EVP_aes_256_gcm.html|here]] page for EVP encrypt to see the usage of the EVP functions and an example similar to the one above. | ||
+ | </note> |