0

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

  • 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). – Simon Richter Nov 24 '20 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](https://gitlab.com/cryptsetup/cryptsetup/-/wikis/DMCrypt) 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 '20 at 14:53
  • Sector 0 starts at offset 0, sector 1 starts at offset 512, ... – Simon Richter Nov 28 '20 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 '20 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. – Simon Richter Nov 30 '20 at 10:17
  • Okey so my LUKS partition begin at 4358144 (cf. the creation shown above). So I did 4358144 / 512 = 8'512 = 0x2140. I tried with { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x40 } or { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x21 } without success (i tried as well with 0x2140 at the beginning then padded with 0). – Ripitchip Nov 30 '20 at 12:15
  • Sorry, that was unclear. It is an offset within the partition. The beginning of the partition has the LUKS header, so there is no encrypted data there -- if there were, the IV for that would be `00 00 00 00 00 00 00 00 ...`. 512 bytes into the partition, we're still inside the LUKS header, but if there were encrypted data here, it'd use the IV `01 00 00 00 00 00 00 00 ...`. At some place behind the LUKS header, typically at 2 MB, actual encrypted data starts, it would have a sector number of 2 MB / 512 = 4096 = 0x1000, so its IV is `00 10 00 00 00 00 00 00 ...`. – Simon Richter Nov 30 '20 at 14:06
  • Using this IV, you can decrypt 512 bytes, then you reset the IV to `01 10 00 00 00 00 00 00 ...` and read the next sector. – Simon Richter Nov 30 '20 at 14:06
  • Ah yes I understand now. But here we are speaking about decryption and since begining I tried to find the encrypted master key. Well I looked at LuksFormat command to see if I could give myseld the initial sector but didn't find any option for this. I think I'll just let it go, I already lost a lot of time on it. I don't really know how my teacher expects us to do it as he adviced me to do the encryption by hand myself, and doesn't seem to know more than you. – Ripitchip Nov 30 '20 at 20:30

0 Answers0