One assignement of my teacher is driving me crazy because I don't think I'm that far from the solution but I still can't get it so I hope someone will be able to help me figure it out.
Assignment
The assignment in short is as follow : create a LUKS partition of 2GB, then with the dd command, dump 1 Mbytes of the partition /dev/sbd3 (== the LUKS partition) to a file. Can you find the header partition and the crypted master key.
I'm able to find the header with the information given here and here. But I'm not able to find the master key. I tried the following :
- Read the documentation to see if it's at a fixed place. It seems to be the case for LUKS 1 but my partition has LUKS 2.
- Do the encryption with tools found online.
- Do the encryption with Openssl (which was the advice of my teacher as online tools wouldn't always be reliable.
In short, my idea is : do the encryption as it would be done by LUKS and then grep the solution on the header file.
Initial steps to reproduce the situation
Note : the LUKS partition was created on a USB device and was the third partition on it. That's why I refer to /dev/sdb3.
Creation of a partition :
> sudo fdisk /dev/sdb
# Delete partition 3 with d (if I have one)
# press n (new partition)
# press p (primary)
# 3 (partition number)
# 4358144 (start sector)
# +2G (for a partition of 2GiB)
# Delete latest signature if asked
# press w
Creation of a fixed passphrase (64 x '3') and master-key (512 x '3') :
> yes "3" | head -c 1024 > ~/Documents/first
> tr -d '\n' < first >> ~/Documents/three-master
> yes "3" | head -c 128 > ~/Documents/first
> tr -d '\n' < first >> ~/Documents/three
> ls -l # Verify size
> hexdump -v three # Verify data
Creation of the LUKS partition :
> sudo cryptsetup --debug --pbkdf-memory 256 --hash sha512 --key-file ~/Documents/three --master-key-file ~/Documents/three-master --pbkdf pbkdf2 --key-size 256 --pbkdf-force-iterations 1000 luksFormat /dev/sdb3
> sudo dd if=/dev/sdb3 of=~/Documents/header.txt bs=1M count=1
See the LUKS informations :
> sudo cryptsetup luksDump /dev/sdb3
> sudo cryptsetup luksDump --dump-master-key /dev/sdb3
What I did so far
What I've understood of the course lesson :
- The passphrase key is used to derivate another passphrase. For this, a salt, iterations and the algorithm (argon2 or PBKDF2) must be known.
- We get the encrypted master-key with the master-key, the derived passphrase key and an algorithm (aes for example).
Here is the code I wrote which uses the method given by OpenSSL (my sources which helped me here and here) :
//gcc -Wall -Wextra -o crypt crypt.c -lcrypto
#include <openssl/evp.h>
#include <string.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
// PBKDF2
const int PWD_LENGTH = 64;
const char *PWD = "3333333333333333333333333333333333333333333333333333333333333333";
const int ITERATION = 1000;
const int SALT_LEN = 32;
const unsigned char SALT[] = { 0xbd, 0xcc, 0xec, 0x25, 0x28, 0x92, 0x9d, 0xfc,
0x8d, 0xf5, 0x5d, 0xb7, 0x70, 0x1f, 0x43, 0x7d,
0xce, 0xcc, 0x62, 0x00, 0xe5, 0xe9, 0xf0, 0xfb,
0x50, 0x63, 0x57, 0x99, 0xc2, 0x01, 0xa6, 0x4f};
const int ITER = 1000;
const int KEY_LEN = 32;
// AES
const unsigned char plaintext[] = {
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33
};
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
printf("Error occured ! \n");
exit(-1);
}
int encrypt(const unsigned char *plaintext, const int plaintext_len, const unsigned char *key,
const unsigned char *iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int len;
int i;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_xts(), NULL, key, NULL))
handleErrors();
for (i = 0; i < ITER; i++) {
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;
/* Finalise the encryption. Further ciphertext bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;
}
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int main ()
{
printf("Hello world\n");
// === PBKDF2
// this will be the result of PBKDF2-HMAC
unsigned char* out = (unsigned char*)calloc(KEY_LEN, sizeof(unsigned char));
memset(out, '\0', KEY_LEN);
int ret = PKCS5_PBKDF2_HMAC(
PWD,
PWD_LENGTH,
SALT,
SALT_LEN,
ITER,
EVP_sha512(),
KEY_LEN,
out
);
if(ret == 0)
{
printf("An error occured...\n");
exit(-1);
}
printf("out :\n");
for(int i=0;i<KEY_LEN;i++) { printf("%02x", out[i]); }
printf("\n");
// === AES
/* A 256 bit key */
unsigned char *key = out;
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"013dcd83a3d81275";
unsigned char ciphertext[8192];
memset(ciphertext, '\0', 8192);
/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
/* Encrypt the plaintext */
printf("out size : %d\n", KEY_LEN);
int ciphertext_len = encrypt(plaintext, KEY_LEN, key, iv, ciphertext);
printf("Cipher text length : %d\n", ciphertext_len);
/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
for(int i=0; i < 8192; i++)
{
if(ciphertext[i] == '\0')
break;
printf("%02x", ciphertext[i]);
}
printf("\n");
/* Clean up */
EVP_cleanup();
ERR_free_strings();
free(out);
return (0);
}
Then I would try to find the result in the header.txt file :
xxd -p ~/Documents/header.txt | tr -d '\n' | grep 'the result'
I get the feeling that the PBKDF2 derived key is alright because I get the same result when using this site. But I don't know about the AES algorithm as I can't find the master key in the header (either with key given by my code or by this site).
My questions
- What is the IV used by AES ? How do I know it ?
- For AES there is a for-loop in my code. Is-this right ? Does it correspond to the 1000 iters I can see when using
sudo cryptsetup luksDump /dev/sdb3
?
Tell me if something is missing in my steps to reproduce the situation ! Best regards