text: // Copyright 2017 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_SECURITY_ZXCRYPT_INCLUDE_ZXCRYPT_VOLUME_H_
  #define SRC_SECURITY_ZXCRYPT_INCLUDE_ZXCRYPT_VOLUME_H_
  
  #include <lib/zx/time.h>
  #include <stddef.h>
  #include <stdint.h>
  #include <zircon/types.h>
  
  #include "src/security/fcrypto/aead.h"
  #include "src/security/fcrypto/bytes.h"
  #include "src/security/fcrypto/cipher.h"
  #include "src/security/fcrypto/digest.h"
  #include "src/security/fcrypto/secret.h"
  
  // |zxcrypt::Volume| manages the interactions of both driver and library code with the metadata
  // used to format and operate zxcrypt devices.  The superblock is saved multiple times on disk to
  // provide redundancy.
  //
  // It manages three types of key material:
  //  - Root: Provided by the consumers of this class.
  //  - Data: Randomly generated at volume creation and used to encrypt and decrypt the volumes data.
  //  - Wrap: Derived from the root keys and used to encrypt and decrypt the data key material.
  //
  // This is an abstract class, with concrete children for FD-backed and
  // zx_device_t-backed implementations.
  namespace zxcrypt {
  
  // Forward declaration of unit test framework.
  namespace testing {
  class TestDevice;
  }
  
  const uint8_t zxcrypt_magic[16] = {
      0x5f, 0xe8, 0xf8, 0x00, 0xb3, 0x6d, 0x11, 0xe7, 0x80, 0x7a, 0x78, 0x63, 0x72, 0x79, 0x70, 0x74,
  };
  
  using key_slot_t = zx_off_t;
  
  // Unifying types used for a couple of calls that will call either FIDL or Banjo
  // interfaces under the hood.
  typedef struct {
    uint64_t block_count;
    uint32_t block_size;
  } BlockInfo;
  
  typedef struct {
    bool allocated;
    size_t count;
  } SliceRegion;
  
  class __EXPORT Volume {
   public:
    // The supported version, named by the algorithms they use.  New version should increment the
    // version number and update the default version.  Zero indicates an error state.
    enum Version : uint32_t {
      kUninitialized = 0,
      kAES256_XTS_SHA256,
    };
  
    // The default version, used when sealing a new volume.
    static const Version kDefaultVersion;
  
    // The amount of data that can "in-flight" to the underlying block device before the zxcrypt
    // driver begins queuing transactions
    static const uint32_t kBufferSize;
  
    explicit Volume();
    virtual ~Volume();
    DISALLOW_COPY_ASSIGN_AND_MOVE(Volume);
  
    // Returns space reserved for metadata and keys
    size_t reserved_blocks() const { return reserved_blocks_; }
    size_t reserved_slices() const { return reserved_slices_; }
    size_t num_slots() const { return num_key_slots_; }
  
    // Opens a zxcrypt volume on the block device described by |fd| using the |key| corresponding to
    // given key |slot|.
    zx_status_t Unlock(const crypto::Secret& key, key_slot_t slot);
  
    // Removes ALL keys, rendering any data in the zxcrypt device inaccessible.  It is an error to
    // call any method except the destructor on this instance after this methods returns.
    zx_status_t Shred();
  
   protected:
    friend class testing::TestDevice;
  
    ////////////////
    // Configuration methods
  
    // Retrieves the block and FVM information and adjusts it.
    zx_status_t Init();
  
    // Maps the volume version to crypto algorithms.
    zx_status_t Configure(Version version);
  
    // Returns via |out| the offset in bytes for the given key |slot|.  Returns an error if the
    // volume hasn't been initialized, or if |slot| is out of range.
    zx_status_t GetSlotOffset(key_slot_t slot, zx_off_t* out) const;
  
    // Derives intermediate keys for the given key |slot| from the given |key|.
    zx_status_t DeriveSlotKeys(const crypto::Secret& key, key_slot_t slot);
  
    // Resets all fields in this object to initial values
    void Reset();
  
    ////////////////
    // Block methods
  
    // Resets the superblock offset to the first location (block 0).
    zx_status_t Begin();
  
    // Advances the superblock offset to the next volume location.  Returns ZX_ERR_STOP if no more
    // offsets available; ZX_ERR_NEXT otherwise.
    zx_status_t Next();
  
    // Creates a new volume, with a new instance GUID and data key and IV, and seals it with the
    // given |key|
    zx_status_t CreateBlock();
  
    // Writes |block| out to each of the superblock locations.
    zx_status_t CommitBlock();
  
    // Encrypts the current data key and IV to the given |slot| using the given |key|.
    zx_status_t SealBlock(const crypto::Secret& key, key_slot_t slot);
  
    // Reads the block and parses and checks various fields before attempting to open it with the
    // given |key| corresponding to the given |slot|.
    zx_status_t UnsealBlock(const crypto::Secret& key, key_slot_t slot);
  
    ////////////////
    // Device methods
  
    virtual zx_status_t GetBlockInfo(BlockInfo* out) = 0;
    virtual zx_status_t GetFvmSliceSize(uint64_t* out) = 0;
    static const size_t MAX_SLICE_REGIONS = 16;
    virtual zx_status_t DoBlockFvmVsliceQuery(uint64_t vslice_start,
                                              SliceRegion ranges[MAX_SLICE_REGIONS],
                                              uint64_t* slice_count) = 0;
    virtual zx_status_t DoBlockFvmExtend(uint64_t start_slice, uint64_t slice_count) = 0;
  
    // Reads a block from the current offset on the underlying device.
    virtual zx_status_t Read() = 0;
  
    // Writes a block to the current offset on the underlying device.
    virtual zx_status_t Write() = 0;
  
    ////////////////
    // Fields
  
    // The underlying block device as accessed via DDK or FDIO.
  
    // The space reserved for metadata.
    uint64_t reserved_blocks_;
    uint64_t reserved_slices_;
  
    // Buffer holding the current block being examined, and its offset on the underlying device.
    crypto::Bytes block_;
    zx_off_t offset_;
  
    // The instance GUID for this device.
    crypto::Bytes guid_;
    // A copy of the entire header, used as AAD for the AEAD.
    crypto::Bytes header_;
  
    // The algorithm, lengths, and buffers for the key-wrapping AEAD.
    crypto::AEAD::Algorithm aead_;
    crypto::Secret wrap_key_;
    crypto::Bytes wrap_iv_;
  
    // The algorithm for data processing Cipher and length of wrapped key material.
    crypto::Cipher::Algorithm cipher_;
    crypto::Secret data_key_;
    crypto::Bytes data_iv_;
    size_t slot_len_;
    size_t num_key_slots_;
  
    // The digest used by the HKDF.
    crypto::digest::Algorithm digest_;
  };
  
  }  // namespace zxcrypt
  
  #endif  // SRC_SECURITY_ZXCRYPT_INCLUDE_ZXCRYPT_VOLUME_H_
  