Playing with ZFS Encryption In Oracle Solaris 11.1

Published July 2014
by Alexandre Borges Oracle ACE

Part 5 of a series that describes the key features of ZFS in Oracle Solaris 11.1 and provides step-by-step procedures explaining how to use them. This article focuses on different methods for encrypting and decrypting files, file systems, and pools.


Oracle Solaris 11 supports encryption on ZFS in a native way to protect critical data without depending on external programs, and it is integrated with the Oracle Solaris Cryptographic Framework, which in turn makes encryption easier and faster by providing several symmetric and asymmetric algorithms for encrypting files and entire file systems. Moreover, when ZFS encryption is enabled on a newly created file system, encryption is automatically inherited by any descendant file systems, For added flexibility, encrypted file systems can live with unencrypted file systems in the same pool.

The following are the supported symmetric algorithms and their respective mechanisms:



root@solaris11-1:~# encrypt -l
Algorithm       Keysize:  Min   Max (bits)
------------------------------------------
aes                       128   256
arcfour                     8  2048
des                        64    64
3des                      128   192

root@solaris11-1:~# cryptoadm list -m provider=aes
aes: CKM_AES_ECB,CKM_AES_CBC,CKM_AES_CTR,CKM_AES_CCM,CKM_AES_GCM,CKM_AES_GMAC,
CKM_AES_CFB128,CKM_AES_XTS,CKM_AES_XCBC_MAC
root@solaris11-1:~#

From the available options, the 128-bit AES CCM mode is the default. In case we are using deduplication on some file systems, be aware that a CCM mode is required when combining both encryption and deduplication.

There are several ways to use ZFS encryption on a system running Oracle Solaris 11. Let's explore them.

First Way

We can encrypt a single file or a whole file system using the same algorithms. The following shows an example for a single file:

root@solaris11-2:/tmp# cp /etc/hosts /tmp/

root@solaris11-2:/tmp# cd /tmp/
root@solaris11-2:/tmp# encrypt -a aes -i /tmp/hosts -o /tmp/hosts.aes
Enter passphrase:
Re-enter passphrase:

root@solaris11-2:/tmp# file hosts*
hosts:       ascii text
hosts.aes:   data

I entered the password oracle123! and everything worked fine. As we can see, the file was encrypted.

If we want to decrypt the file, we can use the following command:



root@solaris11-2:/tmp# decrypt -a aes -i /tmp/hosts.aes -o /tmp/hosts.decrypted
Enter passphrase:

root@solaris11-2:/tmp# ile hosts*
hosts:           ascii text
hosts.aes:       data
hosts.decrypted: ascii text

root@solaris11-2:/tmp# more hosts.decrypted
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# Internet host table
#
::1 solaris11-1 localhost
127.0.0.1 solaris11-1 solaris11.example.com localhost loghost
192.168.1.105 solaris11-1.example.com solaris11-1
192.168.1.102 solaris11-2.example.com solaris11-2
192.168.1.250 freenas.example.com freenas
root@solaris11-1:/tmp#

That was easy. We could do something similar to the following to encrypt the entire file system:



root@solaris11-2:~# zpool create pool_encr c8t3d0
root@solaris11-2:~# fs create -o encryption=on pool_encr/fs_encr_1
Enter passphrase for 'pool_encr/fs_encr_1':
Enter again:
root@solaris11-2:~#

The default form of ZFS encryption is to prompt for a passphrase, as indicated in the example above.

I entered the same passphrase (oracle123!). If we create a new descendant file system, the passphrase is inherited from the parent file system.

The first thing we must be aware of is that it's not possible to decrypt a file system as we did for a single file. Another difference is we had to enter the passphrase in an interactive way. There's no problem doing that for some file systems, but entering the passphrase interactively can be real problem when deploying in big environments.

A better alternative would be to store the passphrase outside of our computer:



root@solaris11-1:/# zpool destroy pool_encr          
root@solaris11-1:/# zpool create pool_encr c8t3d0
root@solaris11-1:/# echo "oracle123" > /media/ORA_PENDRIV/oracle_encryption_key
root@solaris11-1:/# more /media/ORA_PENDRIV/oracle_encryption_key
oracle123
root@solaris11-1:/# zfs create -o encryption=on \
-o keysource=passphrase,file:///media/ORA_PENDRIV/oracle_encryption_key pool_encr/fs_encr_2

In this case, we also need to protect our removable device (pen drive), because the passphrase is there. Note that the file system is mounted during booting only if the system has access to the removable device, but the lack of any encryption key does not prevent the system from booting.

Important: As a last reminder, Oracle Solaris 11 cannot decrypt an encrypted file system the way it can decrypt an encrypted single file.

Second Way

As an alternative, we can use a wrapping key. A wrapping key is used to encrypt the real (symmetric) key that we would use to perform the encryption. In other words, when using a wrapping key, we store the symmetric key in the keystore, encrypt it using the wrapping key and then—when we need the symmetric key for encrypting a file system—the key is accessed and decrypted by using the wrapping key in a noninteractive mode.

The wrapping key could be a passphrase (which is similar to a password) or a raw key, and it's necessary only when the file system is initially mounted.

Different from the first method, for providing further protection, we could store the wrapping key inside the Oracle Solaris Cryptographic Framework, which is a kind of keystore encrypted by a softtoken. This keystore is protected by an initial passphrase (changeme) that we have to alter:



root@solaris11-2:/# pktool setpin
Enter token passphrase: changeme
Create new passphrase: borges123
Re-enter new passphrase: borges123
Passphrase changed.
root@solaris11-2:/#  

The available tokens can be viewed by executing the following command:



root@solaris11-2:~# pktool tokens
Flags: L=Login required  I=Initialized  X=User PIN expired  S=SO PIN expired
Slot ID  Slot Name                    Token Name                        Flags     
-------  ---------                    ----------                        -----     
1        Sun Crypto Softtoken         Sun Software PKCS#11 softtoken    LI     

Let's create and then list some keys:



root@solaris11-2:~# pktool genkey keytype=aes keylen=192 label=otn1
Enter PIN for Sun Software PKCS#11 softtoken: borges123

root@solaris11-2:~# pktool genkey keytype=aes keylen=256 label=otn2
Enter PIN for Sun Software PKCS#11 softtoken:

root@solaris11-2:~# pktool list objtype=key
Enter PIN for Sun Software PKCS#11 softtoken:
Found 2 symmetric keys.
Key #1 - AES:  otn1 (192 bits)
Key #2 - AES:  otn2 (256 bits)

As you can see, the first pktool genkey command created a new key named otn1 using the AES algorithm with 192 bits, and the second pktool genkey command created a key named otn2 using the AES algorithm with 256 bits.

We can repeat the same procedure to encrypt a file, but using the Oracle Solaris Cryptographic Framework this time:



root@solaris11-2:~# cp /etc/hosts /tmp/
root@solaris11-2:~# cd /tmp/
root@solaris11-2:/tmp# encrypt -a aes -K otn2 -i /tmp/hosts -o /tmp/hosts.aes256
Enter PIN for Sun Software PKCS#11 softtoken: borges123


root@solaris11-2:/tmp# file /tmp/hosts*
/tmp/hosts:         ascii text
/tmp/hosts.aes256:  data

We've done it! Nobody knows what the real password is, only that it's stored in the Oracle Solaris 11 keystore. Encrypting the example file (a copy of /etc/hosts) was done using the passphrase (borges123). That's the nice thing: we don’t know the symmetric key itself because we need to enter only the PIN (passphrase) of the keystore.

From here, we could decrypt the file using the same method:

root@solaris11-2:/tmp# decrypt -a aes -K otn2 -i /tmp/hosts.aes256 \

-o /tmp/hosts.decrypted
Enter PIN for Sun Software PKCS#11 softtoken:

root@solaris11-2:/tmp# file /tmp/host*
/tmp/hosts:            ascii text
/tmp/hosts.aes256:     data
/tmp/hosts.decrypted:  ascii text

Before proceeding with file system encryption, it's important to say that the key could be stored outside of the keystore. In this case, the key administration is our responsibility:

root@solaris11-2:/tmp# pktool genkey keystore=file outkey=/mykeys/otn3 \

keytype=aes keylen=256
root@solaris11-2:/tmp# ls -al /mykeys/otn3
-r--------   1 root     root          32 Dec  9 19:14 /mykeys/otn3
root@solaris11-2:/tmp# file /mykeys/otn3
/mykeys/otn3:    data
root@solaris11-2:/tmp# pktool list objtype=key
Enter PIN for Sun Software PKCS#11 softtoken: borges123
Found 2 symmetric keys.
Key #1 - AES:  otn1 (192 bits)
Key #2 - AES:  otn2 (256 bits)
root@solaris11-2:/tmp#

As we can see from the output, the key isn't stored in the Oracle Solaris 11 keystore (softtoken).

To encrypt an entire file system using the PKCS#11 method (softtoken), do the following:



root@solaris11-2:~# zpool create softtoken_pool c8t4d0

root@solaris11-2:~# zfs create -o encryption=aes-256-ccm \
-o keysource=raw,pkcs11:object=otn2 softtoken_pool/fs_softtoken_1
Enter PKCS#11 token PIN for 'softtoken_pool/fs_softtoken_1': borges123

root@solaris11-2:~# zfs list -r softtoken_pool              
NAME                            USED  AVAIL  REFER  MOUNTPOINT
softtoken_pool                 140K  3.91G    32K  /softtoken_pool
softtoken_pool/fs_softtoken_1   33K  3.91G    33K  /softtoken_pool/fs_softtoken_1

Cool. The symmetric key is stored inside the PKCS#11 keystore. Then, the zfs create command used it to create and encrypt the softtoken_pool/fs_softtoken_1 file system.

It's a nice exercise to collect further information about the file system encryption:



root@solaris11-2:~# zfs get encryption softtoken_pool/fs_softtoken_1
NAME                            PROPERTY   VALUE        SOURCE
softtoken_pool/fs_softtoken_1  encryption  aes-256-ccm  local

root@solaris11-2:~# zfs get keysource softtoken_pool/fs_softtoken_1
NAME                            PROPERTY  VALUE                   SOURCE
softtoken_pool/fs_softtoken_1  keysource  raw,pkcs11:object=otn2  local

To make a new file system, but using another key, is straightforward:



root@solaris11-2:~# zfs create -o encryption=aes-192-ccm \
-o keysource=raw,pkcs11:object=otn1 softtoken_pool/fs_softtoken_2
Enter PKCS#11 token PIN for 'softtoken_pool/fs_softtoken_2': borges123

root@solaris11-2:~# zfs get encryption softtoken_pool/fs_softtoken_2
NAME                            PROPERTY   VALUE        SOURCE
softtoken_pool/fs_softtoken_2  encryption  aes-192-ccm  local

root@solaris11-2:~# zfs get keysource softtoken_pool/fs_softtoken_2
NAME                            PROPERTY  VALUE                   SOURCE
softtoken_pool/fs_softtoken_2  keysource  raw,pkcs11:object=otn1  local

root@solaris11-2:~# zfs list -r softtoken_pool
NAME                            USED  AVAIL  REFER  MOUNTPOINT
softtoken_pool                 194K  3.91G    33K  /softtoken_pool
softtoken_pool/fs_softtoken_1   33K  3.91G    33K  /softtoken_pool/fs_softtoken_1
softtoken_pool/fs_softtoken_2   33K  3.91G    33K  /softtoken_pool/fs_softtoken_2

Finally, it's possible to encrypt the entire pool (not just some of the file systems):



root@solaris11-2:~# zpool create -o encryption=on \
-o keysource=raw,pkcs11:object=otn1 softtoken_pool_2 c8t5d0
Enter PKCS#11 token PIN for 'softtoken_pool_2': borges123

root@solaris11-2:~# zfs create softtoken_pool_2/fs_softtoken_3
root@solaris11-2:~# zfs create softtoken_pool_2/fs_softtoken_4

This is very interesting: the encrypted pool was created and the pin number (that is, the passphrase for the keystore) was required, but when we created the descendant file systems (fs_softtoken_3 and fs_softtoken_4) no passphrase is prompted for because descendant file systems inherit the parent file system’s encryption key. To verify this, run the following command:



root@solaris11-2:~# zfs get encryption,keysource softtoken_pool_2/fs_softtoken_3 \
softtoken_pool_2/fs_softtoken_3
NAME                             PROPERTY    VALUE                   SOURCE
softtoken_pool_2/fs_softtoken_3  encryption  on                      inherited from softtoken_pool_2
softtoken_pool_2/fs_softtoken_3  keysource   raw,pkcs11:object=otn1  inherited from softtoken_pool_2
softtoken_pool_2/fs_softtoken_3  encryption  on                      inherited from softtoken_pool_2
softtoken_pool_2/fs_softtoken_3  keysource   raw,pkcs11:object=otn1  inherited from softtoken_pool_2

Amazing. Exactly as we had predicted.

See Also

Here are some links to other things I've written:

And here are some Oracle Solaris 11 resources:

About the Author

Alexandre Borges is an Oracle ACE and who worked as an employee and contracted instructor at Sun Microsystems from 2001 to 2010 teaching Oracle Solaris, Oracle Solaris Cluster, Oracle Solaris security, Java EE, Sun hardware, and MySQL courses. Nowadays, he teaches classes for Symantec, Oracle partners, Hitachi, and EC-Council, and he teaches several very specialized classes about information security. In addition, he is a regular writer and columnist at Linux Magazine Brazil.

Revision 1.0, 07/15/2014