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.


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>

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)
    printf("Error occured ! \n");

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))

    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))

        /* 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))
        ciphertext_len = len;
        /* Finalise the encryption. Further ciphertext bytes may be written at
        * this stage.
        if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) 
        ciphertext_len += len;

    /* Clean up */
    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(
    if(ret == 0) 
        printf("An error occured...\n");

    printf("out :\n");
    for(int i=0;i<KEY_LEN;i++) { printf("%02x", out[i]); }

    // === 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 */

    /* 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')
        printf("%02x", ciphertext[i]); 

    /* Clean up */

    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

  • 1
    The IV would normally be derived from the sector offset, because for random access, you'd want to be able to find the key at a given offset without generating the entire AES stream up to that point -- so the AES is restarted for each encryption sector. The size of that sector and the IV derivation method should be in the luks header (I'm sure about the sector size, that is a parameter to luksFormat, but I'd expect the method to be there as well for completeness). Nov 24, 2020 at 16:42
  • When looking at the header, there is a field "sector" : 512 bytes, so it should be the sector size. Then as my cipher is aes-xts-plain64, the IV derivation method should be plain64. Then looking at this website it's written ` the initial vector is the 64-bit little-endian version of the sector number, padded with zeros if necessary.` What is the sector number ? o.o
    – Ripitchip
    Nov 28, 2020 at 14:53
  • Sector 0 starts at offset 0, sector 1 starts at offset 512, ... Nov 28, 2020 at 17:26
  • I'm sorry, but I don't really get it. It starts at offset 0 of what ? My passphrase ? Or somewhere in the Luks header ? Maybe I'll need to search how the encryption works because I'm really lost here and didn't have much encryption course.
    – Ripitchip
    Nov 29, 2020 at 18:34
  • Offset 0 of the partition. The partition is divided into sectors where each has the size listed in the header. So to get the AES stream at an arbitrary offset, you divide that offset by the sector size to get the sector number, use that as the IV, and start generating AES, decrypting from the sector start. So to read data at offset 6000 you'd use an IV of 11, and start decrypting at offset 5632, and restart with an IV of 12 when you reach offset 6144. Nov 30, 2020 at 10:17


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.