sys_unlink { /* system call service routine */
vfs_unlink { /* VFS method */
call nc_permission()
if not permitted: return error
nc_unlink { /* NCryptfs method */
call nc_perm_preop() /* code we added */
vfs_unlink { /* VFS method */
call ext2_permission()
if not permitted: return error
call ext2_unlink() /* EXT2 method */
} /* end of inner vfs_unlink */
call nc_perm_fixup() /* code we added */
} /* end of nc_unlink */
} /* end of outer vfs_unlink */
} /* end of sys_unlink */
The VFS operation (e.g., vfs_unlink) checks the permission
using the nc_permission function. If the permission check
succeeds, the corresponding NCryptfs-specific operation is called
(e.g., nc_unlink). NCryptfs locates the lower-level object
and again calls the VFS operation. The VFS operation checks
permissions for the lower-level inode before calling the lower-level
operation. This control flow means that we can not actually intercept
the lower-level permission call. Instead, we change
current->fsuid to the owner of the lower-level object before
the operation is performed and restore it afterward, which is done in
nc_perm_preop and nc_perm_fixup, respectively.
We change only the permissions of the current task, and the process
can not perform any additional operations until we restore the
current->fsuid and return from the NCryptfs function. This
ensures that only one lower file system operation can be performed
between nc_perm_preop and nc_perm_fixup.
Linux 2.6 will have Linux Security Modules (LSMs) that allow the
interception of many security operations [29].
Unfortunately, the LSM framework is not sufficient to bypass
lower-level permissions either. Their VFS calls the
file-system-specific permission operation first. The LSM
permissions operation is called only if the file-system-specific
operation succeeds. The LSM operation can allow or deny access only
to objects that the file system has already permitted. A better
solution is to consult the file-system-specific permission
operation. This result should be passed to the LSM module which can
make the final decision, possibly based on the file-system-specific
result.
Cryptography
To ensure data confidentiality, NCryptfs uses strong cryptography
algorithms (e.g., Blowfish or AES in CFB mode). File data and file names
are handled in two different ways.
Data is encrypted one page at a time, using an initialization vector
(IV) specified along with the encryption key XORed with the
inode number and page number. For security, ideally the entire file
would be encrypted at once, but then random access would be
prohibitively expensive; to access the nth byte of data, n bytes
would need to be decrypted, and any write would require re-encryption
of the entire file. For optimal performance, each byte would be
encrypted individually, but without data interdependence, encryption
becomes significantly less secure
[24].
File names are encrypted with the IV XORed with the inode
number of the directory, but the output may contain characters that
are not valid UNIX pathnames (i.e., / and NULL). To
rectify this problem, the result is base-64 encoded before being
passed to the lower-level file system. This reduces the maximum path
length by 25%. A checksum is stored at the beginning of the
encrypted file name for two reasons. First, if a file name is not
encrypted with the correct key, then this checksum will prevent it
from appearing in NCryptfs. Second, since CFB mode is used, if two
files have a common prefix, then they will have a common
encrypted prefix. Since it is unlikely that these two files will have
the same checksum, prefixing their names with the checksum will
prevent them from having the same prefix in the ciphertext. Finally,
the directory entries "." and ".." are not
encrypted to preserve the directory structure on the lower-level file
system.
| Feature | CFS | TCFS | BestCrypt | Cryptfs | NCryptfs | |
| 1 | No keys stored on disk | Yes | a | Yes | Yes | Yes |
| 2 | Keys protected from swap devices | Yes b | Yes | |||
| 3 | Reveals no directory structure | Yes | ||||
| 4 | Multiple concurrent users | Yesc | Yes | Yes | Yes | |
| 5 | Users do not need root intervention | Yes | Yes | |||
| 6 | Multiple ciphers | Yes | Yes | Yes | Yes | |
| 7 | Automatic cipher loading | Yes | Yes | |||
| 8 | Separate permissions per user | Yes | ||||
| 9 | Group support - UNIX GID | Yes | Yes | |||
| 10 | Group support - ad-hoc | Yes | ||||
| 11 | Challenge-response authentication | Yes | ||||
| 12 | Data integrity assurance | Yes | ||||
| 13 | Per-file encryption flag | Yes | ||||
| 14 | Threshold secret sharing | Yes | ||||
| 15 | Key timeouts | Yes | Yes | |||
| 16 | User-space timeout callback | Yes | ||||
| 17 | Process sleep/wakeup on key timeout | Yes | ||||
| 18 | Implementation technique | NFS server | NFS client | loop device | stackable | stackable |
| 19 | No. of systems available | any UNIX | 3d | 2 | 3 | 1e |
| 20 | Additional Blowfish LOC (Lines Of | 33 | 109 | 99 | 0 | 76 |
| Code, excludes cipher implementation) | ||||||
| 21 | Total core LOC | 5258 | 14731 | 3526 | 4943 | 6537 |
| Configuration | CFS | TCFS | BC | NC |
| Elapsed Time - NULL | 5.7 | 16.9 | 1.5 | 2.2 |
| Elapsed Time - BF | 8.4 | 28.4 | 1.7 | 4.5 |
| System Time - NULL | 25.5 | 50.3 | 0.7 | 4.6 |
| System Time - BF | 39.5 | 93.7 | 1.8 | 17.0 |
| Configuration | CFS | TCFS | BC | NC |
| Elapsed Time - NULL | 119 | 106 | 101 | 56 |
| Elapsed Time - BF | 123 | 106 | 127 | 59 |
| System Time - NULL | 553 | 50 | 95 | 51 |
| System Time - BF | 821 | 118 | 280 | 156 |