Kjetil's Information Center: A Blog About My Projects

LUKS Hidden by FAT32

Here is a trick to hide the existence of an encrypted LUKS partition on a disk, by offsetting it into the "data region" of a FAT32 partition. When the disk is inserted on Windows, it will simply show up as an regular empty drive. Putting data on it when mounted as a FAT32 (e.g. on Windows) will most likely destroy the encrypted information.

To find the data region of a FAT32 partition, I have developed this tool based on earlier work on VBRs:

#include <stdio.h>
#include <stdint.h>

#pragma pack(1)
typedef struct vbr_s {
  uint8_t jump_code[3];
  char oem_id[8];
  uint16_t bytes_per_sector;
  uint8_t sectors_per_cluster;
  uint16_t reserved_sectors;
  uint8_t no_of_fats;
  uint16_t root_entries;
  uint16_t small_sectors;
  uint8_t media_descriptor;
  uint16_t sectors_per_fat;
  uint16_t sectors_per_track;
  uint16_t heads;
  uint32_t hidden_sectors;
  uint32_t large_sectors;
  uint8_t physical_drive_number;
  uint8_t current_head;
  uint8_t signature;
  uint32_t id;
  char volume_label[11];
  char system_id[8];
  uint8_t boot_code[448];
  uint16_t boot_record_signature;
} vbr_t;
#pragma pack()

int main(int argc, char *argv[])
  FILE *fh;
  int bytes;
  uint8_t sector[512];
  vbr_t *vbr;

  int root_dir_sectors;
  int fat_part;
  int fat_size;
  int first_data_sector;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s <device>\n", argv[0]);
    return 1;

  fh = fopen(argv[1], "rb");
  if (fh == NULL) {
    fprintf(stderr, "Error: Unable to open device for reading.\n");
    return 1;

  bytes = fread(&sector, sizeof(uint8_t), 512, fh);

  if (bytes < 512) {
    fprintf(stderr, "Error: File is less than 512 bytes.\n");
    return 1;

  vbr = (vbr_t *)&sector[0];

  if (vbr->bytes_per_sector == 0 ||
      vbr->sectors_per_cluster == 0 ||
      vbr->no_of_fats == 0) {
    fprintf(stderr, "Error: Invalid boot record.\n");
    return 1;

  root_dir_sectors = ((vbr->root_entries * 32) + 
    (vbr->bytes_per_sector - 1)) /

  fat_part = ((256 * vbr->sectors_per_cluster) + vbr->no_of_fats) / 2;

  fat_size = ((vbr->large_sectors -
              (vbr->reserved_sectors +
               root_dir_sectors)) + (fat_part - 1)) / fat_part;

  first_data_sector = vbr->reserved_sectors +
                     (vbr->no_of_fats * fat_size) + 

  printf("%d\n", first_data_sector * vbr->bytes_per_sector);
  return 0;

Here are step by step instructions on creating it all:
(Assuming the tool mentioned above is compiled as "fds" and available.)

fdisk /dev/sdd # Create one single large FAT32 partition (0xb) as /dev/sdd1.
mkfs.vfat /dev/sdd1
losetup -o `./fds /dev/sdd1` /dev/loop0 /dev/sdd1
cryptsetup -v luksFormat /dev/loop0
cryptsetup luksOpen /dev/loop0 luks
mkfs.ext2 /dev/mapper/luks
cryptsetup luksClose luks
losetup -d /dev/loop0

Mounting the hidden LUKS partition later on:

losetup -o `./fds /dev/sdd1` /dev/loop0 /dev/sdd1
cryptsetup luksOpen /dev/loop0 luks
mount /dev/mapper/luks /mnt/luks

And unmounting it:

umount /mnt/luks
cryptsetup luksClose luks
losetup -d /dev/loop0

It may be possible to further hide the existence on the LUKS partition by also placing the LUKS header elsewhere, as is allegedly supported in newer versions of the "cryptsetup" tool.

Topic: Scripts and Code, by Kjetil @ 01/03-2016, Article Link