Encrypting Container Files in SLES 10 and SLES 11
There are endless documents, articles, editorials and such, on data security and encryption. Views and opinions fly over which methods are better than others and why. AES, DES, Sha1, twoFish256, Blowfish, TripleDogDareYouFish192. File encryption, Partition encryption, Full disk encryption and the popular, No encryption.
This article is just concerned with showing you how to encrypt a small portion of data called a Container File. A container file is a file that has been created and converted to represent a partition. It is configured, formatted and mounted just like any traditional storage device, except it is still technically, a file.
In the title of this article I specify both SLES 10 and SLES 11, instead of just SLES. That is because with the release of SLES 11, encrypting a file system was changed. I am including SLES 10, as it is still widely used. We’ll walk through both of them in version order.
Why do I want to encrypt a container file and not just individual files or the entire disk? I do incorporate partition encryption, including SWAP, on my SLES 11 servers. I do not encrypt individual files because I have several I use, and keeping up with passphrases would cause me, to make a whole new encrypted file with the passwords to all of the other files. I’d rather make one container file and place the files I want to encrypt in it. All I have to do is mount the container file, do what I need to do, then dismount it.
One caveat to this approach is that while the container file is mounted, root will also have access to the data within that container file. But, once the container file has been dismounted, no one can mount it without the passphrase…Not even root.
There are other ways at getting to the data, probing SWAP or RAM, but those measures of security are beyond the scope of this article.
We’ll make some assumptions before we begin.
Ensure you have “root” access and a good working knowledge of Linux partitioning.
Encrypted Container Files – SLES 10
Creating a container file is fairly simple, and the basics pertain to either SLES 10 or SLES 11. Encrypting them is where the difference lies. Let’s start by creating a simple container file and mounting it. Then we’ll create another one and encrypt it.
Login as root, and if you’re not at the command prompt, open a gnome terminal.
First, we have to create the container file and specify the size we want. We’ll use “dd” for this. Create a 10MB file. You can put the file where ever you wish, I’m using /root/.
# dd if=/dev/zero of=/root/newfile.img bs=1k count=10000 10000+0 records in 10000+0 records out #
We tell “dd” to use “/dev/zero” to fill “newfile.img” with zeros using 1k blocks, for a count of 10,000.
# ll newfile.img -rw-r--r-- 1 root root 10240000 Jan 14 19:21 newfile.img #
We can see it has been created. Since this is not a true disk device, we have to set it up as a “loop” device. Linux provides 8 loop devices, by default. /dev/loop0-7. If you use loop devices for other purposes, you can determine which devices are already in use with the command “losetup –a”. We will use /dev/loop0 for our purposes.
Use the utility “losetup” to assign the new container file to loop0.
# losetup /dev/loop0 /root/newfile.img #
To see if the assignment was successful, use “losetup –a”.
# losetup –a /dev/loop0: :68867 (/root/newfile.img) #
Now that the container file is ready for a file system. We’ll format it with EXT2 using “mke2fs”
# mke2fs -c /dev/loop0 10000 mke2fs 1.38 (30-Jun-2005) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 2512 inodes, 10000 blocks 500 blocks (5.00%) reserved for the super user First data block=1 2 block groups 8192 blocks per group, 8192 fragments per group 1256 inodes per group Superblock backups stored on blocks: 8193 Checking for bad blocks (read-only test): done 000 Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 39 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. #
Create a mount point for the new device. You can create this where ever you need to. We’re using /mnt/.
# mkdir /mnt/newfs #
And then mount the device.
# mount -v -t ext2 /dev/loop0 /mnt/newfs /dev/loop0 on /mnt/newfs type ext2 (rw) #
Get a listing of the new mounted container file.
# # ll /mnt/newfs/ total 13 drwxr-xr-x 3 root root 1024 Jan 14 19:25 . drwxr-xr-x 4 root root 96 Jan 14 19:26 .. drwx------ 2 root root 12288 Jan 14 19:25 lost+found #
Let’s check with a “mount” and a “df” command.
# mount /dev/sda2 on / type reiserfs (rw,acl,user_xattr) proc on /proc type proc (rw) sysfs on /sys type sysfs (rw) tmpfs on /dev/shm type tmpfs (rw) devpts on /dev/pts type devpts (rw,mode=0620,gid=5) /dev/loop0 on /mnt/newfs type ext2 (rw) # # df –h Filesystem Size Used Avail Use% Mounted on /dev/sda2 19G 14G 5.3G 73% / tmpfs 1013M 12K 1013M 1% /dev/shm /dev/loop0 9.5M 13K 9.0M 1% /mnt/newfs #
If you want to make it easier to mount on boot up, place an entry similar to this in your /etc/fstab file.
/root/newfile.img /mnt/newfs ext2 noauto,exec,loop=/dev/loop0 0 0
We use the “noauto” option to prevent it from mounting on boot, but we can mount it easily with mount /mnt/newfs
Before we continue and since we want to use the same loop device, let’s clean up a bit.
Unmount the device
# umount /mnt/newfs #
Remove the loop device assignment.
# losetup –d /dev/loop0 #
Now let’s do the same thing, but we’ll encrypt the container file.
In this scenario, we want to create an encrypted container file that is only usable by a certain user. The container file will reside in their /home/user01/ directory and we’ll name it with a preceding “.” so it is normally hidden from directory listings. We’ll be using AES 128 bit encryption, which means we need to add it to the kernel first. AES isn’t loaded into the kernel by default.
To verify if the AES module is loaded, use “lsmod”
# lsmod | grep aes aes 27200 0 #
If you do not see it, use “modprobe –list | grep –e aes” to find the module and load it with “modprobe [aes_module_name]”
Again, we create the container file using “dd”, but we’re going to make the parameters a little different.
# dd if=/dev/urandom of=/home/user01/.cryptfile bs=4k count=10000 10000+0 records in 10000+0 records out 40960000 bytes (41 MB) copied, 0.339379 s, 121 MB/s #
This time, we used “/dev/urandom”, which fills the file with random data, instead of all zeros. We also created the file in a user’s home directory and put a “.” as the first character in the filename. We stated 4k blocks * 10000 and you’ll see that the container file is 41 MB in size.
We’ll encrypt the file with “losetup” using the “-e” option and specify the type of encryption, “aes”.
# losetup -e aes -T /dev/loop0 /home/user01/.cryptfile Password: Error: Password must be at least 20 characters. #
It failed because our Password MUST be a minimum of 20 characters. The “-T” option makes us enter the password twice to verify. In SLES 11, the option was changed to “-y” and the “-T” was dropped, so you’ll get an error.
# losetup -e aes -T /dev/loop0 /home/user01/.cryptfile Password: Retype password: #
Not real verbose, is it. Let’s see if it worked using “losetup –a”
# losetup –a /dev/loop0: :68867 (/home/user01/.cryptfile) encryption=aes #
There it is. Now, like before, we have to format it.
# mke2fs -t ext2 /dev/loop0 mke2fs 1.38 (30-Jun-2005) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 10000 inodes, 40000 blocks 2000 blocks (5.00%) reserved for the super user First data block=1 5 block groups 8192 blocks per group, 8192 fragments per group 2000 inodes per group Superblock backups stored on blocks: 8193, 24577 Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 32 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. #
We’re not going to mount it yet. We want “user01” to be able to use this container file, exclusively. Remove the loop0 assignment first.
# losetup –d /dev/loop0 #
Create a mount point and change the owner to “user01” to this space. To keep regular users out of this directory, when mounted, assign the group as “root” and change the POSIX for “Other” to 0.
# mkdir /mnt/crypt # cd /mnt/crypt/ # chown user01.root . # cd .. # chown user01.root crypt # chmod -R 640 crypt # # ll drw-r----- 2 user01 root 6 Jan 15 17:13 crypt #
Add the following or similar to the /etc/fstab.
/home/user01/.cryptfile /mnt/crypt ext2 noauto,users,loop=/dev/loop0,encryption=AES 0 0
Again, “noauto”, so it must me manually mounted and we added, “users” so “user01” can mount it without “sudo”.
Let’s try it out as user, “User01”.
$ mount /mnt/crypt Password: $
Notice it prompted for the Password we assigned? If you enter it incorrectly, you will receive a mount error about superblocks.
We’ll take a look at mounts and “df” also.
$ ll /mnt/crypt/ drw--r---- 2 user01 root 12288 Jan 14 19:25 lost+found $ $ mount /dev/sda2 on / type reiserfs (rw,acl,user_xattr) proc on /proc type proc (rw) sysfs on /sys type sysfs (rw) tmpfs on /dev/shm type tmpfs (rw) devpts on /dev/pts type devpts (rw,mode=0620,gid=5) /dev/loop0 on /mnt/crypt type ext2 (rw) $ $ df –h Filesystem Size Used Avail Use% Mounted on /dev/sda2 19G 14G 5.3G 73% / tmpfs 1013M 12K 1013M 1% /dev/shm /dev/loop0 41M 13K 41M 1% /mnt/crypt $
Pretty Sweet, huh! Now User01 is done with whatever they do with that space and unmounts it.
$ umount /mnt/crypt $
That’s pretty much it for SLES 10.
There are a few things to point out.
- The most important is that you nor anyone else cannot change the password on the container file. The encryption of the container file is based on that password. There is a way to change it, but basically, you create a new container file and move the files from one to the other and then remove the old one. Not really a password change.
- If you move the file to another location, remember to change the /etc/fstab file our you’ll get a call.
- I haven’t tried symlinks either to or from, with this method.
Encrypted Container Files – SLES 11
In SLES 11, they brought the ability for hard disk encryption and integrating it into YaST, especially during installation. They changed from standard looping devices to “cryptoloop” and handling encrypted partitions using a device mapper “dm-crypt”. In addition, LUKS, Linux Unified Key Setup, was added because it is a special format for encrypted volumes and it is integrated on top of “dm-crypt”. “dm-crypt” has no limit on the number of encrypted partitions as there are only 8 loop devices.
I’ll explain more features and cool stuff as we build an encrypted container file in SLES 11. I want to point out that all of the steps listed in this section are also available within YaST.
Let’s start by creating the container file for User01, as we did earlier.
# dd if=/dev/urandom of=/home/user01/.cryptfile bs=4k count=10000 10000+0 records in 10000+0 records out 40960000 bytes (41 MB) copied, 8.41466 s, 4.9 MB/s #
Now here’s where it becomes different. We want to assign the file to a loop device, but we omit the encryption option.
# losetup -v /dev/loop0 /home/user01/.cryptfile Loop device is /dev/loop0 #
Using the utility, “cryptsetup”, we’ll encrypt the container file. We pass luksFormat as this is a new partition.
# cryptsetup -v --key-size 256 luksFormat /dev/loop0 WARNING! ======== This will overwrite data on /dev/loop0 irrevocably. Are you sure? (Type uppercase yes): YES Note: make sure keyboard layout and encoding here matches the intended environment for unlocking the volume Enter LUKS passphrase: Verify passphrase: Command successful. #
Unlike “losetup” that required a 20 character minimum on the passphrase, “cryptsetup” will take 1 character. I haven’t seen anything yet that can force this to require a higher minimum.
One thing LUKS allows for is multiple passphrases. This can be helpful as a fallback should the primary get lost or simply forgotten. See man page for cryptsetup.
Let’s take a look at our work. Using “cryptsetup”, we can perform a luksDump to display the details of the container file.
# cryptsetup -v luksDump /dev/loop0 LUKS header information for /dev/loop0 Version: 1 Cipher name: aes Cipher mode: cbc-essiv:sha256 Hash spec: sha1 Payload offset: 2056 MK bits: 256 MK digest: 42 4e c1 28 b7 3c df 16 de d0 53 4f 64 8b bc 4a 9e 97 7d 92 MK salt: a5 5a 52 b3 ae 62 cd c8 0c 58 3e 37 08 13 da 11 4a 0c 5e 7f b4 ba 99 c5 13 ad 80 d3 0b 9d 4e 3d MK iterations: 10 UUID: d51ace66-d295-41f2-a47e-f95b5ee667f4 Key Slot 0: ENABLED Iterations: 224473 Salt: b9 a0 cb 0b de ba ac 51 94 8b ad b8 99 90 40 d1 3a ad ad ba 38 ce dd a0 38 4c c1 8a 90 c8 77 55 Key material offset: 8 AF stripes: 4000 Key Slot 1: DISABLED Key Slot 2: DISABLED Key Slot 3: DISABLED Key Slot 4: DISABLED Key Slot 5: DISABLED Key Slot 6: DISABLED Key Slot 7: DISABLED #
Now we will open the container file using luksOpen option.
# cryptsetup -v luksOpen /dev/loop0 cryptfs Enter LUKS passphrase: key slot 0 unlocked. Command successful. #
This command should have created the device under /dev/mapper/. Let’s list the entries in that directory.
# ll /dev/mapper/ total 0 lrwxrwxrwx 1 root root 16 Nov 26 13:14 control -> ../device-mapper brw-r----- 1 root disk 253, 4 Jan 15 20:35 cryptfs brw-r----- 1 root disk 253, 0 Nov 26 13:14 root-opt brw-r----- 1 root disk 253, 1 Nov 26 13:14 root-root brw-r----- 1 root disk 253, 2 Nov 26 13:14 root-tmp brw-r----- 1 root disk 253, 3 Nov 26 13:14 root-var #
And there it is, “cryptfs”.
Next, we put a file system on it. Here, we’ll use EXT3.
# /sbin/mkfs.ext3 -O dir_index,resize_inode /dev/mapper/cryptfs mke2fs 1.41.9 (22-Aug-2009) Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 9760 inodes, 38972 blocks 1948 blocks (5.00%) reserved for the super user First data block=1 Maximum filesystem blocks=40108032 5 block groups 8192 blocks per group, 8192 fragments per group 1952 inodes per group Superblock backups stored on blocks: 8193, 24577 Writing inode tables: done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 23 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. #
Before we can mount it, we need to make an entry in both /etc/fstab and /etc/crypttab
/dev/mapper/cryptfs /mnt/crypt ext3 noauto,user 0 0
crypt /home/user01/.cryptfile none luks
Mount the new container file.
# mount /dev/mapper/cryptfs /mnt/crypt #
Copy some files to it and let’s see if they are there.
# ll /mnt/crypt/ total 595 -rw-r--r-- 1 root root 351048 Jan 15 20:41 compat-2009.1.19-2.1.i586.rpm drwx------ 2 root root 12288 Jan 15 20:37 lost+found -rw-r--r-- 1 root root 241551 Jan 15 20:42 rkhunter-1.3.8.tar.gz #
Once again, umount the container file when you are done using it to prevent others, namely, “root” from accessing your files.
With previous versions, “/etc/init.d/boot.crypto” was started at boot. In SLES 11, it is “off”, you will need to run “chkconfig boot.crypto on” to enable cryptoloop for your devices.
The SLES 11 Security Guide, in the documentation offers little more than a couple of paragraphs on File System Encryption. I found a lot more information in the man pages and few very old encryption rants and trying it myself. I admit I prefer the SLES 11 methods as they are cleaner, and with LUKS, the encryption options are much more robust than previous versions.