The simplest way to use the Crypt Filesystem is to mount a directory on the local hard disk (e.g., "/crypt"), which contains encrypted files, to a mount point (e.g., "/mnt"). After setting a key, the encrypted files in "/crypt" will be visible (decrypted) in "/mnt". The key can be set by the user-level program "cryptfs_setkey": this program creates a new shell and attaches the key to it. Whenever this shell accesses files of the Crypt Filesystem (i.e. in /mnt), all data transferred to/retrieved from disk will be automatically encrypted/decrypted. This special shell passes on its ability to access the key to its child processes which are created by the Unix process creation mechanism, i.e. commands which are typed in the shell will be able to access files of the Crypt Filesystem. The fact that the key is bound to processes rather than, for example, login names, provides better protection for the encrypted data: Even if a hacker manages to break into the Unix system, it is difficult to compromise the Crypt Filesystem as well. This seems possible only if an attacker manages to gain root privileges, which will be discussed in more detail when the use of NFS in combination with the Crypt Filesystem will be described.
Encryption and decryption of the files is transparent to the user: Once the key is set, all Unix programs work as used, because the Crypt Filesystem takes care of encryption/decryption automatically.
First, the files can be stored on the server in encrypted form and made accessible to the client using NFS. The corresponding directory can then be mounted using the Crypt Filesystem to obtain a directory on the client which contains the files in decrypted form. The mount operation is done the same way as if the NFS-directory was a directory on the local hard disk of the client which contains encrypted files. Using this method, no encrypt- and decrypt-operations have to be performed on the server, which also means that the key is not needed on the server. As the data encrypted on the server, it is safe even if an attacker manages to break into it. As the key is not present at the server, the best possible security is achieved on the server side. ``Best possible'' means that the only way of compromising the system is to break the encryption system (i.e., DES) itself. Even the knowledge of the root password for the server is no use for an attacker if the key for encryption is not known. There is also no need to worry about someone gaining access to the data on its way through the network, because only encrypted data is transmitted, so on the net, the same level of security is achieved as on the server. On the client side, the Crypt Filesystem takes care of decrypting the files which are imported via NFS and makes them transparently accessible the same way as if the files were stored in encrypted form on the local hard disk. As the key has to be stored somewhere in the client's operating system (i.e., within the kernel data structures), care has to be taken in order to prevent an attacker from acquiring superuser privileges. In this case, it cannot be prevented that the attacker finds a way to sneak the key out of the kernel's data structures or to read the uncrypted data directly out of the user adress space of a process which was provided with the key. Therefore, the root password has to be chosen carefully according to well-known rules for Unix passwords, and it has to be kept as secret as the key for the encryption system.
The second method to use NFS in combination with the Crypt Filesystem makes it possible to protect data which is not encrypted on the file server. One way to make sure that only encrypted data is sent over the net to the client would be to make an encrypted copy of every file which is to be exported. With these encrypted copies, the first method (described above) can be used to make the data accessible to the client. To avoid the inconvenience of having to create a copy of the whole directory tree, it is possible to create a "virtual encrypted copy" of the directory tree which is to be exported with the Crypt Filesystem. This is done by mounting the corresponding directory in "inverse mode", creating a directory which is identical to the mounted directory, except that all the files are encrypted. This directory can be exported via NFS and decrypted again on the client to get files which are identical to the ones stored on the server.
Although this method is convenient in order to export files without having to create encrypted files on the server's hard disk, it should be pointed out that there are two major disadvantages: First, the server is vulnerable for an attacker who manages to break into the Unix system, as the files are stored on the hard disk. To compare the situation of an attacker with root privileges on the client (no matter whether the first or the second method is used) to the situation of an attacker with the same privileges on the server when the second method is used, it can be stated that it is still tricky for a "superuser" on the client to find out the key or gain access to the data directly, whereas it is obviously trivial to read the files which are stored without encryption on the server. Especially, to compromise the Crypt Filesystem on the client is only possible while there exist processes which "know" the key. (Therefore, it is recommended to have these "privileged processes" only as long as they are really needed.)
The second disadvantage is that the server has to do the encryption/decryption of the data for every read or write access. As these are cpu intensive operations, performance of the server might decrease. In general, computations should be shifted from the central servers to the local clients whenever possible in order to optimize average response time, because several people contribute to the load of a single file server, whereas there is usually only one person logged on to a client workstation. This general goal is not respected by the method in question. Therefore, it should be evaluated if the convenience of the second method is worth the risk that the work of all those who are dependent on the file server is slowed down. In the long term, it might pay off to generate crypted versions of the files on the server and to export them directly.
The reason why a separate module is used for the crypt routines is that this makes it possible to have a choice of several different crypt methods by providing different versions of the "crypt" module. For example, different users might have different requirements in regard to the level of security that is necessary and the loss in performance of the file system that is acceptable. Usually, an encryption method which provides better security takes also longer to compute for a given amount of data.
The different "crypt" modules must have a common interface, as their routines are all called by the same "cryptfs" module. This interface is given in the header file "crypt.h". It should be feasible to adapt other encryption algorithms which are suitable for the Crypt-FS to this interface and compiling "crypt" modules for these algorithms, being flexible in regard to encryption algorithms which may evolve in the future. Being "suitable" means that the method has to use a symmetric key and that it must be possible to encrypt/decrypt a part of a file without the need to know or to change certain parts of the rest of the file.
The main part of the work is done by the vnode-operations. All operations which have nothing to do with encryption/decryption are passed to the underlying filesystem. Decryption/Encryption is performed by the read- and the write-operations.
As the crypt-routines operate on data blocks of a fixed length (eight bytes), encrypted files are enlarged by one block length. This makes it possible to deal with the last bytes of a file, which do not fill a whole block, and provides a solution to the problem of getting the "real" length of the uncrypted file. Of course, this change in the length of the files has to be taken into account in certain operations (read(), write(), getattr()) to avoid inconsistencies. Furthermore, the operations read and write have to make sure that whole blocks are being used even if this is not the case for the user request, as parts of blocks cannot by decrypted/encrypted.