Encryption support for lofi(7D). The lofi(7D) driver will gain the ability to encrypt/decrypt the raw blocks. This provides parity with Linux and MacOS X which both have encryption support in their equivalent to the lofi(7D) driver. The administration command lofiadm(7D) is extended to support requesting encryption and setting the key. The default output of lofiadm, with no arguments, shows which lofi devices map to which underlying files, this output will gain an additional column to indicate what options are enabled for that device mapping, the value "Encrypted" will be used for encryption. The parsable output where a file or device is given does not change. Crypto algorithm support ------------------------ It is not desirable for lofi(7d) to have the encrypted data to take up more space than the clear text data would. For this reason it is not possible to use a separate digest/hmac algorithm as is commonly done in network protocols, eg aes for encryption and hmac-sha1 for integrity protection of the cipher text. The encrypted block device support on other platforms does not provide any integrity protection support. This means that it is vulnerable to cipher text manipulation. While this is not trivial to do in a way that is advantageous to an attacked it is certainly possible and not just theoretical, and it does at least present a denial of service attack on the data. To ensure we have integrity protection lofi(7D) a future case will introduce a cipher suite that provides a non expanding ciphertext output that has a builtin integrity protection. We expect that that mode will be AES-XEX but are still researching at this time and want to ensure that XEX really does have the desired properties. Initially however we will be using AES-CBC and like other platforms we won't have the integrity protection. Note that no upgrade will be possible between AES-CBC and AES-XEX (or what ever is selected). DES3-CBC and BLOWFISH-CBC ciphers will also be provided. AES-CBC will be the current default. Where an IV is needed for AES-CBC, DES3-CBC, or BLOWFISH-CBC, it is derived from the data block number of the block being encrypted or decrypted. The data block number will be padded on the left with zeros to the appropriate IV length, and then encrypted with AES_ECB, DES3_ECB, or BLOWFISH_ECB respectively. The result is used as the IV for the CBC encryption and decryption the data block. An optimization is proposed specifically for CBC encryption. A dummy block of IV length containing the block number padded on the right is prepended to the data block. This "extended size" block is CBC encrypted with an IV of all zeros. After encryption, the leading dummy block is discarded and the remaining block is the encrypted data. This optimization does not apply to decryption, so two crypto calls are still needed: one to encrypt the block number to compute the IV, and then the decrypt of the block itself with the computed IV. If an incorrect key value is given then the lofiadm mapping will still succeed but any filesystem layered on it will fail to mount (since the data on the device will not appear to be a filesystem). Disk format ----------- Additional space is needed for lofi(7D) encryption support. This space is used to store metadata information pertaining to encryption algorithms used, salt data, versioning, actual start of data area, and other related information. Refer to diagram for details of the contents of this metadata section. (See also PSARC/2007/569 lofi compression support.) The on-disk format is whatever format is selected via newfs/mkfs, but prepended with this metadata section. The filesystem structure is otherwise unchanged. The metadata section is always in the clear, while the rest of the lofi file image data is encrypted. For encrypted lofi images, an encrypt op is interposed immediately before each block is written to physical io, and a decrypt op is called immediate after a reading a each block from physical io so the data can be interpreted correctly. Each block is individually encrypted or decrypted since the block number is used to seed the crypto ops. The initial implementation of encryption support reserves a fixed area in the lofi for future metadata information. The size of this area is expected to vary in length, but the actual start of the lofi image data is always stored in the metadata section at initialization. The contents of the metadata section are TBD pending whether encrypted lofi images should follow the LUKS specification format or some other format. The following minimum fields must be included in the initial implementation to ensure backward and forward compatibility with future updates: - 6 byte magic: hex "CFLOFI" (0x43464c4f4649) - 2 byte version: 0 initially - 4 byte block number: 16 The block number, 0 based, locates the actual start of the encrypted lofi image data. The left side of the metadata diagram shows the content that may be added in future cases. The right side of the diagram shows what is required in the 0th version. Key Management -------------- The encryption key can be specified in one of five different ways: 1) Prompt for a passphrase. This is the default if encryption is requested but no key information is given. The passphrase is used to generate a symmetric encryption key using PKCS#5 PBKD2. The passphrase must be a minimum of 8 bytes. No salt is used in the initial implementation. Future cases may add that a salt and number of iterations option is specified during initialization and saved in the metadata section. This interface is Committed Private. Changes to this method will be incompatible with existing lofi images. 2) A "raw" key of the appropriate length in a file. 3) A reference to a PKCS#11 symmetric key object If the key is in a "userland" PKCS#11 token such as that provided by pkcs11_softtoken, or a 3rd party smartcard device, and it is extractable it will be extracted in wrapped form and passed to lofi(7D). If the key is not extractable and we can't get the raw key attributes then we will not be able to use this key. If the key reference is for a kernel provided PKCS#11 device it will be used by reference only and not extracted. In this case the kernel crypto provider must support AES-CBC, DES3-CBC, or BLOWFISH-CBC. This is the same general model as ksslcfg(1M) uses for providing RSA keys to kssl. The genkey subcommand of pktool(1) can be used to generate these keys. 4) A wrapped key in a file. The key is unwrapped using an RSA key in a PKCS#11 token. This is needed to support smartcard based operations where the smartcard is not able to store symmetric keys; either as a local policy choice or because the token is unable to do so. The smartcard applet used by the ISV Active Identity falls in to this category. It is also desirable to provide this method is a way to do key escrow without the need to escrow the symmetric keys, instead the RSA encryption key is escrowed by the card management system (note none of this card management system or PKCS#11 access to smartcards is provided by this case or is it available in Solaris today, 3rd party products are required). 5) If the -e argument is given an ephemeral key is generated internally. The key is never given to the administrator. This means that after the device is detached from lofi (or the system reboots/crashes) the data placed on that device is not recoverable. This is intended only for encrypted swap. Encrypted Swap -------------- Support for encrypted swap devices by using lofi(7D) layered over the physical swap device/file. This support is only available when swap files are specified in vfstab(4) and is enabled by setting a mount option of "encrypted". Note if this support is used then the swap(1M) command will show a lofi device rather than the underlying swap file or device. This uses an ephemeral key as described above. If using encrypted swap a separate dedicated dump device must be used since dumps on the encrypted partition are not supported - since dumps on lofi devices are not supported regardless of encryption. Once the device is in use by lofi(7D) it can not be used to dump on, lofi(7d) enforces this. This is not a perfect encrypted swap implementation but the exposed interface is intended to be stable and a possible future case may choose to implement encrypted swap using a method other than lofi(7D). Interaction with encrypted swap and suspend to disk --------------------------------------------------- We could in theory store the key in the TPM for machines that have one, but that is better left for a future case were we do fully encrypted boot support with ZFS and when we actually have support for using the TPM as a keystore. Microsoft Vista has this capability today with BitLocker. Suspend to RAM on x86 is not impacted by this case. Suspend to disk is impacted from a security view point both for encrypted swap and encrypted "disks" since we don't want to ever write the keys to disk in an unwrapped form. Ideally we should be "invalidating" the keys when we prepare for suspend or wrapping them and having some sort of password used on resume to unwrap them. That might require a quite extensive framework and is beyond the scope of this case. The lofi module currently returns DDI_FAILURE if an attempt to detach it is made and mappings exist. We believe this may be sufficient to ensure we don't suspend to disk with encrypted lofi devices active. This will be tested before integration and if it is not sufficient we will find a suitable method to ensure that if encrypted lofi mappings exist the suspend to disk will fail. Interaction with lofi compression --------------------------------- The compression and encryption features of lofi are mutually exclusive. On the command line, encryption options and compressions options can not be specified together. Further, encrypting a compressed lofi image or compressing an encrypted lofi image is not allowed. Lofi encryption and compression each write metadata at the beginning of the lofi image that is specific to that feature. The content of the metadata is used to determine if the lofi image is encrypted or compressed, or neither. Once the type is determined, the driver enforces mutually exclusivitity between these features internally too. Command Syntax -------------- See materials/lofiadm.1m Example Usage ------------- 1. Prompt for passphrase and derive key: # lofiadm -c aes-256-cbc -a /dev/dsk/c0t0d0s7 Enter passphrase: 2. Raw AES key in file: # lofiadm -c aes-256-cbc -a /home/jru/private -k /rmdisk/jru/key 3. Key called 'mykey' in PKCS#11 token 'Sun Software PKCS#11 softtoken': # lofiadm -c aes-256-cbc -a /home/jru/private \ -T 'Sun Software PKCS#11 softtoken':::mykey Enter token PIN: 4. Key called 'finance' in any any available PKCS#11 token: # lofiadm -c aes-256-cbc -a /data/finance -T :::finance Enter token PIN: 5. AES key wrapped with PKCS#11 token object named 'ekey' # lofiadm -c aes-256-cbc -a /data/projectb -T :::ekey \ -k /rmdisk/mykeys/projectb Enter token PIN: Future work ----------- A future case will provide a PAM module and suitable configuration store so that users can have encrypted filesystems provided by lofi(7D) and UFS/PCFS mounted when they login. A future case will also provide users a way to mount and umount their encrypted images on demand using a GUI tool. The above two future projects are deliberately not part of this case so that the interface they present to the user can be compatible with the future ZFS crypto support. They may well deliver before ZFS crypto but at this time they are not sufficiently well specified to support ZFS crypto and lofi(7D) crypto. It is believed that this case is sufficiently complete and useful even if the above mentioned future work was never delivered. References ---------- 1. materials/lofi-crypto-lofiadm.1m 2. materials/lofi-crypto-lofi.7d 3. materials/lofi-disk-fmt.jpg 4. PSARC/2007/569 lofi compression