(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
luks.c
       1  /*
       2   * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
       3   * Copyright (C) 2018 Milan Broz <gmazyland@gmail.com>
       4   *
       5   * Inspired by libvolume_id by
       6   *     Kay Sievers <kay.sievers@vrfy.org>
       7   *
       8   * This file may be redistributed under the terms of the
       9   * GNU Lesser General Public License.
      10   */
      11  #include <stdio.h>
      12  #include <stdlib.h>
      13  #include <unistd.h>
      14  #include <string.h>
      15  #include <errno.h>
      16  #include <ctype.h>
      17  #include <stdint.h>
      18  
      19  #include "superblocks.h"
      20  
      21  #define LUKS_CIPHERNAME_L		32
      22  #define LUKS_CIPHERMODE_L		32
      23  #define LUKS_HASHSPEC_L			32
      24  #define LUKS_DIGESTSIZE			20
      25  #define LUKS_SALTSIZE			32
      26  #define LUKS_MAGIC_L			6
      27  #define UUID_STRING_L			40
      28  #define LUKS2_LABEL_L			48
      29  #define LUKS2_SALT_L			64
      30  #define LUKS2_CHECKSUM_ALG_L		32
      31  #define LUKS2_CHECKSUM_L		64
      32  
      33  #define LUKS_MAGIC	"LUKS\xba\xbe"
      34  #define LUKS_MAGIC_2	"SKUL\xba\xbe"
      35  
      36  /* Offsets for secondary header (for scan if primary header is corrupted). */
      37  #define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
      38                               0x40000, 0x080000, 0x100000, 0x200000, 0x400000 }
      39  
      40  static const uint64_t secondary_offsets[] = LUKS2_HDR2_OFFSETS;
      41  
      42  struct luks_phdr {
      43  	uint8_t		magic[LUKS_MAGIC_L];
      44  	uint16_t	version;
      45  	uint8_t		cipherName[LUKS_CIPHERNAME_L];
      46  	uint8_t		cipherMode[LUKS_CIPHERMODE_L];
      47  	uint8_t		hashSpec[LUKS_HASHSPEC_L];
      48  	uint32_t	payloadOffset;
      49  	uint32_t	keyBytes;
      50  	uint8_t		mkDigest[LUKS_DIGESTSIZE];
      51  	uint8_t		mkDigestSalt[LUKS_SALTSIZE];
      52  	uint32_t	mkDigestIterations;
      53  	uint8_t		uuid[UUID_STRING_L];
      54  } __attribute__((packed));
      55  
      56  struct luks2_phdr {
      57  	char		magic[LUKS_MAGIC_L];
      58  	uint16_t	version;
      59  	uint64_t	hdr_size;	/* in bytes, including JSON area */
      60  	uint64_t	seqid;		/* increased on every update */
      61  	char		label[LUKS2_LABEL_L];
      62  	char		checksum_alg[LUKS2_CHECKSUM_ALG_L];
      63  	uint8_t		salt[LUKS2_SALT_L]; /* unique for every header/offset */
      64  	char		uuid[UUID_STRING_L];
      65  	char		subsystem[LUKS2_LABEL_L]; /* owner subsystem label */
      66  	uint64_t	hdr_offset;	/* offset from device start in bytes */
      67  	char		_padding[184];
      68  	uint8_t		csum[LUKS2_CHECKSUM_L];
      69  	/* Padding to 4k, then JSON area */
      70  } __attribute__ ((packed));
      71  
      72  static int luks_attributes(blkid_probe pr, struct luks2_phdr *header, uint64_t offset)
      73  {
      74  	int version;
      75  	struct luks_phdr *header_v1;
      76  
      77  	if (blkid_probe_set_magic(pr, offset, LUKS_MAGIC_L, (unsigned char *) &header->magic))
      78  		return BLKID_PROBE_NONE;
      79  
      80  	version = be16_to_cpu(header->version);
      81  	blkid_probe_sprintf_version(pr, "%u", version);
      82  
      83  	if (version == 1) {
      84  		header_v1 = (struct luks_phdr *)header;
      85  		blkid_probe_strncpy_uuid(pr,
      86  			(unsigned char *) header_v1->uuid, UUID_STRING_L);
      87  	} else if (version == 2) {
      88  		blkid_probe_strncpy_uuid(pr,
      89  			(unsigned char *) header->uuid, UUID_STRING_L);
      90  		blkid_probe_set_label(pr,
      91  			(unsigned char *) header->label, LUKS2_LABEL_L);
      92  		blkid_probe_set_id_label(pr, "SUBSYSTEM",
      93  			(unsigned char *) header->subsystem, LUKS2_LABEL_L);
      94  	}
      95  
      96  	return BLKID_PROBE_OK;
      97  }
      98  
      99  static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag __attribute__((__unused__)))
     100  {
     101  	struct luks2_phdr *header;
     102  	size_t i;
     103  
     104  	header = (struct luks2_phdr *) blkid_probe_get_buffer(pr, 0, sizeof(struct luks2_phdr));
     105  	if (!header)
     106  		return errno ? -errno : BLKID_PROBE_NONE;
     107  
     108  	if (!memcmp(header->magic, LUKS_MAGIC, LUKS_MAGIC_L)) {
     109  		/* LUKS primary header was found. */
     110  		return luks_attributes(pr, header, 0);
     111  	}
     112  
     113  	/* No primary header, scan for known offsets of LUKS2 secondary header. */
     114  	for (i = 0; i < ARRAY_SIZE(secondary_offsets); i++) {
     115  		header = (struct luks2_phdr *) blkid_probe_get_buffer(pr,
     116  			  secondary_offsets[i], sizeof(struct luks2_phdr));
     117  
     118  		if (!header)
     119  			return errno ? -errno : BLKID_PROBE_NONE;
     120  
     121  		if (!memcmp(header->magic, LUKS_MAGIC_2, LUKS_MAGIC_L))
     122  			return luks_attributes(pr, header, secondary_offsets[i]);
     123  	}
     124  
     125  	return BLKID_PROBE_NONE;
     126  }
     127  
     128  const struct blkid_idinfo luks_idinfo =
     129  {
     130  	.name		= "crypto_LUKS",
     131  	.usage		= BLKID_USAGE_CRYPTO,
     132  	.probefunc	= probe_luks,
     133  	.magics		= BLKID_NONE_MAGIC
     134  };