Index: src/filed/backup.c
===================================================================
--- src/filed/backup.c	(revision 3419)
+++ src/filed/backup.c	(working copy)
@@ -599,7 +599,6 @@
    wbuf = sd->msg;                    /* write buffer */
    cipher_input = (uint8_t *)rbuf;    /* encrypt uncompressed data */
 
-
    Dmsg1(300, "Saving data, type=%d\n", ff_pkt->type);
 
 #ifdef HAVE_LIBZ
@@ -620,7 +619,7 @@
 
       /* 
        * Only change zlib parameters if there is no pending operation.
-       * This should never happen as deflaterset is called after each
+       * This should never happen as deflatereset is called after each
        * deflate.
        */
 
@@ -670,7 +669,7 @@
 
    /*
     * Make space at beginning of buffer for fileAddr because this
-    *   same buffer will be used for writing if compression if off.
+    *   same buffer will be used for writing if compression is off.
     */
    if (ff_pkt->flags & FO_SPARSE) {
       rbuf += SPARSE_FADDR_SIZE;
@@ -728,13 +727,13 @@
 
 #ifdef HAVE_LIBZ
       /* Do compression if turned on */
-      if (!sparseBlock && (ff_pkt->flags & FO_GZIP) && jcr->pZLIB_compress_workset) {         
+      if (!sparseBlock && (ff_pkt->flags & FO_GZIP) && jcr->pZLIB_compress_workset) {
          compress_len = max_compress_len;
          Dmsg4(400, "cbuf=0x%x len=%u rbuf=0x%x len=%u\n", cbuf, compress_len,
             rbuf, sd->msglen);
          
          ((z_stream*)jcr->pZLIB_compress_workset)->next_in   = (Bytef *)rbuf;
-                        ((z_stream*)jcr->pZLIB_compress_workset)->avail_in  = sd->msglen;               
+                        ((z_stream*)jcr->pZLIB_compress_workset)->avail_in  = sd->msglen;
          ((z_stream*)jcr->pZLIB_compress_workset)->next_out  = (Bytef *)cbuf;
                         ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = compress_len;
 
@@ -760,15 +759,26 @@
 #endif
 
       if (ff_pkt->flags & FO_ENCRYPT) {
+         uint32_t initial_len = 0;
+
+         /* Encrypt the length of the input block */
+         uint32_t packet_len = htonl(cipher_input_len);
+
+         if (!crypto_cipher_update(cipher_ctx, (const u_int8_t *)&packet_len, sizeof(packet_len), (u_int8_t *)jcr->crypto_buf, &initial_len)) {
+            /* Encryption failed. Shouldn't happen. */
+            Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
+            goto err;
+         }
+
          /* Encrypt the input block */
-         if (crypto_cipher_update(cipher_ctx, cipher_input, cipher_input_len, (uint8_t *)jcr->crypto_buf, &encrypted_len)) {
-            if (encrypted_len == 0) {
+         if (crypto_cipher_update(cipher_ctx, cipher_input, cipher_input_len, (u_int8_t *)&jcr->crypto_buf[initial_len], &encrypted_len)) {
+            if ((initial_len + encrypted_len) == 0) {
                /* No full block of data available, read more data */
                continue;
             }
             Dmsg2(400, "encrypted len=%d unencrypted len=%d\n",
                encrypted_len, sd->msglen);
-            sd->msglen = encrypted_len; /* set encrypted length */
+            sd->msglen = initial_len + encrypted_len; /* set encrypted length */
          } else {
             /* Encryption failed. Shouldn't happen. */
             Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
Index: src/filed/restore.c
===================================================================
--- src/filed/restore.c	(revision 3423)
+++ src/filed/restore.c	(working copy)
@@ -383,6 +383,9 @@
             bclose(&bfd);
             continue;
          }
+
+         jcr->crypto_count = 0;
+         jcr->crypto_size = 0;
          break;
 
       case STREAM_FILE_DATA:
@@ -728,6 +731,55 @@
    return false;
 }
 
+bool decompress_data(JCR *jcr, char **data, uint32_t *length)
+{
+#ifdef HAVE_LIBZ
+   uLong compress_len;
+   int stat;
+   char ec1[50];                      /* Buffer printing huge values */
+
+   /* 
+    * NOTE! We only use uLong and Byte because they are
+    *  needed by the zlib routines, they should not otherwise
+    *  be used in Bacula.
+    */
+   compress_len = jcr->compress_buf_size;
+   Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, *length);
+   if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
+               (const Byte *)*data, (uLong)*length)) != Z_OK) {
+      Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
+            jcr->last_fname, zlib_strerror(stat));
+      return false;
+   }
+   *data = jcr->compress_buf;
+   *length = compress_len;
+   Dmsg2(100, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
+   return true;
+#else
+   Qmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
+   return false;
+#endif
+}
+
+bool store_data(JCR *jcr, BFILE *bfd, char *data, const int32_t length, bool win32_decomp)
+{
+   if (win32_decomp) {
+      if (!processWin32BackupAPIBlock(bfd, data, length)) {
+         berrno be;
+         Jmsg2(jcr, M_ERROR, 0, _("Write error in Win32 Block Decomposition on %s: %s\n"), 
+               jcr->last_fname, be.strerror(bfd->berrno));
+         return false;
+      }
+   } else if (bwrite(bfd, data, length) != (ssize_t)length) {
+      berrno be;
+      Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
+            jcr->last_fname, be.strerror(bfd->berrno));
+      return false;
+   }
+
+   return true;
+}
+
 /*
  * In the context of jcr, write data to bfd.
  * We write buflen bytes in buf at addr. addr is updated in place.
@@ -737,14 +789,11 @@
 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
       uint64_t *addr, int flags, CIPHER_CONTEXT *cipher, uint32_t cipher_block_size)
 {
-   int stat;
    char *wbuf;                        /* write buffer */
    uint32_t wsize;                    /* write size */
    uint32_t rsize;                    /* read size */
+   uint32_t decrypted_len = 0;        /* Decryption output length */
    char ec1[50];                      /* Buffer printing huge values */
-   const uint8_t *cipher_input;       /* Decryption input */
-   uint32_t cipher_input_len;         /* Decryption input length */
-   uint32_t decrypted_len = 0;        /* Decryption output length */
 
    if (flags & FO_SPARSE) {
       ser_declare;
@@ -768,86 +817,121 @@
       wbuf = buf;
       rsize = buflen;
    }
+
+   jcr->ReadBytes += rsize;
    wsize = rsize;
-   cipher_input = (uint8_t *)wbuf;
-   cipher_input_len = (uint32_t)wsize;
 
    if (flags & FO_ENCRYPT) {
       ASSERT(cipher);
 
+      while (jcr->crypto_size > 0 && jcr->crypto_count > 0 && wsize > 0) {
+         uint32_t chunk_size = 16;
+
+         if (chunk_size > wsize) {
+            chunk_size = wsize;
+         }
+
+         /*
+          * Grow the crypto buffer, if necessary.
+          * crypto_cipher_update() will process only whole blocks,
+          * buffering the remaining input.
+          */
+         jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, jcr->crypto_count + chunk_size + cipher_block_size);
+
+         /* Decrypt the input block */
+         if (!crypto_cipher_update(cipher, 
+                                   (const u_int8_t *)wbuf, 
+                                   chunk_size, 
+                                   (u_int8_t *)&jcr->crypto_buf[jcr->crypto_count], 
+                                   &decrypted_len)) {
+            /* Decryption failed. Shouldn't happen. */
+            Jmsg(jcr, M_FATAL, 0, _("Decryption error\n"));
+            return -1;
+         }
+
+         jcr->crypto_count += decrypted_len;
+         wbuf += chunk_size;
+         wsize -= chunk_size;
+
+         if (jcr->crypto_count >= jcr->crypto_size) {
+
+            char *packet = &jcr->crypto_buf[4]; /* Decrypted, possibly decompressed output here. */
+            uint32_t packet_size = jcr->crypto_size - 4;
+
+            if (flags & FO_GZIP) {
+               if (!decompress_data(jcr, &packet, &packet_size)) {
+                  return -1;
+               }
+            } else {
+               Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
+            }
+
+            if (!store_data(jcr, bfd, packet, packet_size, (flags & FO_WIN32DECOMP) != 0)) {
+               return -1;
+            }
+
+            jcr->JobBytes += packet_size;
+            *addr += packet_size;
+
+            memmove(&jcr->crypto_buf[0], &jcr->crypto_buf[jcr->crypto_size], jcr->crypto_count - jcr->crypto_size);
+            jcr->crypto_count -= jcr->crypto_size;
+            jcr->crypto_size = 0;
+         }
+      }
+
       /*
        * Grow the crypto buffer, if necessary.
        * crypto_cipher_update() will process only whole blocks,
        * buffering the remaining input.
        */
-      jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, cipher_input_len + cipher_block_size);
+      jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, jcr->crypto_count + wsize + cipher_block_size);
 
-
       /* Decrypt the input block */
-      if (!crypto_cipher_update(cipher, cipher_input, cipher_input_len, (uint8_t *)jcr->crypto_buf, &decrypted_len)) {
+      if (!crypto_cipher_update(cipher, 
+                                (const u_int8_t *)wbuf, 
+                                wsize, 
+                                (u_int8_t *)&jcr->crypto_buf[jcr->crypto_count], 
+                                &decrypted_len)) {
          /* Decryption failed. Shouldn't happen. */
          Jmsg(jcr, M_FATAL, 0, _("Decryption error\n"));
          return -1;
       }
 
+      Dmsg2(100, "decrypted len=%d encrypted len=%d\n", decrypted_len, wsize);
+
       if (decrypted_len == 0) {
          /* No full block of data available, write more data */
-         jcr->ReadBytes += rsize;
          return 0;
       }
 
-      Dmsg2(400, "decrypted len=%d undecrypted len=%d\n",
-         decrypted_len, cipher_input_len);
-      wsize = decrypted_len;
-      wbuf = jcr->crypto_buf; /* Decrypted, possibly decompressed output here. */
+      jcr->crypto_count += decrypted_len;
+
+      if (jcr->crypto_size == 0 && jcr->crypto_count >= 4) {
+         jcr->crypto_size = ntohl(*(uint32_t *)&jcr->crypto_buf[0]) + 4;
+      }
+
+      if (jcr->crypto_size == 0 || jcr->crypto_count < jcr->crypto_size) {
+         return 0;
+      }
+
+      wsize = jcr->crypto_size - 4;
+      wbuf = &jcr->crypto_buf[4]; /* Decrypted, possibly decompressed output here. */
    }
 
    if (flags & FO_GZIP) {
-#ifdef HAVE_LIBZ
-      uLong compress_len;
-      /* 
-       * NOTE! We only use uLong and Byte because they are
-       *  needed by the zlib routines, they should not otherwise
-       *  be used in Bacula.
-       */
-      compress_len = jcr->compress_buf_size;
-      Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
-      if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
-                  (const Byte *)wbuf, (uLong)wsize)) != Z_OK) {
-         Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
-               jcr->last_fname, zlib_strerror(stat));
+      if (!decompress_data(jcr, &wbuf, &wsize)) {
          return -1;
       }
-      wbuf = jcr->compress_buf;
-      wsize = compress_len;
-      cipher_input = (uint8_t *)jcr->compress_buf; /* decrypt decompressed data */
-      cipher_input_len = compress_len;
-      Dmsg2(100, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
-#else
-      Qmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
-      return -1;
-#endif
    } else {
       Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
    }
 
-   if (flags & FO_WIN32DECOMP) {
-      if (!processWin32BackupAPIBlock(bfd, wbuf, wsize)) {
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("Write error in Win32 Block Decomposition on %s: %s\n"), 
-               jcr->last_fname, be.strerror(bfd->berrno));
-         return -1;
-      }
-   } else if (bwrite(bfd, wbuf, wsize) != (ssize_t)wsize) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
-            jcr->last_fname, be.strerror(bfd->berrno));
+   if (!store_data(jcr, bfd, wbuf, wsize, (flags & FO_WIN32DECOMP) != 0)) {
       return -1;
    }
 
    jcr->JobBytes += wsize;
    *addr += wsize;
-   jcr->ReadBytes += rsize;
 
    return wsize;
 }
@@ -860,28 +944,47 @@
 bool flush_cipher(JCR *jcr, BFILE *bfd, int flags, CIPHER_CONTEXT *cipher, uint32_t cipher_block_size)
 {
    uint32_t decrypted_len;
+   char *wbuf;                        /* write buffer */
+   uint32_t wsize;                    /* write size */
+   char ec1[50];                      /* Buffer printing huge values */
 
    /* Write out the remaining block and free the cipher context */
-   jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, cipher_block_size);
+   jcr->crypto_buf = check_pool_memory_size(jcr->crypto_buf, jcr->crypto_count + cipher_block_size);
 
-   if (!crypto_cipher_finalize(cipher, (uint8_t *)jcr->crypto_buf, &decrypted_len)) {
+   if (!crypto_cipher_finalize(cipher, (uint8_t *)&jcr->crypto_buf[jcr->crypto_count], &decrypted_len)) {
       /* Writing out the final, buffered block failed. Shouldn't happen. */
       Jmsg1(jcr, M_FATAL, 0, _("Decryption error for %s\n"), jcr->last_fname);
    }
 
-   if (flags & FO_WIN32DECOMP) {
-      if (!processWin32BackupAPIBlock(bfd, jcr->crypto_buf, decrypted_len)) {
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("Write error in Win32 Block Decomposition on %s: %s\n"), 
-               jcr->last_fname, be.strerror(bfd->berrno));
-         return false;
-      }
-   } else if (bwrite(bfd, jcr->crypto_buf, decrypted_len) != (ssize_t)decrypted_len) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
-            jcr->last_fname, be.strerror(bfd->berrno));
+   if (decrypted_len == 0)
+   {
+      ASSERT(jcr->crypto_count == 0);
+      return true;
+   }
+
+   jcr->crypto_count += decrypted_len;
+
+   if (jcr->crypto_size == 0) {
+      ASSERT(jcr->crypto_count >= 4);
+      jcr->crypto_size = ntohl(*(uint32_t *)&jcr->crypto_buf[0]) + 4;
+   }
+
+   ASSERT(jcr->crypto_count == jcr->crypto_size);
+
+   wbuf = &jcr->crypto_buf[4];
+   wsize = jcr->crypto_size - 4;
+
+   if (flags & FO_GZIP) {
+      decompress_data(jcr, &wbuf, &wsize);
+   } else {
+      Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
+   }
+
+   if (!store_data(jcr, bfd, wbuf, wsize, (flags & FO_WIN32DECOMP) != 0)) {
       return false;
    }
 
+   jcr->JobBytes += wsize;
+
    return true;
 }
Index: src/jcr.h
===================================================================
--- src/jcr.h	(revision 3419)
+++ src/jcr.h	(working copy)
@@ -275,6 +275,8 @@
    uint8_t *pki_session_encoded;      /* Cached DER-encoded copy of pki_session */
    int32_t pki_session_encoded_size;  /* Size of DER-encoded pki_session */
    POOLMEM *crypto_buf;               /* Encryption/Decryption buffer */
+   int32_t crypto_count;              /* Count of bytes currently in crypto_buf */
+   int32_t crypto_size;               /* Total bytes in packet */
    DIRRES* director;                  /* Director resource */
    bool runscript_after;              /* Don't run After Script twice */
 #endif /* FILE_DAEMON */
