A Adaptive Security of \(\mathsf {CryFS}\)
Theorem 2
\(\mathbf{(Adaptive~Security~of~}{\mathsf {CryFS}}{} \mathbf{).}\) \({\mathsf {CryFS}}^{\mathcal {E}_1, \mathcal {E}_2} = (\mathsf {Gen},\mathsf {Init},\mathsf {Update},\mathsf {Dec})\) is \(\mathsf {IND}\text {-}\mathsf {aCFA}\) secure, if \(\mathcal {E}_1 = (\mathsf {Gen}_1,\mathsf {Enc}_1,\mathsf {Dec}_1)\) and \(\mathcal {E}_2 = (\mathsf {Gen}_2,\mathsf {Enc}_2,\mathsf {Dec}_2)\) are \(\mathsf {IND}\text {-}\mathsf {CPA}\) secure encryption schemes.
Proof
Consider the following modification to \(\mathsf {IND}\text {-}\mathsf {naCFA}\): When the adversary queries \(\mathsf {Init}\) or the \(\mathsf {Update}_j\) oracles or expects output (C, s), instead of getting \(\mathsf {Enc}_1(K_\mathrm {master}, K_\mathrm {fs})\) they instead get \(\mathsf {Enc}_1(K_\mathrm {master}, 0)\). Now, assume towards a contradiction an adversary A with a success probability of p against \(\mathsf {IND}\text {-}\mathsf {aCFA}\) and a success probability of \(p'\) against \(\mathsf {IND}\text {-}\mathsf {aCFA'}\), where \(p = p'+d\) for a positive non-negligible d. This adversary can be used to construct an adversary B with a non-negligible advantage of \(\frac{d}{2}\) which breaks the \(\mathsf {IND}\text {-}\mathsf {CPA}\) security of \(\mathcal {E}_1\). The game draws \(K_\mathrm {master}\leftarrow \mathsf {Gen}_1(1^k)\) and a random bit b. When A uses the \(\mathsf {Init}\) oracle, B generates a new file system key \(K_\mathrm {fs}\leftarrow \mathsf {Gen}_2(1^k)\) and uses the \(\mathsf {LR}\) oracle of the \(\mathsf {IND}\text {-}\mathsf {CPA}\) game to get \(c_\mathrm {fs}\) as either an encryption of 0 or of \(K_\mathrm {fs}\), depending on the value of b. Then it generates a new empty file system \((C_j, s_j)\) but replaces the encryption of \(K_\mathrm {fs}\) with \(c_\mathrm {fs}\). A expects access to an \(\mathsf {Update}_j\) oracle which can be built by using \(K_\mathrm {fs}\) to decrypt and encrypt blocks. Again, B replaces all encryptions of \(K_\mathrm {fs}\) with \(c_\mathrm {fs}\). When the adversary outputs j, \(F^0\), \(F^1\), B draws a random bit a. It uses \(\mathsf {Update}_j\) to build the challenge \((C', s')\) as an encryption of \(F^a\). If A outputs a (A wins), B outputs 1. If A loses, B outputs 0. For \(b=0\), this was a perfect simulation of the \(\mathsf {IND}\text {-}\mathsf {aCFA'}\) game. B has success probability \(\mathrm {Pr}[a\not \leftarrow A \mid b=0] = 1-p'\). For \(b=1\), this was a perfect simulation of the \(\mathsf {IND}\text {-}\mathsf {aCFA}\) game. B has success probability \(\mathrm {Pr}[a \leftarrow A \mid b=1] = p = p'+d\). Together, B has success probability \(\mathrm {Pr}[b \leftarrow B] =\frac{1}{2}(1-p') + \frac{1}{2}(p'+d) = \frac{1}{2} + \frac{d}{2}\). Since d is non-negligible, B has a non-negligible advantage against \(\mathsf {IND}\text {-}\mathsf {CPA}\).
Now, assume towards another contradiction that \(A'\) is a successful attacker on \(\mathsf {IND}\text {-}\mathsf {aCFA'}\). We transform \(A'\) into a successful attacker \(B'\) on the \(\mathsf {IND}\text {-}\mathsf {CPA}\) security of \(\mathcal {E}_2\). Intuitively, \(B'\) selects a random file system created by \(A'\) and uses \(A'\) to break its security. Since the number of file systems is a fixed constant, this only reduces the success probability by a constant amount. The reduction works as follows. The game draws \(\mathsf {K}_\mathrm {fs}\) and a random bit b. \(B'\) draws \(\mathsf {K}_\mathrm {master}\leftarrow \mathsf {Gen}_1(1^k)\) and draws a random \(j^* \leftarrow \{1,\dots ,q_\mathsf {Init}\}\). When \(A'\) uses \(\mathsf {Init}\) for the j-th time and \(j\ne j^*\), \(B'\) generates a new \(K_\mathrm {fs}'\), encrypts it with \(K_\mathrm {master}\), and creates an empty ciphertext file system. Knowing \(K_\mathrm {master}\), the \(\mathsf {Update}_j\) oracle can easily be implemented. In every output, \(\mathsf {Enc}_1(K_\mathrm {master}, K_\mathrm {fs})\) is replaced with an encryption of 0. When \(A'\) uses \(\mathsf {Init}\) for the \(j^*\)-th time, \(B'\) generates a new empty file system by using the encryption oracle of the \(\mathsf {IND}\text {-}\mathsf {CPA}\) experiment to encrypt all blocks. Again, \(B'\) prepends \(\mathsf {Enc}_1(K_\mathrm {master}, 0)\). \(B'\) also saves the current plaintext file system \(F_j\) (which is empty). If \(A'\) uses their access to the \(\mathsf {Update}_j\)-oracle, \(B'\) updates the saved plaintext according to the input to the oracle. It uses the encryption oracle to encrypt added or modified blocks and exchanges them in the saved ciphertext. \(B'\) updates the saved file system \(F_j\) and the state \(s_j\). Upon receiving challenge j, \(F^0\) and \(F^1\) from \(A'\), \(B'\) updates the corresponding plaintext \(F_j\) for both \(F^0\) and \(F^1\) respectively and passes the added and modified blocks of \(\mathsf {Repr}(F^0)\) and \(\mathsf {Repr}(F^1)\) (when compared to \(\mathsf {Repr}(F_j)\)) to the \(\mathsf {LR}\) oracle of the \(\mathsf {IND}\text {-}\mathsf {CPA}\) experiment. It now has an encryption of either the modified blocks in \(F^0\) or in \(F^1\). Since it is required that \((F_j, F^0,F^1)\in R_d\) (i.e. they add, remove, and modify blocks with the same ID), \(B'\) knows which ciphertext blocks it has to add, remove and replace with their new versions in order to generate the correct ciphertext file system, even though it does not know which change was selected by the experiment. \(B'\) prepends \(\mathsf {Enc}_1(K_\mathrm {master}, 0)\) to the generated ciphertext and passes it to \(A'\) along with the updated state. This is a correct simulation of the \(\mathsf {IND}\text {-}\mathsf {aCFA'}\) game. When \(A'\) submits a guess for b, \(B'\) forwards it to the game and thus inherits its success probability. This is a contradiction to the assumption that \(\mathcal {E}_2\) is \(\mathsf {IND}\text {-}\mathsf {CPA}\) secure. \(\square \)
B Integrity of \(\mathsf {CryFS}\)
Theorem 3
(Integrity of \(\mathsf {CryFS}\)
). \({\mathsf {CryFS}}^{\mathcal {E}_1, \mathcal {E}_2} = (\mathsf {Gen},\mathsf {Init},\mathsf {Update},\mathsf {Dec})\) is \(\mathsf {INT}\text {-}\mathsf {FS}\) secure, if \(\mathcal {E}_1\) is \(\mathsf {IND}\text {-}\mathsf {CPA}\) and \(\mathcal {E}_2\) is \(\mathsf {INT}\text {-}\mathsf {CTXT}\) secure.
Proof
Again, we first change \(\mathsf {INT}\text {-}\mathsf {FS}\) to \(\mathsf {INT}\text {-}\mathsf {FS'}\) by replacing \(\mathsf {Enc}_1(K_\mathrm {master},K_\mathrm {fs})\) with \(\mathsf {Enc}_1(K_\mathrm {master},0)\) in the output of all oracles. Assume towards a contradiction that an adversary A with success probability of p against \(\mathsf {INT}\text {-}\mathsf {FS}\) and success probability of \(p'\) against \(\mathsf {INT}\text {-}\mathsf {FS'}\) exists (where \(p = p'+d\) for a positive non-negligible d). This adversary can be used to construct an adversary B with an advantage of \(\frac{d}{2}\) against the \(\mathsf {IND}\text {-}\mathsf {CPA}\) security of \(\mathcal {E}_1\) by using the following reduction: When A uses \(\mathsf {Init}\), B generates \(K_\mathrm {fs}\leftarrow \mathsf {Gen}_2(1^k)\) and uses the \(\mathsf {LR}\) oracle of the \(\mathsf {IND}\text {-}\mathsf {CPA}\) game to get \(c_\mathrm {fs}\) as either an encryption of 0 or of \(K_\mathrm {fs}\). It generates \((C_j, s_j)\) using \(K_\mathrm {fs}\) but replaces the encrypted file system key with \(c_\mathrm {fs}\). B builds the \(\mathsf {Update}_j\) and \(\mathsf {Dec}_j\) oracles using \(K_\mathrm {fs}\) to decrypt and encrypt blocks. Each output contains \(c_\mathrm {fs}\) instead of the encrypted file system key. When \(\mathsf {Dec}_j\) is used, B checks whether decryption was successful for \(C\ne C'\), i.e. whether A was successful. If A was successful, B outputs 1, otherwise it outputs 0. If \(b=0\), this was a perfect simulation of the \(\mathsf {INT}\text {-}\mathsf {FS'}\) game. B has success probability \(\mathrm {Pr}[0\leftarrow B \mid b=0] = 1-p'\). If \(b=1\), this was a perfect simulation of the \(\mathsf {INT}\text {-}\mathsf {FS}\) game. B has success probability \(\mathrm {Pr}[1 \leftarrow B \mid b=1] = p = p'+d\) Together, B has success probability \(\mathrm {Pr}[b \leftarrow B] = \frac{1}{2}(1-p') + \frac{1}{2}(p'+d) = \frac{1}{2} + \frac{d}{2}\). Since d is non-negligible, this is a non-negligible advantage for B against \(\mathsf {IND}\text {-}\mathsf {CPA}\).
Now, assume towards another contradiction that \(A'\) is a successful attacker on \(\mathsf {INT}\text {-}\mathsf {FS'}\). We give a reduction which transforms \(A'\) into a successful attacker \(B'\) on \(\mathsf {INT}\text {-}\mathsf {CTXT}\). The game draws \(K_\mathrm {fs}\leftarrow \mathsf {Gen}_2(1^k)\) and \(B'\) draws \(K_\mathrm {master}\leftarrow \mathsf {Gen}_1(1^k)\). \(B'\) draws a random \(j^* \leftarrow \{1,\dots ,q_\mathsf {Init}\}\). When \(A'\) uses \(\mathsf {Init}\) for the j-th time with \(j\ne j^*\), \(B'\) generates a new independent \(K_\mathrm {fs}'\) and creates a new ciphertext file system with this key. Knowing \(K_\mathrm {fs}'\), implementing \(\mathsf {Update}_j\) and \(\mathsf {Dec}_j\) oracles is straightforward. In every output, \(\mathsf {Enc}_1(K_\mathrm {master}, K_\mathrm {fs})\) gets replaced by \(\mathsf {Enc}_1(K_\mathrm {master}, 0)\). When \(A'\) uses \(\mathsf {Init}\) for the \(j^*\)-th time, \(B'\) creates a new empty file system but uses the encryption oracle provided by \(\mathsf {INT}\text {-}\mathsf {CTXT}\) to encrypt all blocks. It also builds \(\mathsf {Update}_j\) and \(\mathsf {Dec}_j\) but uses the decryption and encryption oracles of the \(\mathsf {INT}\text {-}\mathsf {CTXT}\) game to decrypt and encrypt. Instead of prepending \(\mathsf {Enc}_1(K_\mathrm {master}, K_\mathrm {fs})\), which \(B'\) does not know, it prepends \(\mathsf {Enc}_1(K_\mathrm {master}, 0)\).
Since \(A'\) is successful, there is an oracle query \(\mathsf {Dec}_j(K, C', s_j)\) which decrypts successfully with \(C_j\ne C'\). With non-negligible probability \(\frac{1}{q_\mathsf {Init}}\), this happens for \(j=j^*\), where \(B'\) implemented \(\mathsf {Init}\) using the \(\mathsf {INT}\text {-}\mathsf {CTXT}\) experiment. \(C_j\) and \(C'\) have the same set of block IDs, otherwise \(\mathsf {Dec}_j(K_\mathrm {master}, C', s_j)=\bot \). So there has to be a block in \(C'\) which is different from the corresponding block in \(C_j\), i.e. \(\exists i,c_i,c_i': (i, c_i)\in C_j, (i, c_i')\in C', c_i\ne c_i'\). This block \(c_i'\) was input to the decryption oracle of the \(\mathsf {IND}\text {-}\mathsf {CTXT}\) game when decrypting \(C'\). We argue that \(c_i'\) wins the \(\mathsf {INT}\text {-}\mathsf {CTXT}\) game. First note that \(\mathsf {INT}\text {-}\mathsf {FS'}\) decrypts with \(c_\mathrm {fs}=\mathsf {Enc}_1(K_\mathrm {master}, K_\mathrm {fs})\) from the state, not with the \(c_\mathrm {fs}'=\mathsf {Enc}_1(K_\mathrm {master}, 0)\) passed to the adversary. Therefore \(c_i'\) decrypts successfully with the key from the \(\mathsf {INT}\text {-}\mathsf {CTXT}\) experiment. We now have to argue that \(c_i'\) was never output by the \(\mathsf {INT}\text {-}\mathsf {CTXT}\) encryption oracle. Recall that this oracle is only used for encrypting the output of the j-th query of the \(\mathsf {Init}\) oracle and for the outputs of the \(\mathsf {Update}_j\) oracle. Since \(C'\) decrypts successfully, we know that the plaintext \(((i',b_i'),v_i') := \mathsf {DecBlock}(K, (i, c_i'))\) has ID \(i=i'\) and a version number \(v_i' \ge v_i^s\) where \(v_i^s\) is the version number in the state. All previous \(\mathrm {Update'}_j\) oracle queries for this block ID encrypted a block with version number \(v_i \le v_i^s\), and \(v_i=v_i^s\) only for \(c_i\) where we know \(c_i'\ne c_i\). So we know \(c_i'\) was not output of the \(\mathrm {Update}_j\) oracle. If \((i, c_i')\) was in the j-th output of the \(\mathsf {Init}\) oracle, then \(v_i'=0\). In this case, either block i was never modified, which is a contradiction to \(c_i \ne c_i'\), or block i was modified, which means \(v_i^s>0\) and is a contradiction to successful decryption. Taking everything into account, we know that \(c_i'\) was never output by the \(\mathsf {INT}\text {-}\mathsf {CTXT}\) encryption oracle and thus wins the game. This is a contradiction to the assumed security of \(\mathcal {E}_2\). \(\square \)
C Achieving Multi-user-Compatibility
\(\mathsf {CryFS}\) provides confidentiality, integrity and fast file system operations in a single-user context. However, the design presented so far does not work well when used by multiple users for multiple reasons. For example, we cannot distinguish whether an integrity violation was caused by an attacker rolling back a block, or by a second client synchronising modifications on top of an outdated version. We resolve these problems by introducing a number of measures, which ensure that \(\mathsf {CryFS}\) can be used with multiple users without integrity guarantees while maintaining integrity in the single-user setting.
First, in addition to having a pointer from the directory block to the root of a file, we also add a pointer from each file root node back to the directory it belongs to. That is, the whole directory structure is stored twice, once bottom-up in these pointers and once top-down through the file system tree. Using this, we can recover from a race condition where two users both add a different file to the same directory by periodically scanning for “dangling” pointers and reintegrate the corresponding files into the directory block.
Second, we extend the header of each block to also contain a unique client ID of the client who last modified the block along with the version counter. Further, each client saves the newest version for every block ID and client combination, and remembers the last updating client. Now, when a client reads a block that still has the same client ID as in his local state, the version number is checked to be non-decreasing otherwise it has to be increasing.
Third, instead of explicitly flagging deleted blocks in the local state, we set their last updating client ID to \(\bot \). This allows clients to reintroduce deleted blocks as long as they increase the version number. Last, we allow to disable the check for missing blocks since there is no mechanism for a client to communicate, that he deleted a block, which will cause other clients to think that an attacker has deleted it.