Solaris Loopback Crypto & Compression
Posted on April 1, 2009
Linux has always been in love with its loopback trickery for implementing compression and cryptography but a cry has gone out for similar capabilities in Solaris and those requests have been answered. The Solaris Loopback File driver (aka: LOFI) has supported compression for some time now, and as of snv_105 encryption has been added as well.
LOFI Basics
If your unfamiliar with LOFI, lets catch you up. LOFI is used for accessing a file as a block device. The most common use is for loopback mounting ISO images. You simply create a loopback device for the file and then mount the image (CD/DVD’s are typically the HighSiera FileSystem: “hsfs” as opposed to the iso9960 filesystem type on Linux):
root@quadra ISO$ lofiadm -d /dev/lofi/1 root@quadra ISO$ root@quadra ISO$ lofiadm Block Device File Options root@quadra ISO$ lofiadm -a dfly-gui-2.2.0_REL.iso /dev/lofi/1 root@quadra ISO$ lofiadm Block Device File Options /dev/lofi/1 /home/benr/ISO/dfly-gui-2.2.0_REL.iso - root@quadra ISO$ mount -F hsfs /dev/lofi/1 /a root@quadra ISO$ cd /a root@quadra a$ ls COPYRIGHT autorun autorun.pif boot.catalog etc kernel.smp root sys var README autorun.bat bin dev etc.hdd mnt rr_moved tmp README.USB autorun.inf boot dflybsd.ico index.html proc sbin usr root@quadra a$ cd / root@quadra /$ umount /a root@quadra /$ lofiadm -d /dev/lofi/1 root@quadra /$ lofiadm Block Device File Options root@quadra /$
Another way to LOFI is to create an empty file, create a loopback device for it and then to treat it like a disk, creating a filesystem on it and such. This has its usefulness but can be kinda boring.
root@quadra ~$ mkfile 100m lumpospace root@quadra ~$ lofiadm -a /home/benr/lumpospace /dev/lofi/1 root@quadra ~$ newfs /dev/lofi/1 newfs: construct a new file system /dev/rlofi/1: (y/n)? y /dev/rlofi/1: 204600 sectors in 341 cylinders of 1 tracks, 600 sectors 99.9MB in 22 cyl groups (16 c/g, 4.69MB/g, 2240 i/g) super-block backups (for fsck -F ufs -o b=#) at: 32, 9632, 19232, 28832, 38432, 48032, 57632, 67232, 76832, 86432, 115232, 124832, 134432, 144032, 153632, 163232, 172832, 182432, 192032, 201632 root@quadra ~$ mount /dev/lofi/1 /a root@quadra ~$ df -h /a Filesystem Size Used Avail Use% Mounted on /dev/lofi/1 94M 1.1M 84M 2% /a root@quadra ~$ umount /a root@quadra ~$ lofiadm -d /dev/lofi/1
LOFI Compression
Compression is slightly non-intuative in that you can compress and existing image but thereafter it is available read only. You can not read/write a compressed image. Images can be compressed by running lofiadm -C gzip somefile, before adding the file as usual. The only (currently) available algorithm is GZip, which can by default is set to gzip6 but can be tweek such as by specifying “gzip-9”.
Lets compress the image we created with UFS above for fun. I’ve added 26MB of binaries to it and it was originally a 100MB file (image).
root@quadra /$ lofiadm -C gzip-9 /home/benr/lumpospace root@quadra /$ ls -lh /home/benr/lumpospace -rw------T 1 root root 9.7M Apr 1 15:15 /home/benr/lumpospace root@quadra /$ lofiadm -a /home/benr/lumpospace /dev/lofi/1 root@quadra /$ lofiadm Block Device File Options /dev/lofi/1 /home/benr/lumpospace Compressed(gzip-9) root@quadra /$ mount /dev/lofi/1 /a mount: I/O error mount: Cannot mount /dev/lofi/1
Notice the mount failed… thats because the image is read-only… try again with the read-only mount option (ro):
root@quadra ~$ mount -o ro /dev/lofi/1 /a root@quadra ~$ cd /a root@quadra a$ ls 7z avahi-publish-service chat cxref dvd+rw-format 7za avahi-resolve checkeq daps dvd+rw-mediainfo ...
So the result of compressing the image is that its now read-only… but the 100MB image with 26MB of data now only consumes 9.7MB of disk.
If you decide you need to add data to a compressed image, you’ll need to uncompress it (using ‘lofiadm -U compressedfile’), do your thing, then re-compress it.
Truth is, compressed lofi is fairly uninteresting in most cases because ZFS already does a great job with read/write compression. So… moving on to encryption….
LOFI Encryption
Encryption is more interesting. You can use a variety of algorithms including AES (128bit, 192bit, and 256bit), 3DES, and Blowfish, with a variety of key stores.
Lets do a simple example using Blowfish. Notice that if you do not specify a key store it will resort to using passwords:
root@quadra ~$ mkfile 100m secrets root@quadra ~$ lofiadm -a secrets -c blowfish-cbc Enter key: goawaynow Re-enter key: goawaynow <--- Not echo'ed /dev/lofi/1 root@quadra ~$ lofiadm Block Device File Options /dev/lofi/1 /home/benr/secrets Encrypted root@quadra ~$ newfs /dev/lofi/1 newfs: construct a new file system /dev/rlofi/1: (y/n)? y /dev/rlofi/1: 204600 sectors in 341 cylinders of 1 tracks, 600 sectors 99.9MB in 22 cyl groups (16 c/g, 4.69MB/g, 2240 i/g) super-block backups (for fsck -F ufs -o b=#) at: 32, 9632, 19232, 28832, 38432, 48032, 57632, 67232, 76832, 86432, 115232, 124832, 134432, 144032, 153632, 163232, 172832, 182432, 192032, 201632 root@quadra ~$ mount /dev/lofi/1 /a root@quadra ~$ cp IBM-TakeoverPlan /a root@quadra ~$ umount /a root@quadra ~$ lofiadm -d /dev/lofi/1
So we created an empty file for loopback use, added it with Blowfish encryption enabled, and created a UFS filesystem on it. Then we use it like any normal filesystem, unmount it and destroy the LOFI when we're done.
When you decided you need to use it again, you'll preform the exact same steps, however the password you enter will be the same password. This is the strange bit... if you get the password wrong everything will seem to work but the data is unreadable. (this is because the password is your key and the key is wrong, therefore the data won't decrypt):
root@quadra ~$ lofiadm -a secrets -c blowfish-cbc Enter key: thisismykey Re-enter key: thisismykey <--- this is not echo'ed /dev/lofi/1 root@quadra ~$ lofiadm Block Device File Options /dev/lofi/1 /home/benr/secrets Encrypted root@quadra ~$ mount /dev/lofi/1 /a mount: /dev/lofi/1 is not this fstype
When it comes to key stores... you have the option to use an ephemeral (one-time) key (-e), a raw key file (-k keyfile), or a PKCS#11 token (-T).
Lets try using a raw key file. We'll generate it for AES256 using the Solaris Key Management Framekwork's pktool:
root@quadra ~$ pktool genkey keystore=file outkey=lofi.key keytype=aes keylen=256 print=y Key Value ="b2998f7634863a563e6030085dcf01d4680b4fd90f0de6661824fba215ba9cb9" root@quadra ~$ mkfile 100m toomanysecrets root@quadra ~$ lofiadm -a toomanysecrets -c aes-256-cbc -k lofi.key /dev/lofi/1 root@quadra ~$ lofiadm Block Device File Options /dev/lofi/1 /home/benr/toomanysecrets Encrypted root@quadra ~$ newfs /dev/lofi/1 newfs: construct a new file system /dev/rlofi/1: (y/n)? y /dev/rlofi/1: 204600 sectors in 341 cylinders of 1 tracks, 600 sectors 99.9MB in 22 cyl groups (16 c/g, 4.69MB/g, 2240 i/g) super-block backups (for fsck -F ufs -o b=#) at: 32, 9632, 19232, 28832, 38432, 48032, 57632, 67232, 76832, 86432, 115232, 124832, 134432, 144032, 153632, 163232, 172832, 182432, 192032, 201632 root@quadra ~$ mount /dev/lofi/1 /a
While KMF PKCS#11 is supported, all attempts on my part to use it failed... so I'll blog about that some other day when I work it out.
In parting, I'll suggest that anyone serious about crypto and compressed filesystem should check out the OpenSolaris FUSE Project and stay tuned for ZFS Crypto support.