text: /*
  **==============================================================================
  **
  ** LSVMTools 
  ** 
  ** MIT License
  ** 
  ** Copyright (c) Microsoft Corporation. All rights reserved.
  ** 
  ** Permission is hereby granted, free of charge, to any person obtaining a copy
  ** of this software and associated documentation files (the "Software"), to deal
  ** in the Software without restriction, including without limitation the rights
  ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  ** copies of the Software, and to permit persons to whom the Software is
  ** furnished to do so, subject to the following conditions:
  ** 
  ** The above copyright notice and this permission notice shall be included in 
  ** all copies or substantial portions of the Software.
  ** 
  ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  ** SOFTWARE
  **
  **==============================================================================
  */
  #include "luksblkdev.h"
  #include "luks.h"
  #include "alloc.h"
  #include "strings.h"
  #include "print.h"
  
  #define LUKSBLKDEV_MAGIC 0x5acdeed9
  
  typedef struct _BlkdevImpl BlkdevImpl;
  
  struct _BlkdevImpl
  {
      Blkdev base;
      UINT32 magic;
      LUKSHeader header;
      Blkdev* rawdev; /* underlying raw LUKS device */
      UINT8* masterkey; /* size is header->key_bytes */
  };
  
  static BOOLEAN _ValidLUKSBlkdev(
      Blkdev* dev)
  {
      BlkdevImpl* impl = (BlkdevImpl*)dev;
      return impl != NULL && impl->magic == LUKSBLKDEV_MAGIC;
  }
  
  static int _Close(
      Blkdev* dev)
  {
      int rc = -1;
      BlkdevImpl* impl = (BlkdevImpl*)dev;
  
      if (!_ValidLUKSBlkdev(dev))
          goto done;
  
      if (impl->masterkey)
          Free(impl->masterkey);
  
      if (impl->rawdev)
          impl->rawdev->Close(impl->rawdev);
  
      Free(impl);
  
      rc = 0;
  
  done:
      return rc;
  }
  
  static int _GetN(
      Blkdev* dev,
      UINTN blkno,
      UINTN nblocks,
      void* data)
  {
      int rc = -1;
      BlkdevImpl* impl = (BlkdevImpl*)dev;
      UINTN toRead = nblocks * BLKDEV_BLKSIZE;
      UINT8* tmp = NULL;
      Blkdev* rawdev;
      UINTN startBlkno;
  
      if (!_ValidLUKSBlkdev(dev) || !data || !impl->rawdev || !impl->masterkey)
          goto done;
  
      if (!nblocks)
      {
          rc = 0;
          goto done;
      }
  
      /* Allocate memory and read from blk device. */
      tmp = (UINT8*) Malloc(toRead);
      if (!tmp)
          goto done;
  
      rawdev = impl->rawdev;
      startBlkno = impl->header.payload_offset + blkno;
  
      if (rawdev->GetN(rawdev, startBlkno, nblocks, tmp) != 0)
          goto done;
  
      /* Call LUKS function to decrypt the data. */
      if (LUKSCrypt(
          LUKS_CRYPT_MODE_DECRYPT,
          &impl->header,
          impl->masterkey,
          tmp,
          data,
          toRead,
          blkno) != 0)
      {
          goto done;
      }
  
      rc = 0;
  
  done:
      if (tmp)
          Free(tmp);
  
      return rc;
  }
  
  static int _PutN(
      Blkdev* dev,
      UINTN blkno,
      UINTN nblocks,
      const void* data)
  {
      int rc = -1;
      BlkdevImpl* impl = (BlkdevImpl*)dev;
      UINTN toWrite = nblocks * BLKDEV_BLKSIZE;
      UINT8* tmp = NULL;
      Blkdev* rawdev;
      UINTN startBlkno;
  
      if (!_ValidLUKSBlkdev(dev) || !data || !impl->rawdev || !impl->masterkey)
      {
          goto done;
      }
  
      if (!nblocks)
      {
          rc = 0;
          goto done;
      }
  
      /* Allocate memory and encrypt the data. */
      tmp = (UINT8*) Malloc(toWrite);
      if (!tmp)
          goto done;
  
      if (LUKSCrypt(
          LUKS_CRYPT_MODE_ENCRYPT,
          &impl->header,
          impl->masterkey,
          data,
          tmp,
          toWrite,
          blkno) != 0)
      {
          goto done;
      }
  
      /* Write the encrypted data to the device. */
      rawdev = impl->rawdev;
      startBlkno = impl->header.payload_offset + blkno;
      if (rawdev->PutN(rawdev, startBlkno, nblocks, tmp) != 0)
          goto done;
  
      rc = 0;
  
  done:
      if (tmp)
         Free(tmp);
  
      return rc;
  }
  
  static int _SetFlags(
      Blkdev* dev,
      UINT32 flags)
  {
      /* No flags supported */
      return -1;
  }
  
  Blkdev* LUKSBlkdevFromMasterkey(
      Blkdev* rawdev,
      const UINT8* masterkey,
      UINT32 masterkeyBytes)
  {
      BlkdevImpl* impl = NULL;
      UINT8* masterkeyClone = NULL;
      LUKSHeader header;
  
      /* Check parameters */
      if (!rawdev || !masterkey)
          goto done;
  
      /* Read the LUKS header */
      if (LUKSReadHeader(rawdev, &header) != 0)
          goto done;
  
      /* If masterkey size is wrong */
      if (masterkeyBytes != header.key_bytes)
          goto done;
  
      /* Allocate the master key */
      if (!(masterkeyClone = (UINT8*)Calloc(1, header.key_bytes)))
          goto done;
  
      /* Clone the master key */
      Memcpy(masterkeyClone, masterkey, header.key_bytes);
  
      /* Allocate the block device */
      if (!(impl = (BlkdevImpl*)Calloc(1, sizeof(BlkdevImpl))))
          goto done;
  
      /* Initialize the block device */
      impl->base.Close = _Close;
      impl->base.PutN = _PutN;
      impl->base.GetN = _GetN;
      impl->rawdev = rawdev;
      impl->magic = LUKSBLKDEV_MAGIC;
      impl->header = header;
      impl->masterkey = masterkeyClone;
  
  done:
  
      if (!impl)
      {
          if (masterkeyClone)
              Free(masterkeyClone);
      }
  
      return &impl->base;
  }
  
  Blkdev* LUKSBlkdevFromRawBytes(
      Blkdev* rawdev,
      const UINT8* passphrase,
      UINTN passphraseSize)
  {
      BlkdevImpl* impl = NULL;
      UINT8* masterkey = NULL;
      LUKSHeader header;
  
      /* Check parameters */
      if (!rawdev || !passphrase)
          goto done;
  
      /* Read the LUKS header */
      if (LUKSReadHeader(rawdev, &header) != 0)
          goto done;
      
      /* Allocate the master key */
      if (!(masterkey = (UINT8*)Calloc(1, header.key_bytes)))
          goto done;
  
      /* Use passphrase to unlock the master key */
      if (LUKSGetMasterKey(rawdev, &header, passphrase, passphraseSize, masterkey) != 0)
          goto done;
  
      /* Allocate the block device */
      if (!(impl = (BlkdevImpl*)Calloc(1, sizeof(BlkdevImpl))))
          goto done;
  
      /* Initialize the block device */
      impl->base.Close = _Close;
      impl->base.GetN = _GetN;
      impl->base.PutN = _PutN;
      impl->base.SetFlags = _SetFlags;
      impl->magic = LUKSBLKDEV_MAGIC;
      impl->header = header;
      impl->rawdev = rawdev;
      impl->masterkey = masterkey;
  
  done:
  
      if (!impl)
      {
          if (masterkey)
              Free(masterkey);
      }
  
      return &impl->base;
  }
  
  BOOLEAN IsRawLUKSDevice(
      Blkdev* rawdev)
  {
      BOOLEAN result = FALSE;
      union
      {
          LUKSHeader header;
          UINT8 sectors[LUKS_SECTOR_SIZE];
      }
      u;
      static UINT8 _magic[] = LUKS_MAGIC_INITIALIZER;
  
      if (!rawdev)
          goto done;
  
      /* Read the first two sectors of the raw device */
      if (BlkdevRead(rawdev, 0, &u, sizeof(u)) != 0)
          goto done;
  
      /* Check the LUKS magic bytes */
      if (Memcmp(&u.header, _magic, LUKS_MAGIC_SIZE) != 0)
          goto done;
  
      result = TRUE;
  
  done:
      return result;
  }
  
  Blkdev* LUKSBlkdevFromPassphrase(
      Blkdev* rawdev,
      const char* passphrase)
  {
      return LUKSBlkdevFromRawBytes(rawdev, (const UINT8*) passphrase, Strlen(passphrase));
  }
  
  int LUKSBlkdevGetMasterKey(
      Blkdev* dev,
      const UINT8** masterkeyData,
      UINTN* masterkeyBytes)
  {
      int rc = -1;
      BlkdevImpl* impl = (BlkdevImpl*)dev;
  
      if (!_ValidLUKSBlkdev(dev))
          goto done;
  
      if (!masterkeyData || !masterkeyBytes || !impl->masterkey)
          goto done;
  
      *masterkeyData = impl->masterkey;
      *masterkeyBytes = impl->header.key_bytes;
  
      rc = 0;
  
  done:
      return rc;
  }
  