Monday 12 January 2009 @22:05
Original, unmodified image
The other day, for kicks, I wrote a small program to embed a hidden image within another image, and another to extract the hidden image. This is called steganography:
…the art and science of writing hidden messages in such a way that no-one apart from the sender and intended recipient even realizes there is a hidden message, a form of security through obscurity. By contrast, cryptography obscures the meaning of a message, but it does not conceal the fact that there is a message. [Wikipedia]
With hidden image embedded; the differences are all but invisible.
Embedded image partially revealed by shifting colors; click through to see more.
Step through the demo on flickr, and read the descriptions to understand what’s going on. In this technique, I use 6 bits per channel for the outer, visible image, and 2 bits per channel for the hidden image. However, the composed result is pretty much indistinguishable from the original.
The programs use the GraphicsMagick variant of the ImageMagick library. (I had GM ready to go already because I used it for other projects.) If you want to play with these images yourself, the JPEG conversions on Flickr will not work; download this PNG instead.
#include <Magick++.h>
#include <iostream>
using std::cout;
using std::string;
using namespace Magick;
Quantum revealDisguisedColor(Quantum q)
{
return (q & 3) << 6;
}
int main(int argc, char** argv, char** envp)
{
InitializeMagick(*argv);
assert(argc == 3);
const string samplePath = argv[1];
const string outputPath = argv[2];
cout << "Loading " << samplePath << '\n';
Image im (samplePath);
Geometry g = im.size();
cout << "Dimensions are " << (string)g << '\n';
cout << "Depth is " << im.depth() << '\n';
assert(im.type() == TrueColorType);
for(unsigned x = 0; x < g.width(); x++) {
for(unsigned y = 0; y < g.height(); y++) {
Color c = im.pixelColor(x, y);
cout << (string)c << " --> ";
c.redQuantum(revealDisguisedColor(c.redQuantum()));
c.greenQuantum(revealDisguisedColor(c.greenQuantum()));
c.blueQuantum(revealDisguisedColor(c.blueQuantum()));
cout << (string)c << '\n';
im.pixelColor(x, y, c);
}
}
cout << "Writing " << outputPath << '\n';
im.write(outputPath);
return 0;
}
#include <Magick++.h>
#include <iostream>
using std::cout;
using std::string;
using namespace Magick;
Quantum mergeQuanta(Quantum pub, Quantum priv)
{
priv >>= 6;
pub &= 0xFC;
return pub | priv;
}
Color mergeColors(Color pub, Color priv)
{
pub.redQuantum(mergeQuanta(pub.redQuantum(), priv.redQuantum()));
pub.greenQuantum(mergeQuanta(pub.greenQuantum(), priv.greenQuantum()));
pub.blueQuantum(mergeQuanta(pub.blueQuantum(), priv.blueQuantum()));
return pub;
}
int main(int argc, char** argv, char** envp)
{
InitializeMagick(*argv);
assert(argc == 4);
const string publicPath = argv[1];
const string privatePath = argv[2];
const string outputPath = argv[3];
cout << "Loading " << publicPath << '\n';
Image pub (publicPath);
Geometry g = pub.size();
assert(pub.depth() <= 8);
assert(pub.type() == TrueColorType);
cout << "Loading " << privatePath << '\n';
Image priv (privatePath);
assert(priv.size() == g);
assert(priv.depth() <= 8);
assert(priv.type() == TrueColorType);
for(unsigned x = 0; x < g.width(); x++) {
for(unsigned y = 0; y < g.height(); y++) {
pub.pixelColor(x, y, mergeColors(pub.pixelColor(x, y),
priv.pixelColor(x, y)));
}
}
cout << "Writing " << outputPath << '\n';
pub.write(outputPath);
return 0;
}
Tuesday 10 July 2007 @11:38
Over the past few days, I’ve been cleaning up compromised web sites that run PHP-based content management systems. This got me thinking (not for the first time) about the sad state of CMS security.
One of the key problems is that CMS software is not always treated with the same level of care as regular system software. As with any net-facing software, flaws must be carefully tracked and patches swiftly applied. This is tricky because CMSs are not always installed using the regular package administration system; often they are uploaded into the public_html spaces of regular users.
But I want to address an underlying problem that has more to do with the design of these systems themselves (which of course impacts their suitability for packaging and maintenance in something like the Debian archive). In my experience, many content management systems jumble together the following kinds of files and code that should — following the principles of least privilege and privilege separation — be kept distinct:
- Data files or scripts that should directly correspond to URLs.
- Data files or scripts that are merely included or opened from other files, and therefore should not be reachable from any URL.
- Code that needs privilege to write to the file system or database.
- Code that merely needs read privilege.
- Directories in which the code can create and modify files.
- Writable directories whose contents are accessible as URLs.
- Writable directories accessible as URLs, in which script extensions (.php, .cgi, etc.) are honored.
The astute reader should be able to deduce the security implications of each of the above, but here are some hints. Web-accessible library code increases the surface area for exploits. Writable, web-accessible directories invite spam content. Writable, executable, web-accessible directories are havens for malware.
Keeping these categories distinct would not just increase the baseline security of the CMS, it would also improve usability with other tools like chroot jails and suPHP. The latter provides privilege separation by executing scripts with the privileges of their owner rather than the web user (www-data), but of course that requires spawning a new process for each request. One of the reasons that PHP (and later, Python) proliferated in web applications is the lower overhead of running the interpreters as modules within the web server. By isolating the bits of code that need write access, one might achieve a better compromise of efficiency and security.
I understand that a reason for flouting security conventions (apart from ignorance) is ease of installation. Content management systems are often set up by naive users over FTP connections to unprivileged accounts on shared hosts. But I believe it’s entirely possible to design the system more securely for expert users or site administrators, while still allowing naive users their (more vulnerable) one-click installs. Pay-as-you-go security. The content management systems that do get packaged for Debian are usually configured in a pretty reasonable way, but it’s telling that the worst offenders don’t get packaged at all.
Friday 28 July 2006 @11:41
Last week, I bought a pair of 200G IDE disks, just because they were dirt cheap. Probably I’ll use one at home and one at work. I already have a 150G at home for music and such.
I used to be a SCSI snob — and I guess in some ways I still am — but I just can’t afford that habit anymore! Although I miss the performance of SCSI, the price differential per GB is enormous. The drop in performance is definitely noticeable, particularly since I now have two large disks on the same bus. Any disk-intensive activity also drives up the CPU load, which it never would do with SCSI. And forget running more than one disk-intensive process at a time. If I’m still on the computer when ‘updatedb’ starts running, it’s time for bed.
Anyway, in rearranging my file systems at home, I decided to try something new. I now have my root and /home file systems on encrypted partitions. Why? Just because I can, I guess. It might be a fairly valuable technique on a laptop, which is more easily lost or stolen. At least then, you can be reasonably confident the thief can’t access your data.
On a home desktop machine though, crypto seems admittedly frivolous. Am I part of the tinfoil hat set, who thinks the FBI (or some darker, more sinister organization) is going to sneak in and confiscate or clone my drives? Do I have anything on there to hide anyway? Not really. But I do believe strongly in a right to privacy. And if we don’t exercise the rights we do have, we are likely to lose them.
The Disk Encryption HOWTO by David Braun was essential reading, although I didn’t follow its prescriptions precisely. You will need a Linux 2.6 kernel with ‘cryptoloop’ and ‘aes’ compiled in, and the ‘loop-aes-utils’ package that provides crypto-aware versions of ‘mount’ and ‘losetup’.
What happens, essentially, is this: I keep a small unencrypted boot partition near the beginning of the disk. It contains the kernel, the aforementioned ‘loop-aes-utils’, some scripts, a set of keys, and a few other essential binaries: sh, ls, and pivot_root. I configure grub to boot and root from this partition, and provide the kernel with a custom init script. This script prompts the console for a master password (must be 20 or more characters), and uses this to unlock an image containing the keys to each partition. The keys themselves are totally random 60-character strings.
Once the keys are available, the init script uses ‘losetup’ to configure crypto-enhanced loop-back devices for each partition. Then it can unmount the keys, mount the soon-to-be root partition, pivot_root to it, and invoke the real /sbin/init. The remaining partitions will be mounted automatically later on, so long as you use the /dev/loop devices in /etc/fstab, or better yet, refer to them by filesystem label.
LABEL=debian-root / ext3 defaults 0 1
LABEL=linux-home /home ext3 defaults 0 2
LABEL=linux-swap none swap sw 0 0
It sounds fancy, but once I was familiar with the tools and their capabilities, it wasn’t that bad to set up. The HOWTO describes booting off of a USB stick that contains the keys and kernel; this way authentication is based on something you know (master password) and something you have (the USB stick). This was too much of a pain for my home setup, plus my BIOS is too old to boot from USB.
What took the most work was allaying my fears that I’d be totally hosed when something goes wrong with the boot process. It turns out that the current Ubuntu Live CD (6.06) includes a kernel with the required modules. So I can boot from the Live CD, mount my /boot partition, and then manually use the keys to mount my encrypted partitions. The only important thing is to keep a safe backup of the boot partition, especially the keys. If I lose those 60-character keys I really am hosed. Currently I have /boot mirrored on both disks, and the keys file copied on various other machines.
Why not just encrypt /home, or even just $HOME for the current user? Encrypting the root filesystem is something of a pain, involving as it does a pivot_root and delicate boot-time hacking. As the HOWTO points out, a GNU/Linux system really makes no guarantees about information flow; there’s no telling what stuff from /home may show up in /var/log or wherever. So it’s simplest just to encrypt everything, including the swap partition.
So maybe this display of Linux wizardry makes up for my gaffe about iptables earlier in the week.
(Funny that I started this post complaining about the performance of IDE drives, and then proceeded to add a layer of encryption on top of that. I haven’t done extensive benchmarking, but I did run ‘iozone’ a few times, and as far as I can tell the crypto only slows down reads and writes by 1 or 2%.)
Saturday 1 July 2006 @14:54
I just watched a 45-minute ACLU video on how to assert your rights during police encounters. It reviewed the 4th, 5th, and 6th amendments, complete with reenactments and alternate re-reenactments. It was fairly cheesy production-wise, but an important message in my opinion.
One thing that bothered me though, is that in most of the scenarios presented, the targets of police attention actually did appear to be guilty of some crime. The white kids driving to the concert did have pot in the car, for example. They had everything to lose by consenting to a search. And so the video could have been titled “How to get away with doing illegal stuff.”
This is unfortunate, because one could easily come away from watching this video with the all-too-common sentiment “if I’m not doing anything wrong, then I have nothing to fear.” What is much more interesting to me is persuading people that it’s vital that we assert our rights even when we’re not doing anything wrong.
Lately I’ve been trying to promote signed and encrypted email again, among less technical friends. And I routinely encounter the similar sentiment, “My email is just not that personal or interesting.”
I first used email in 1991, and first learned about strong cryptography (PGP) in about 1992. I was thrilled, and I immediately dashed off encrypted messages to my good friends Alice and Bob. If you had told me then that in 15 years, people would still be sending plain text messages out in the open where anyone could read or alter them, I’d have thought you were nuts.
Oh sure, it’s fairly common for computer nerds to have PGP or GPG keys, but in most cases they’re not routinely used for email; it’s just too inconvenient. (They are routinely used in some quarters for signing code; c.f. Debian.) But isn’t it strange that my bank would send me an email with a URL where I can read my latest statement? Why not send the statement directly through the email? Answer: because we have reasonably good, wide-spread encryption standards for the web, but still not for email.
So I tried to look into what wide-spread standards do exist for email, because it certainly isn’t PGP/GPG. I haven’t quite straightened out all the acronyms yet, but it seems like the X509/PKCS7 is fairly common. Thawte offers free personal certificates, so I got myself one. I even met with a network of enthusiasts to get notarized (at a Starbucks on the upper west side). This just means that — in exchange for showing my passport to a couple of strangers — I can now put my real name in my certs, rather than just my email address.
All this stuff is supported fairly well in Apple Mail and the Keychain Assistant. My partner and I now routinely exchange encrypted messages. And now I’ve started signing messages I send to others, to see how their systems deal with it. The results to date are not encouraging.
Anyway, our esteemed president can take credit for my resurgent interest in the bill of rights. One day last month I got so pissed off by some executive transgression or another (sad that I don’t even remember which one) that I joined three organizations on the same day: the ACLU, the Electronic Frontier Foundation, and Americans United for the Separation of Church and State. Do I hear an ‘Amen’?
Oh yeah, the president has even made me appreciate the 2nd amendment more, which I interpret as being primarily about the ability (and responsibility) of the citizenry to overthrow a tyrannical government.
But YMMV, as IANACS.*
*CS = Constitutional Scholar