VeraCrypt

Documentation >> Plausible Deniability >> Hidden Volume >> Protection of Hidden Volumes

Protection of Hidden Volumes Against Damage

If you mount a VeraCrypt volume within which there is a hidden volume, you may read data stored on the (outer) volume without any risk. However, if you (or the operating system) need to save data to the outer volume, there is a risk that the hidden volume will get damaged (overwritten). To prevent this, you should protect the hidden volume in a way described in this section.
When mounting an outer volume, type in its password and before clicking OK, click Mount Options:
VeraCrypt GUI
 
In the Mount Options dialog window, enable the option 'Protect hidden volume against damage caused by writing to outer volume '. In the 'Password to hidden volume' input field, type the password for the hidden volume. Click OK and, in the main password entry dialog, click OK.
Mounting with hidden protection


Both passwords must be correct; otherwise, the outer volume will not be mounted. When hidden volume protection is enabled, VeraCrypt does not actually mount the hidden volume. It only decrypts its header (in RAM) and retrieves information about the size of the hidden volume (from the decrypted header). Then, the outer volume is mounted and any attempt to save data to the area of the hidden volume will be rejected (until the outer volume is dismounted). Note that VeraCrypt never modifies the filesystem (e.g., information about allocated clusters, amount of free space, etc.) within the outer volume in any way. As soon as the volume is dismounted, the protection is lost. When the volume is mounted again, it is not possible to determine whether the volume has used hidden volume protection or not. The hidden volume protection can be activated only by users who supply the correct password (and/or keyfiles) for the hidden volume (each time they mount the outer volume).

As soon as a write operation to the hidden volume area is denied/prevented (to protect the hidden volume), the entire host volume (both the outer and the hidden volume) becomes write-protected until dismounted (the VeraCrypt driver reports the 'invalid parameter' error to the system upon each attempt to write data to the volume). This preserves plausible deniability (otherwise certain kinds of inconsistency within the file system could indicate that this volume has used hidden volume protection). When damage to hidden volume is prevented, a warning is displayed (provided that the VeraCrypt Background Task is enabled – see the chapter VeraCrypt Background Task). Furthermore, the type of the mounted outer volume displayed in the main window changes to 'Outer(!) ':
VeraCrypt GUI


Moreover, the field Hidden Volume Protected in the Volume Properties dialog window says:
'Yes (damage prevented!)'.

Note that when damage to hidden volume is prevented, no information about the event is written to the volume. When the outer volume is dismounted and mounted again, the volume properties will not display the string "damage prevented".

There are several ways to check that a hidden volume is being protected against damage:
    /* inflate.h -- internal inflate state definition
     * Copyright (C) 1995-2016 Mark Adler
     * For conditions of distribution and use, see copyright notice in zlib.h
     */
    
    /* WARNING: this file should *not* be used by applications. It is
       part of the implementation of the compression library and is
       subject to change. Applications should only use zlib.h.
     */
    
    /* define NO_GZIP when compiling if you want to disable gzip header and
       trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
       the crc code when it is not needed.  For shared libraries, gzip decoding
       should be left enabled. */
    #ifndef NO_GZIP
    #  define GUNZIP
    #endif
    
    /* Possible inflate modes between inflate() calls */
    typedef enum {
        HEAD = 16180,   /* i: waiting for magic header */
        FLAGS,      /* i: waiting for method and flags (gzip) */
        TIME,       /* i: waiting for modification time (gzip) */
        OS,         /* i: waiting for extra flags and operating system (gzip) */
        EXLEN,      /* i: waiting for extra length (gzip) */
        EXTRA,      /* i: waiting for extra bytes (gzip) */
        NAME,       /* i: waiting for end of file name (gzip) */
        COMMENT,    /* i: waiting for end of comment (gzip) */
        HCRC,       /* i: waiting for header crc (gzip) */
        DICTID,     /* i: waiting for dictionary check value */
        DICT,       /* waiting for inflateSetDictionary() call */
            TYPE,       /* i: waiting for type bits, including last-flag bit */
            TYPEDO,     /* i: same, but skip check to exit inflate on new block */
            STORED,     /* i: waiting for stored size (length and complement) */
            COPY_,      /* i/o: same as COPY below, but only first time in */
            COPY,       /* i/o: waiting for input or output to copy stored block */
            TABLE,      /* i: waiting for dynamic block table lengths */
            LENLENS,    /* i: waiting for code length code lengths */
            CODELENS,   /* i: waiting for length/lit and distance code lengths */
                LEN_,       /* i: same as LEN below, but only first time in */
                LEN,        /* i: waiting for length/lit/eob code */
                LENEXT,     /* i: waiting for length extra bits */
                DIST,       /* i: waiting for distance code */
                DISTEXT,    /* i: waiting for distance extra bits */
                MATCH,      /* o: waiting for output space to copy string */
                LIT,        /* o: waiting for output space to write literal */
        CHECK,      /* i: waiting for 32-bit check value */
        LENGTH,     /* i: waiting for 32-bit length (gzip) */
        DONE,       /* finished check, done -- remain here until reset */
        BAD,        /* got a data error -- remain here until reset */
        MEM,        /* got an inflate() memory error -- remain here until reset */
        SYNC        /* looking for synchronization bytes to restart inflate() */
    } inflate_mode;
    
    /*
        State transitions between above modes -
    
        (most modes can go to BAD or MEM on error -- not shown for clarity)
    
        Process header:
            HEAD -> (gzip) or (zlib) or (raw)
            (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
                      HCRC -> TYPE
            (zlib) -> DICTID or TYPE
            DICTID -> DICT -> TYPE
            (raw) -> TYPEDO
        Read deflate blocks:
                TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
                STORED -> COPY_ -> COPY -> TYPE
                TABLE -> LENLENS -> CODELENS -> LEN_
                LEN_ -> LEN
        Read deflate codes in fixed or dynamic block:
                    LEN -> LENEXT or LIT or TYPE
                    LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
                    LIT -> LEN
        Process trailer:
            CHECK -> LENGTH -> DONE
     */
    
    /* State maintained between inflate() calls -- approximately 7K bytes, not
       including the allocated sliding window, which is up to 32K bytes. */
    struct inflate_state {
        z_streamp strm;             /* pointer back to this zlib stream */
        inflate_mode mode;          /* current inflate mode */
        int last;                   /* true if processing last block */
        int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip,
                                       bit 2 true to validate check value */
        int havedict;               /* true if dictionary provided */
        int flags;                  /* gzip header method and flags (0 if zlib) */
        unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
        unsigned long check;        /* protected copy of check value */
        unsigned long total;        /* protected copy of output count */
        gz_headerp head;            /* where to save gzip header information */
            /* sliding window */
        unsigned wbits;             /* log base 2 of requested window size */
        unsigned wsize;             /* window size or zero if not using window */
        unsigned whave;             /* valid bytes in the window */
        unsigned wnext;             /* window write index */
        unsigned char FAR *window;  /* allocated sliding window, if needed */
            /* bit accumulator */
        unsigned long hold;         /* input bit accumulator */
        unsigned bits;              /* number of bits in "in" */
            /* for string and stored block copying */
        unsigned length;            /* literal or length of data to copy */
        unsigned offset;            /* distance back to copy string from */
            /* for table and code decoding */
        unsigned extra;             /* extra bits needed */
            /* fixed and dynamic code tables */
        code const FAR *lencode;    /* starting table for length/literal codes */
        code const FAR *distcode;   /* starting table for distance codes */
        unsigned lenbits;           /* index bits for lencode */
        unsigned distbits;          /* index bits for distcode */
            /* dynamic table building */
        unsigned ncode;             /* number of code length code lengths */
        unsigned nlen;              /* number of length code lengths */
        unsigned ndist;             /* number of distance code lengths */
        unsigned have;              /* number of code lengths in lens[] */
        code FAR *next;             /* next available space in codes[] */
        unsigned short lens[320];   /* temporary storage for code lengths */
        unsigned short work[288];   /* work area for code table building */
        code codes[ENOUGH];         /* space for code tables */
        int sane;                   /* if false, allow invalid distance too far */
        int back;                   /* bits back of last unprocessed length/lit */
        unsigned was;               /* initial length of match */
    };