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.