Heres a version with a working patch ;)

-- 
You received this message because you are subscribed to the Google Groups 
"bareos-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to bareos-devel+unsubscr...@googlegroups.com.
To post to this group, send email to bareos-devel@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
diff --git a/core/src/lib/crypto.h b/core/src/lib/crypto.h
index d4e845c..1eb5aaf 100644
--- a/core/src/lib/crypto.h
+++ b/core/src/lib/crypto.h
@@ -164,5 +164,6 @@ const char *crypto_digest_name(crypto_digest_t type);
 const char *crypto_digest_name(DIGEST *digest);
 crypto_digest_t CryptoDigestStreamType(int stream);
 const char *crypto_strerror(crypto_error_t error);
+int CryptoRandomFill(unsigned char *buf, int size);
 
 #endif /* BAREOS_LIB_CRYPTO_H_ */
diff --git a/core/src/lib/crypto_openssl.cc b/core/src/lib/crypto_openssl.cc
index 04eb4b8..8ec06bb 100644
--- a/core/src/lib/crypto_openssl.cc
+++ b/core/src/lib/crypto_openssl.cc
@@ -433,6 +433,13 @@ X509_KEYPAIR *crypto_keypair_dup(X509_KEYPAIR *keypair)
    return newpair;
 }
 
+/* 
+ * Fill a buffer with random bytes
+ */
+int CryptoRandomFill(unsigned char *buf, int size)
+{
+  return RAND_bytes(buf, size);
+}
 
 /*
  * Load a public key from a PEM-encoded x509 certificate.
diff --git a/core/src/stored/CMakeLists.txt b/core/src/stored/CMakeLists.txt
index 2a3b5e6..aec46ae 100644
--- a/core/src/stored/CMakeLists.txt
+++ b/core/src/stored/CMakeLists.txt
@@ -78,7 +78,7 @@ set (LIBBAREOSSD_SRCS acquire.cc ansi_label.cc askdir.cc 
autochanger.cc
          butil.cc crc32.cc dev.cc device.cc ebcdic.cc label.cc lock.cc
          mount.cc read_record.cc record.cc reserve.cc scan.cc
          sd_backends.cc sd_plugins.cc sd_stats.cc spool.cc
-         stored_globals.cc stored_conf.cc vol_mgr.cc wait.cc
+         stored_globals.cc stored_conf.cc vol_mgr.cc vol_crypto.cc wait.cc
          ${AVAILABLE_DEVICE_API_SRCS}
     )
 
diff --git a/core/src/stored/block.cc b/core/src/stored/block.cc
index b34fc17..9a08592 100644
--- a/core/src/stored/block.cc
+++ b/core/src/stored/block.cc
@@ -64,6 +64,7 @@ void DumpBlock(DeviceBlock *b, const char *msg)
    int32_t  FileIndex;
    int32_t  Stream;
    int bhl, rhl;
+   char Sum[BLKHDR_SUM_LENGTH+1];
    char buf1[100], buf2[100];
 
    UnserBegin(b->buf, BLKHDR1_LENGTH);
@@ -73,7 +74,15 @@ void DumpBlock(DeviceBlock *b, const char *msg)
    UnserBytes(Id, BLKHDR_ID_LENGTH);
    ASSERT(UnserLength(b->buf) == BLKHDR1_LENGTH);
    Id[BLKHDR_ID_LENGTH] = 0;
-   if (Id[3] == '2') {
+   if (Id[3] == '3') {
+      unser_uint32(VolSessionId);
+      unser_uint32(VolSessionTime);
+      Sum[BLKHDR_SUM_LENGTH] = 0;
+      UnserBytes(Sum, BLKHDR_SUM_LENGTH);
+      bhl = BLKHDR3_LENGTH;
+      rhl = RECHDR2_LENGTH;
+   }
+   else if (Id[3] == '2') {
       unser_uint32(VolSessionId);
       unser_uint32(VolSessionTime);
       bhl = BLKHDR2_LENGTH;
@@ -188,6 +197,7 @@ void EmptyBlock(DeviceBlock *block)
    block->write_failed = false;
    block->block_read = false;
    block->FirstIndex = block->LastIndex = 0;
+   memset(block->Sum, 0, 32);
 }
 
 /**
@@ -202,16 +212,18 @@ static uint32_t SerBlockHeader(DeviceBlock *block, bool 
DoChecksum)
    uint32_t block_len = block->binbuf;
 
    Dmsg1(1390, "SerBlockHeader: block_len=%d\n", block_len);
-   SerBegin(block->buf, BLKHDR2_LENGTH);
+   SerBegin(block->buf, BLKHDR3_LENGTH);
    ser_uint32(CheckSum);
    ser_uint32(block_len);
    ser_uint32(block->BlockNumber);
    SerBytes(WRITE_BLKHDR_ID, BLKHDR_ID_LENGTH);
-   if (BLOCK_VER >= 2) {
+   if (BLOCK_VER == 2) {
       ser_uint32(block->VolSessionId);
       ser_uint32(block->VolSessionTime);
    }
-
+   if (BLOCK_VER == 3) {
+     SerBytes(block->Sum, BLKHDR_SUM_LENGTH);
+   }
    /*
     * Checksum whole block except for the checksum
     */
@@ -220,7 +232,7 @@ static uint32_t SerBlockHeader(DeviceBlock *block, bool 
DoChecksum)
                     block_len-BLKHDR_CS_LENGTH);
    }
    Dmsg1(1390, "ser_bloc_header: checksum=%x\n", CheckSum);
-   SerBegin(block->buf, BLKHDR2_LENGTH);
+   SerBegin(block->buf, BLKHDR3_LENGTH);
    ser_uint32(CheckSum);              /* now add checksum to block header */
    return CheckSum;
 }
@@ -280,6 +292,24 @@ static inline bool unSerBlockHeader(JobControlRecord *jcr, 
Device *dev, DeviceBl
          block->read_errors++;
          return false;
       }
+   } else if (Id[3] == '3') {
+      unser_uint32(block->VolSessionId);
+      unser_uint32(block->VolSessionTime);
+      UnserBytes(block->Sum, BLKHDR_SUM_LENGTH);
+      bhl = BLKHDR3_LENGTH;
+      block->BlockVer = 3;
+      block->bufp = block->buf + bhl;
+      if (!bstrncmp(Id, BLKHDR3_ID, BLKHDR_ID_LENGTH)) {
+         dev->dev_errno = EIO;
+         Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", 
got \"%s\". Buffer discarded.\n"),
+            dev->file, dev->block_num, BLKHDR3_ID, Id);
+         if (block->read_errors == 0 || verbose >= 2) {
+            Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+         }
+         block->read_errors++;
+         return false;
+      }
+
    } else {
       dev->dev_errno = EIO;
       Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got 
\"%s\". Buffer discarded.\n"),
@@ -322,7 +352,9 @@ static inline bool unSerBlockHeader(JobControlRecord *jcr, 
Device *dev, DeviceBl
    block->BlockNumber = BlockNumber;
    Dmsg3(390, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
       bhl, block_len);
-   if (block_len <= block->read_len && dev->DoChecksum()) {
+   /* The crytpo checksum works to checksum the block and crc32 wont work after
+    * the raw block is enciphered */
+   if (block_len <= block->read_len && dev->DoChecksum() && dev->VolHdr.cipher 
== 0) {
       BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
                          block_len-BLKHDR_CS_LENGTH);
       if (BlockCheckSum != CheckSum) {
@@ -572,6 +604,7 @@ bool DeviceControlRecord::WriteBlockToDev()
    int hit_max1, hit_max2;
    bool ok = true;
    DeviceControlRecord *dcr = this;
+   struct DeviceBlock *prev_block;
    uint32_t checksum;
 
    if (no_tape_write_test) {
@@ -724,6 +757,17 @@ bool DeviceControlRecord::WriteBlockToDev()
    int retry = 0;
    errno = 0;
    status = 0;
+
+   /* Cryto xfrm the block before write. If somethings goes wrong
+    * such as end-of-media we revert back to the OLD plaintext
+    * block and pass it back up to the handlers up the stack.
+    */
+   prev_block = VolCryptoBlockEncrypt(jcr, block);
+   if (!prev_block) {
+     Dmsg0(200, "VolCryptoBlockEncrypt() returned FALSE!\n");
+     return false;
+   }
+
    do {
       if (retry > 0 && status == -1 && errno == EBUSY) {
          BErrNo be;
@@ -752,6 +796,13 @@ bool DeviceControlRecord::WriteBlockToDev()
 #endif
 
    if (status != (ssize_t)wlen) {
+     /* When using crypto, return to the old, untransformed block before
+      * we pass back */
+      if (prev_block != block) {
+        FreeBlock(block);
+        block = prev_block;
+      }
+
       /*
        * Some devices simply report EIO when the volume is full.
        * With a little more thought we may be able to check
@@ -850,6 +901,11 @@ bool DeviceControlRecord::WriteBlockToDev()
    dev->file_addr += wlen;            /* update file address */
    dev->file_size += wlen;
 
+   /* Discard the old unencrypted block */
+   if (prev_block != block) {
+     FreeBlock(prev_block);
+   }
+
    Dmsg2(1300, "WriteBlock: wrote block %d bytes=%d\n", dev->block_num, wlen);
    EmptyBlock(block);
    return true;
@@ -1075,6 +1131,10 @@ reread:
       return false;
    }
 
+   if (!VolCryptoBlockDecrypt(jcr, block)) {
+     Jmsg0(jcr, M_ERROR, 0, "Volume decryption has failed.\n");
+     return false;
+   }
    /*
     * If the block is bigger than the buffer, we Reposition for
     *  re-reading the block, allocate a buffer of the correct size,
diff --git a/core/src/stored/block.h b/core/src/stored/block.h
index dabc22d..d5f3ebe 100644
--- a/core/src/stored/block.h
+++ b/core/src/stored/block.h
@@ -41,14 +41,17 @@ class Device;                           /* for forward 
reference */
 /* Block Header definitions. */
 #define BLKHDR1_ID                       "BB01"
 #define BLKHDR2_ID                       "BB02"
+#define BLKHDR3_ID                       "BB03"
 #define BLKHDR_ID_LENGTH                  4
 #define BLKHDR_CS_LENGTH                  4     /**< checksum length */
+#define BLKHDR_SUM_LENGTH                32     /**< cryptographic checksum 
len */
 #define BLKHDR1_LENGTH                   16     /**< Total length */
 #define BLKHDR2_LENGTH                   24     /**< Total length */
+#define BLKHDR3_LENGTH                   56     /**< Total length */
 
-#define WRITE_BLKHDR_ID     BLKHDR2_ID
-#define WRITE_BLKHDR_LENGTH BLKHDR2_LENGTH
-#define BLOCK_VER                        2
+#define WRITE_BLKHDR_ID     BLKHDR3_ID
+#define WRITE_BLKHDR_LENGTH BLKHDR3_LENGTH
+#define BLOCK_VER                        3
 
 /* Record header definitions */
 #define RECHDR1_LENGTH                   20
@@ -59,7 +62,8 @@ class Device;                           /* for forward 
reference */
 #define BareosId                         "Bareos 2.0 immortal\n"
 #define OldBaculaId                      "Bacula 1.0 immortal\n"
 #define OlderBaculaId                    "Bacula 0.9 mortal\n"
-#define BareosTapeVersion                20
+#define BareosTapeVersion                21
+#define OldBareosTapeVersion1            20
 #define OldCompatibleBareosTapeVersion1  11
 #define OldCompatibleBareosTapeVersion2  10
 #define OldCompatibleBareosTapeVersion3  9
@@ -102,6 +106,7 @@ struct DeviceBlock {
    uint32_t read_len;                 /* bytes read into buffer, if zero, 
block empty */
    uint32_t VolSessionId;             /* */
    uint32_t VolSessionTime;           /* */
+   uint8_t Sum[BLKHDR_SUM_LENGTH+1];     /* cryptographic checksum */
    uint32_t read_errors;              /* block errors (checksum, header, ...) 
*/
    int      BlockVer;                 /* block version 1 or 2 */
    bool     write_failed;             /* set if write failed */
diff --git a/core/src/stored/label.cc b/core/src/stored/label.cc
index e6315b1..791ceac 100644
--- a/core/src/stored/label.cc
+++ b/core/src/stored/label.cc
@@ -35,6 +35,7 @@
 #include "stored/device.h"
 #include "stored/label.h"
 #include "lib/edit.h"
+#include "lib/crypto.h"
 #include "include/jcr.h"
 
 namespace storagedaemon {
@@ -527,6 +528,8 @@ static void CreateVolumeLabelRecord(DeviceControlRecord 
*dcr, Device *dev, Devic
    SerString(dev->VolHdr.LabelProg);
    SerString(dev->VolHdr.ProgVersion);
    SerString(dev->VolHdr.ProgDate);
+   SerBytes(dev->VolHdr.Salt, sizeof(dev->VolHdr.Salt));
+   ser_uint16(dev->VolHdr.cipher);
 
    SerEnd(rec->data, SER_LENGTH_Volume_Label);
    bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
@@ -577,6 +580,12 @@ void CreateVolumeLabel(Device *dev, const char *VolName, 
const char *PoolName)
    bstrncpy(dev->VolHdr.LabelProg, my_name, sizeof(dev->VolHdr.LabelProg));
    sprintf(dev->VolHdr.ProgVersion, "Ver. %s %s", VERSION, BDATE);
    sprintf(dev->VolHdr.ProgDate, "Build %s %s", __DATE__, __TIME__);
+   memset(dev->VolHdr.Salt, 0, sizeof(dev->VolHdr.Salt));
+   if (device->vol_crypto_key) {
+    /* We dont allow selection, just set something strong */
+     dev->VolHdr.cipher = V_CRYPTO_AESGCM256;
+     CryptoRandomFill((unsigned char *)dev->VolHdr.Salt, 8);
+   }
    dev->SetLabeled();               /* set has Bareos label */
    if (debug_level >= 90) {
       DumpVolumeLabel(dev);
@@ -736,6 +745,8 @@ bool UnserVolumeLabel(Device *dev, DeviceRecord *rec)
 
    dev->VolHdr.LabelType = rec->FileIndex;
    dev->VolHdr.LabelSize = rec->data_len;
+   memset(dev->VolHdr.Key, 0, sizeof(dev->VolHdr.Key));
+   memset(dev->VolHdr.Iv, 0, sizeof(dev->VolHdr.Iv));
 
 
    /* UnSerialize the record into the Volume Header */
@@ -765,6 +776,11 @@ bool UnserVolumeLabel(Device *dev, DeviceRecord *rec)
    UnserString(dev->VolHdr.ProgVersion);
    UnserString(dev->VolHdr.ProgDate);
 
+   if (dev->VolHdr.VerNum > 20) {
+     UnserBytes(dev->VolHdr.Salt, sizeof(dev->VolHdr.Salt));
+     unser_uint16(dev->VolHdr.cipher);
+   }
+
    SerEnd(rec->data, SER_LENGTH_Volume_Label);
    Dmsg0(190, "unser_vol_label\n");
    if (debug_level >= 190) {
@@ -824,7 +840,9 @@ void DumpVolumeLabel(Device *dev)
 {
    int dbl = debug_level;
    uint32_t File;
+   uint64_t salt;
    const char *LabelType;
+   const char *crypto;
    char buf[30];
    struct tm tm;
    struct date_time dt;
@@ -855,7 +873,11 @@ void DumpVolumeLabel(Device *dev)
       break;
    }
 
-   Pmsg11(-1, _("\nVolume Label:\n"
+  /* Bareos formatting doens't let me print this directly */
+   memcpy(&salt, dev->VolHdr.Salt, 8);
+   crypto = GetVolCryptoName(dev->VolHdr.cipher);
+
+   Pmsg13(-1, _("\nVolume Label:\n"
 "Id                : %s"
 "VerNo             : %d\n"
 "VolName           : %s\n"
@@ -867,12 +889,15 @@ void DumpVolumeLabel(Device *dev)
 "MediaType         : %s\n"
 "PoolType          : %s\n"
 "HostName          : %s\n"
+"Cipher            : %s\n"
+"Key Salt          : %llx\n"
 ""),
              dev->VolHdr.Id, dev->VolHdr.VerNum,
              dev->VolHdr.VolumeName, dev->VolHdr.PrevVolumeName,
              File, LabelType, dev->VolHdr.LabelSize,
              dev->VolHdr.PoolName, dev->VolHdr.MediaType,
-             dev->VolHdr.PoolType, dev->VolHdr.HostName);
+             dev->VolHdr.PoolType, dev->VolHdr.HostName,
+             crypto, salt);
 
    if (dev->VolHdr.VerNum >= 11) {
       char dt[50];
diff --git a/core/src/stored/record.h b/core/src/stored/record.h
index 49ba2a9..74d7051 100644
--- a/core/src/stored/record.h
+++ b/core/src/stored/record.h
@@ -160,6 +160,8 @@ struct Volume_Label {
    */
   int32_t LabelType;                  /**< This is written in header only */
   uint32_t LabelSize;                 /**< length of serialized label */
+  uint8_t Key[65];                    /**< Crypto key */
+  uint8_t Iv[65];                     /**< Crypto IV */
   /*
    * The items below this line are stored on
    * the tape
@@ -190,6 +192,8 @@ struct Volume_Label {
   char LabelProg[50];                 /**< Label program name */
   char ProgVersion[50];               /**< Program version */
   char ProgDate[50];                  /**< Program build date/time */
+  char Salt[8];                       /**< Salt used to protect volume */
+  uint16_t cipher;                    /**< Cipher used to encrypt the volume */
 
 };
 
diff --git a/core/src/stored/stored.h b/core/src/stored/stored.h
index d3d909a..1634743 100644
--- a/core/src/stored/stored.h
+++ b/core/src/stored/stored.h
@@ -62,6 +62,7 @@ const int sd_debuglevel = 300;
 #include "stored_conf.h"
 #include "include/jcr.h"
 #include "vol_mgr.h"
+#include "vol_crypto.h"
 #include "reserve.h"
 
 #ifdef BAREOS_LIB_LIB_H_
diff --git a/core/src/stored/stored_conf.cc b/core/src/stored/stored_conf.cc
index e9b295c..907f5e4 100644
--- a/core/src/stored/stored_conf.cc
+++ b/core/src/stored/stored_conf.cc
@@ -262,6 +262,7 @@ static ResourceItem dev_items[] = {
      NULL},
     {"AutoInflate", CFG_TYPE_IODIRECTION, ITEM(res_dev.autoinflate), 0, 0, 
NULL, "13.4.0-", NULL},
     {"CollectStatistics", CFG_TYPE_BOOL, ITEM(res_dev.collectstats), 0, 
CFG_ITEM_DEFAULT, "true", NULL, NULL},
+    {"VolumeCryptoKey", CFG_TYPE_STRNAME, ITEM(res_dev.vol_crypto_key), 0, 0, 
NULL, NULL, NULL},
     {NULL, 0, {0}, 0, 0, NULL, NULL, NULL}};
 
 /**
diff --git a/core/src/stored/stored_conf.h b/core/src/stored/stored_conf.h
index 69a2137..c8b6d13 100644
--- a/core/src/stored/stored_conf.h
+++ b/core/src/stored/stored_conf.h
@@ -179,6 +179,7 @@ public:
    char *unmount_command;             /**< Unmount command */
    char *write_part_command;          /**< Write part command */
    char *free_space_command;          /**< Free space command */
+   char *vol_crypto_key;              /**< Encryption/Decrypt key for volume */
 
    /*
     * The following are set at runtime
diff --git a/core/src/stored/vol_crypto.cc b/core/src/stored/vol_crypto.cc
new file mode 100644
index 0000000..d094adb
--- /dev/null
+++ b/core/src/stored/vol_crypto.cc
@@ -0,0 +1,310 @@
+#include "include/bareos.h"
+#include "stored/stored.h"
+
+#include "vol_crypto.h"
+#include <openssl/evp.h>
+
+namespace storagedaemon {
+
+#define MAX_CIPHERS 2
+
+/* IMPORTANT. Dont use a strict block cipher, they will pad the data
+ *  * making it larger than what it needs to be. GCM is for all intents
+ *   * and purposes - a stream cipher. So we use that which retains
+ *    * the correct length of the data.
+ *     * We could also use chacha20-poly1305 but its less available
+ *      * in openssl. */
+static const char * vol_crypto_name[] = {
+  "None",
+  "AES-GCM-256",
+  NULL
+};
+
+
+static bool get_crypto_key_material(Device *dev, uint8_t *key, uint8_t *iv) {
+
+  Dmsg0(100, "Entering get_crypto_key_material\n");
+  /* We only do this once per volume, given its expensive */
+  if (dev->VolHdr.Key[0] == 0 && dev->VolHdr.Iv[0] == 0) {
+    Dmsg0(10, "Key not derived, attempting to derive key\n");
+    if (!EVP_BytesToKey(EVP_aes_128_gcm(), EVP_sha256(), 
+                       (unsigned char *)dev->VolHdr.Salt,
+                       (unsigned char *)dev->device->vol_crypto_key,
+                       strlen(dev->device->vol_crypto_key),
+                       VOL_CRYPTO_ROUNDS,
+                       (unsigned char *)dev->VolHdr.Key,
+                       (unsigned char *)dev->VolHdr.Iv))  {
+      Dmsg0(10, "Key derivation failed\n");
+      return false;
+    }
+  }
+
+  /* With key material derived, copy the key and derive a new IV */
+  memcpy(key, dev->VolHdr.Key, sizeof(dev->VolHdr.Key));
+  memcpy(iv, dev->VolHdr.Iv, sizeof(dev->VolHdr.Key));
+
+  /* For now, the new IV is partially made up of the block number being 
+ *    * manipulated */
+  memcpy(iv, &dev->block_num, sizeof(dev->block_num));
+
+  return true;
+}
+
+
+
+const char * GetVolCryptoName(int v)
+{
+  if (v >= MAX_CIPHERS)
+    return NULL;
+  return vol_crypto_name[v];
+}
+
+
+bool VolCryptoBlockDecrypt(JobControlRecord *jcr, struct DeviceBlock *block) {
+  struct Device *dev = block->dev;
+  struct DeviceBlock *old = NULL;
+  EVP_CIPHER_CTX *evp;
+  const EVP_CIPHER *cipher = NULL;
+  uint8_t *op = NULL;
+  uint8_t *np = NULL;
+  int32_t olen, nlen, wlen;
+
+  uint8_t key[65];
+  uint8_t iv[65];
+  uint8_t tmp[64];
+
+  if (!block) {
+    return false;
+  }
+
+  dev = block->dev;
+
+  /* We dont decrypt block zero */
+  if (block->BlockNumber == 0) {
+    Dmsg0(100, "Do not decrypt block zero which is typically the volume 
label\n");
+    return true;
+  }
+
+  evp = EVP_CIPHER_CTX_new();
+  if (!evp) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot allocate memory for cipher context\n"));
+    return false;
+  }
+ 
+  /* No decryption on none block */
+  if (dev->VolHdr.cipher == V_CRYPTO_NONE) {
+    return true;
+  }
+  else if (dev->VolHdr.cipher == V_CRYPTO_AESGCM256) {
+    Dmsg0(100, "VOLUME CRYPTO IS AESGCM256\n");
+    cipher = EVP_aes_256_gcm();
+  }
+  else {
+    Dmsg1(100, "Volume header cipher reported back as %d\n", 
dev->VolHdr.cipher);
+    Jmsg1(jcr, M_FATAL, 0, _("Volume header cipher reported back as %d\n"), 
dev->VolHdr.cipher);
+    goto fail;
+  }
+
+  /* Deterine what key and iv we are using for this block */
+  if (!get_crypto_key_material(dev, key, iv)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot derive key material for volume 
crypto\n"));
+    goto fail;
+  }
+
+  if (!EVP_DecryptInit(evp, cipher, key, iv)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot initialize encryption routine\n"));
+    goto fail;
+  }
+
+  /* Retrieve the auth tag */
+  if (dev->VolHdr.cipher == V_CRYPTO_AESGCM256) {
+    if (!EVP_CIPHER_CTX_ctrl(evp, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
+      Jmsg0(jcr, M_FATAL, 0, _("Was unable to set IV len for volume 
decryption\n"));
+      goto fail;
+    }
+  }
+
+  old = dup_block(block);
+  if (!old) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot allocate memory for volume block 
duplication\n"));
+    goto fail;
+  }
+
+  op = (uint8_t *)old->buf + BLKHDR3_LENGTH;
+  np = (uint8_t *)block->buf + BLKHDR3_LENGTH;
+  olen = block->block_len - BLKHDR3_LENGTH;
+  nlen = 0;
+  if (!EVP_DecryptUpdate(evp, np, &nlen, op, olen)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot perform encryption routine\n"));
+    goto swapblock;
+  }
+
+  /* Expect the input to be the same length as the output */
+  if (old->block_len != (nlen + BLKHDR3_LENGTH)) {
+    Jmsg2(jcr, M_FATAL, 0, _("Expected block encryption to be %d bytes but was 
%d\n"),
+                             old->binbuf, block->binbuf);
+    goto swapblock;
+  }
+
+  /* Retrieve the auth tag */
+  if (dev->VolHdr.cipher == V_CRYPTO_AESGCM256) {
+    if (!EVP_CIPHER_CTX_ctrl(evp, EVP_CTRL_GCM_SET_TAG, 16, block->Sum)) {
+      Jmsg0(jcr, M_FATAL, 0, _("Was unable to set tag for volume 
decryption\n"));
+      goto fail;
+    }
+  }
+
+  /* Only when doing a true block mode cipher do we get bytes here */
+  if (!EVP_DecryptFinal(evp, tmp, &wlen)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot finalize encryption routine, possible 
corruption.\n"));
+    goto swapblock;
+  }
+
+  if (wlen != 0) {
+    Jmsg2(jcr, M_FATAL, 0, _("Expected block encryption to be %d bytes after 
finalize but was %d\n"),
+                             block->binbuf, block->binbuf+wlen);
+    goto swapblock;
+  }
+
+  if (old)
+    FreeBlock(old);
+  if (evp)
+    EVP_CIPHER_CTX_free(evp);
+  return true;
+
+swapblock:
+  memcpy(block->bufp, old->bufp, old->binbuf);
+  block->binbuf = old->binbuf;
+
+fail:
+  if (old)
+    FreeBlock(old);
+  if (evp)
+    EVP_CIPHER_CTX_free(evp);
+  return false;
+
+}
+
+struct DeviceBlock * VolCryptoBlockEncrypt(JobControlRecord *jcr, struct 
DeviceBlock *block) {
+  struct Device *dev = NULL;
+  struct DeviceBlock *old = NULL;
+  EVP_CIPHER_CTX *evp;
+  const EVP_CIPHER *cipher = NULL;
+  uint8_t *op = NULL;
+  uint8_t *np = NULL;
+  int32_t olen, nlen, wlen;
+
+  uint8_t key[65];
+  uint8_t iv[65];
+  uint8_t tmp[64];
+
+  if (!block) {
+    return NULL;
+  }
+
+  dev = block->dev;
+
+  /* We dont encrypt block zero */
+  if (block->BlockNumber == 0) {
+    Dmsg0(100, "Do not encrypt block zero which is typically the volume 
label\n");
+    return block;
+  }
+
+  evp = EVP_CIPHER_CTX_new();
+  if (!evp) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot allocate memory for cipher context\n"));
+    return NULL;
+  }
+
+  /* Do nothing if volume encryption isn't enabled */
+  if (dev->VolHdr.cipher ==  V_CRYPTO_NONE) {
+    Dmsg0(100, "VOLUME CRYPTO IS NONE\n");
+    return block;
+  }
+  else if (dev->VolHdr.cipher == V_CRYPTO_AESGCM256) {
+    Dmsg0(100, "VOLUME CRYPTO IS AESGCM256\n");
+    cipher = EVP_aes_256_gcm();
+  }
+  else {
+    Dmsg1(100, "Volume header cipher reported back as %d\n", 
dev->VolHdr.cipher);
+    Jmsg1(jcr, M_FATAL, 0, _("Volume header cipher reported back as %d\n"), 
dev->VolHdr.cipher);
+    goto fail;
+  }
+
+  old = dup_block(block);
+  if (!old) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot allocate memory for volume block 
duplication\n"));
+    goto fail;
+  }
+
+  /* Deterine what key and iv we are using for this block */
+  if (!get_crypto_key_material(dev, key, iv)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot derive key material for volume 
crypto\n"));
+    goto fail;
+  }
+
+  if (!EVP_EncryptInit(evp, cipher, key, iv)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot initialize encryption routine\n"));
+    goto fail;
+  }
+
+  op = (uint8_t *)old->buf + BLKHDR3_LENGTH;
+  np = (uint8_t *)block->buf + BLKHDR3_LENGTH;
+  olen = block->block_len - BLKHDR3_LENGTH;
+  nlen = 0;
+  if (!EVP_EncryptUpdate(evp, np, &nlen, op, olen)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot perform encryption routine\n"));
+    goto swapblock;
+  }
+
+  /* Expect the input to be the same length as the output */
+  if (old->block_len != (nlen + BLKHDR3_LENGTH)) {
+    Jmsg2(jcr, M_FATAL, 0, _("Expected block encryption to be %d bytes but was 
%d\n"),
+                             old->binbuf, block->binbuf);
+    goto swapblock;
+  }
+
+  /* Only when doing a true block mode cipher do we get bytes here */
+  if (!EVP_EncryptFinal(evp, tmp, &wlen)) {
+    Jmsg0(jcr, M_FATAL, 0, _("Cannot finalize encryption routine\n"));
+    goto swapblock;
+  }
+
+  if (wlen != 0) {
+    Jmsg2(jcr, M_FATAL, 0, _("Expected block encryption to be %d bytes after 
finalize but was %d\n"),
+                             block->binbuf, block->binbuf+wlen);
+    goto swapblock;
+  }
+
+  /* Retrieve the auth tag */
+  if (dev->VolHdr.cipher == V_CRYPTO_AESGCM256) {
+    if (!EVP_CIPHER_CTX_ctrl(evp, EVP_CTRL_GCM_GET_TAG, 16, block->Sum)) {
+      Jmsg0(jcr, M_FATAL, 0, _("Was unable to retrieve tag for volume 
encryption\n"));
+      goto swapblock;
+    }
+    /* We've got to write our bytes directly into the buffer from the checksum 
*/
+    memcpy(&block->buf[24], block->Sum, 16);
+    FILE *f = fopen("/tmp/blockdata.dat", "a");
+    fwrite(&block->BlockNumber, sizeof(uint32_t), 1, f);
+    fwrite(block->Sum, 16, 1, f);
+    fclose(f);
+  }
+
+  if (evp)
+    EVP_CIPHER_CTX_free(evp);
+  return old;
+
+swapblock:
+  memcpy(block->bufp, old->bufp, old->binbuf);
+  block->binbuf = old->binbuf;
+
+fail:
+  if (old)
+    FreeBlock(old);
+  if (evp)
+    EVP_CIPHER_CTX_free(evp);
+  return block;
+}
+
+} /* namespace storagedaemon */
+
diff --git a/core/src/stored/vol_crypto.h b/core/src/stored/vol_crypto.h
new file mode 100644
index 0000000..f8fc001
--- /dev/null
+++ b/core/src/stored/vol_crypto.h
@@ -0,0 +1,24 @@
+#ifndef VOL_CRYPTO_H
+#define VOL_CRYPTO_H
+
+#include <openssl/evp.h>
+
+namespace storagedaemon {
+
+#define VOL_CRYPTO_ROUNDS 32768
+#define VOL_CRYPTO_IV_LEN 16
+#define VOL_CRYPTO_KEY_LEN 64
+
+enum {
+  V_CRYPTO_NONE = 0,
+  V_CRYPTO_AESGCM256
+};
+
+struct DeviceBlock * VolCryptoBlockEncrypt(JobControlRecord *jcr, struct 
DeviceBlock *block);
+bool VolCryptoBlockDecrypt(JobControlRecord *jcr, struct DeviceBlock *block);
+
+const char * GetVolCryptoName(int);
+
+} /* namespace storagedaemon */
+#endif
+

Reply via email to