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 |