E
Eric Hansen
Guest
A lot of people use TrueCrypt to create virtual drives/containers to encrypt files, and it works wonders when you’re using Windows, because Windows has no built-in support for such technology. However, in the world of Linux, we’ve been fortunate to have this for a vast amount of time!
This will be a small article (the next one will cover other ways to use cryptsetup), but beneficial nonetheless.
You can do this with a regular device, but we’ll use our system’s resources for this. By this I mean we will convert a file to a block device (drive), and treat that as the container. I’m doing this on Ubuntu 12.04 stock kernel (most come with dm-crypt and LUKS support enabled by default now anyways).
Also, sudo su - so you can be root for this, makes it easier in the end and most of the commands will require it anyways for this guide.
Creating The Block Device
This is going to be semi-long compared to the rest because there’s two parts to it. First, we need to create an empty file of a specific size and null/zero it out. Then we need to connect it to our system so it thinks its a block device. After that the rest is pretty simple, but I’ll break this into smaller parts as well.
Installing Needed Software
While the kernel itself typically supports the methods used by default, we fall back into the issue again (similar to LXC) where we need to have userspace tools. Assuming you’re using Debian/Ubuntu (and this is the only time I’ll make this assumption throughout this entire guide), simply install (as root) cryptsetup:
Creating the File
Typically when you create a file in Linux there’s a multitude of ways to do it (echo to it, touch, editors, etc…). However, given the nature of what this file will be used for none of those methods will work for us. We need a file that’s pre-allocated to a specific size and yet empty.
For us, we have a very useful (and standard) tool called dd. What this does for us is everything stated above. We’ll pass it 3 arguments: input file, output file and count size (how big we want it to be). The input file will be /dev/zero so we can zero it out, the output file will be /root/test.bin but you can name it and place it wherever you want, and we’ll make it 512MB big. Now, since I believe drives should be measured in 1024-bytes, not the 1000-bytes you often see, we’ll make the conversion as such too:
After a little bit (depending on how fast your computer, I/O, etc… is), you’ll see output like this:
Its basically telling you some data about the disk performance (irrelevant here but its common to see this when people are testing the performance of VPSes).
Connecting a Device to the File
We have the file, but how are we going to trick our system into thinking that its a device? Well, a small bit of technical detail: devices in Linux are nothing but special files.
That’s right. When you mount a drive, the kernel/system just sees it as another file (specifically a directory). So how are we going to make this work in our favor? Well, in terms of networking there’s always a loopback device (127.0.0.1 typically). This is nothing but a dummy adapter on the system. The same exists for block devices, and by default you’ll probably have more than one of them. As a demonstration:
Ignore the last one, but the 0-7 entries above are what we’re interested in. These are the loopback devices of blocks, which we can use to our advantage. There’s more to these which I’ll show at the end, but essentially we just need to pick an unused loop device we want to use, and point it to our newly created file (basically like mount), using losetup:
I had to use loop1 but that’s irrelevant. You won’t see any output saying it was successful, otherwise you’ll see some error stating why it wouldn’t work. Essentially it creates what can be considered a symlink of test.bin to loop0.
Partition It
Descriptive header, eh?
So now we have to format our file/device so our system can work with it. I usually use cfdisk but for the sake of this article we’ll use fdisk:
I’m not sure if multiple partitions can be made safely, I’ve tried but had limited success, so we’ll just stick with one for now.
Setting Up dm-crypt and LUKS
Setting Up Crypt
Normally this would be the step you format the partition, right? Well, lets not and say we will later. Instead we’ll make it a container first, partition it second. Now, there’s a few options available to you at this stage, but to get our feet wet and make sure things work we’ll do virtually the bare minimum:
The “--verbose” switch allows cryptsetup to give us more information, while “--verify-passphrase” makes us type it in twice so we know there’s no goofs. “luksFormat” specifies that we want to use the LUKS extension of dm-crypt and also tells dm-crypt to create a LUKS header on /dev/loop0. It’ll ask you for a passphrase which is the password needed to actually mount it. Multiple passphrases can be provided as well, but we’ll stick with one for now.
There’s really not a whole lot to this exactly so that’s why I didn’t go into detail about this.
Opening the Block Device
In order for our system to see it (and for us to format it), we need to connect the block device to our system. Fortunately cryptsetup has an easy-to-do way of this, mapping our block device to /dev/mapper/*. Let me explain:
We have /dev/loop0 (the block device) mapped to our test.bin file so we’re going to stick working with block files pretty much forever now in this. But what we do is tell cryptsetup to mount the container to /dev/mapper/sometest (the last parameter passed is what we’re mapping to). So for example if you have /dev/sda1 mapped to /, this mapped /dev/loop0 to /dev/mapper/sometest, where you can store all of your files.
But wait, there’s one issue...its not formatted!
Formatting Our Container
Remember that partition we made? That’s why we made it. All of our data will fit inside of that partition. To do that though we need to create a filesystem on it (right now its like a bowl of tofu, lets make it pudding!):
Simple, right? Now the rest is normal procedure.
Mounting the Container
So, now that we have this wonderfully encrypted container for storage, how do we mount it? Well, lets first create a folder to mount it to (remember, we’re still working with block devices at this point):
Then, so we can see it:
Voila! Now when you put files into there it’ll be mapped to the container that encrypts everything thanks to LUKS and dm-crypt! To unmount you just do an umount on it.
This will be a small article (the next one will cover other ways to use cryptsetup), but beneficial nonetheless.
You can do this with a regular device, but we’ll use our system’s resources for this. By this I mean we will convert a file to a block device (drive), and treat that as the container. I’m doing this on Ubuntu 12.04 stock kernel (most come with dm-crypt and LUKS support enabled by default now anyways).
Also, sudo su - so you can be root for this, makes it easier in the end and most of the commands will require it anyways for this guide.
Creating The Block Device
This is going to be semi-long compared to the rest because there’s two parts to it. First, we need to create an empty file of a specific size and null/zero it out. Then we need to connect it to our system so it thinks its a block device. After that the rest is pretty simple, but I’ll break this into smaller parts as well.
Installing Needed Software
While the kernel itself typically supports the methods used by default, we fall back into the issue again (similar to LXC) where we need to have userspace tools. Assuming you’re using Debian/Ubuntu (and this is the only time I’ll make this assumption throughout this entire guide), simply install (as root) cryptsetup:
Code:
apt-get install cryptsetup
Typically when you create a file in Linux there’s a multitude of ways to do it (echo to it, touch, editors, etc…). However, given the nature of what this file will be used for none of those methods will work for us. We need a file that’s pre-allocated to a specific size and yet empty.
For us, we have a very useful (and standard) tool called dd. What this does for us is everything stated above. We’ll pass it 3 arguments: input file, output file and count size (how big we want it to be). The input file will be /dev/zero so we can zero it out, the output file will be /root/test.bin but you can name it and place it wherever you want, and we’ll make it 512MB big. Now, since I believe drives should be measured in 1024-bytes, not the 1000-bytes you often see, we’ll make the conversion as such too:
Code:
dd if=/dev/zero of=/root/test.bin count=1000k
Code:
root:~# dd if=/dev/zero of=~/test.bin count=1000k
1024000+0 records in
1024000+0 records out
524288000 bytes (524 MB) copied, 2.62044 s, 200 MB/s
Its basically telling you some data about the disk performance (irrelevant here but its common to see this when people are testing the performance of VPSes).
Connecting a Device to the File
We have the file, but how are we going to trick our system into thinking that its a device? Well, a small bit of technical detail: devices in Linux are nothing but special files.
That’s right. When you mount a drive, the kernel/system just sees it as another file (specifically a directory). So how are we going to make this work in our favor? Well, in terms of networking there’s always a loopback device (127.0.0.1 typically). This is nothing but a dummy adapter on the system. The same exists for block devices, and by default you’ll probably have more than one of them. As a demonstration:
Code:
root:~# ls -liha /dev/loop*
7196 brw-rw---- 1 root disk 7, 0 Aug 22 15:28 /dev/loop0
7197 brw-rw---- 1 root disk 7, 1 Aug 22 09:33 /dev/loop1
7198 brw-rw---- 1 root disk 7, 2 Aug 22 09:33 /dev/loop2
7199 brw-rw---- 1 root disk 7, 3 Aug 22 09:33 /dev/loop3
7200 brw-rw---- 1 root disk 7, 4 Aug 22 09:33 /dev/loop4
7201 brw-rw---- 1 root disk 7, 5 Aug 22 09:33 /dev/loop5
7202 brw-rw---- 1 root disk 7, 6 Aug 22 09:33 /dev/loop6
7203 brw-rw---- 1 root disk 7, 7 Aug 22 09:33 /dev/loop7
7195 crw------- 1 root root 10, 237 Aug 22 09:33 /dev/loop-control
Ignore the last one, but the 0-7 entries above are what we’re interested in. These are the loopback devices of blocks, which we can use to our advantage. There’s more to these which I’ll show at the end, but essentially we just need to pick an unused loop device we want to use, and point it to our newly created file (basically like mount), using losetup:
Code:
losetup /dev/loop0 /root/test.bin
Partition It
Descriptive header, eh?
So now we have to format our file/device so our system can work with it. I usually use cfdisk but for the sake of this article we’ll use fdisk:
Code:
root:~# fdisk /dev/loop0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x20ce46d0.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
Command (m for help): n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
Partition number (1-4, default 1):
Using default value 1
First sector (2048-1023999, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-1023999, default 1023999):
Using default value 1023999
Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
WARNING: Re-reading the partition table failed with error 22: Invalid argument.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.
I’m not sure if multiple partitions can be made safely, I’ve tried but had limited success, so we’ll just stick with one for now.
Setting Up dm-crypt and LUKS
Setting Up Crypt
Normally this would be the step you format the partition, right? Well, lets not and say we will later. Instead we’ll make it a container first, partition it second. Now, there’s a few options available to you at this stage, but to get our feet wet and make sure things work we’ll do virtually the bare minimum:
Code:
root:~# cryptsetup --verbose --verify-passphrase luksFormat /dev/loop0
WARNING!
========
This will overwrite data on /dev/loop0 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
Verify passphrase:
Command successful.
The “--verbose” switch allows cryptsetup to give us more information, while “--verify-passphrase” makes us type it in twice so we know there’s no goofs. “luksFormat” specifies that we want to use the LUKS extension of dm-crypt and also tells dm-crypt to create a LUKS header on /dev/loop0. It’ll ask you for a passphrase which is the password needed to actually mount it. Multiple passphrases can be provided as well, but we’ll stick with one for now.
There’s really not a whole lot to this exactly so that’s why I didn’t go into detail about this.
Opening the Block Device
In order for our system to see it (and for us to format it), we need to connect the block device to our system. Fortunately cryptsetup has an easy-to-do way of this, mapping our block device to /dev/mapper/*. Let me explain:
Code:
root:~# cryptsetup luksOpen /dev/loop0 sometest
Enter passphrase for /dev/loop0:
We have /dev/loop0 (the block device) mapped to our test.bin file so we’re going to stick working with block files pretty much forever now in this. But what we do is tell cryptsetup to mount the container to /dev/mapper/sometest (the last parameter passed is what we’re mapping to). So for example if you have /dev/sda1 mapped to /, this mapped /dev/loop0 to /dev/mapper/sometest, where you can store all of your files.
But wait, there’s one issue...its not formatted!
Formatting Our Container
Remember that partition we made? That’s why we made it. All of our data will fit inside of that partition. To do that though we need to create a filesystem on it (right now its like a bowl of tofu, lets make it pudding!):
Code:
root:~# mkfs.ext4 -j /dev/mapper/sometest
mke2fs 1.42 (29-Nov-2011)
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
Stride=0 blocks, Stripe width=0 blocks
127512 inodes, 509952 blocks
25497 blocks (5.00%) reserved for the super user
First data block=1
Maximum filesystem blocks=67633152
63 block groups
8192 blocks per group, 8192 fragments per group
2024 inodes per group
Superblock backups stored on blocks:
8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409
Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done
Mounting the Container
So, now that we have this wonderfully encrypted container for storage, how do we mount it? Well, lets first create a folder to mount it to (remember, we’re still working with block devices at this point):
Code:
mkdir /mnt/encrypto
Code:
mount /dev/mapper/sometest /mnt/encrypto
Attachments
Last edited: