Keyczar: Easy Encryption in Python (and others)

Nov. 9, 2010, 5:18 p.m.

 

Encryption is one of those things that can be really hard to do correctly. Using a good encryption library, however, can make things a little easier for you. You should look for one that has a simple API and sane defaults. Of course, it's also important that they correctly use the ciphers, but the best advice I have for that one is to try to pick an open source library that a lot of people use.

I really like Keyczar, and use it whenever I need to encrypt stuff. They have bindings for several languages, but I've only ever used the Python version. You can look at the site for the documentation, but I just want to show you the few pieces of it that I use frequently. I'm going to try to keep this pretty high-level and just show you the basics. Definitely look into the documentation if you want to do anything more advanced.

API Layout

For the parts of Keyczar that I use, the API is very friendly. Most of the key classes reside in keyczar.keys and that's generally the only place from which I import. There are a bunch of key classes available, but I tend to use either RSA keys (RsaPrivateKey, RsaPublicKey) or AES keys (AesKey).

The key classes have a static method named Generate() that generates a key of that type (with reasonable defaults). An instance of a key will usually have Encrypt(), Decrypt(), Sign(), or Verify() functions depending on the type of key.

Asymmetric Keys

Usually when I need to use asymmetric encryption I use RSA. First, you need to generate a keypair:

>>> from keyczar.keys import RsaPrivateKey
>>> k = RsaPrivateKey.Generate() # usually I just use the default parameters
>>> k
<keyczar.keys.RsaPrivateKey object at 0x13e0b50>
>>> k.size  # default RSA key size is 2048
2048
>>> k.public_key  # this is asymmetric encryption, so here's the public key
<keyczar.keys.RsaPublicKey object at 0x13e0bd0>

I just used the default settings when generating this key, but you can also pass some parameters (like size) to the Generate() function. This gives us both an RsaPrivateKey and the corresponding RsaPublicKey. You can perform encryption like so:

>>> pub_key = k.public_key  # can only use the public key for encryption
>>> ciphertext = pub_key.Encrypt('whatever data you want encrypted')
>>> k.Decrypt(ciphertext)  # pretty easy, huh?
'whatever data you want encrypted'

IMPORTANT NOTE: You can only use the Public Key for encryption. Calling Encrypt() on the private key actually uses the public key. You'll notice there's no Decrypt() function on the public key.

I believe it pads and salts the data for you as well, so you don't have to worry about that.

You can also create a signature for a message:

>>> signature = k.Sign('my message')
>>> k.public_key.Verify('my message', signature)
True
>>> k.public_key.Verify('not my message', signature)
False

Symmetric Keys

When you have more than just a little bit of data to encrypt, you should use a stream cipher like AES.

>>> from keyczar.keys import AesKey
>>> k = AesKey.Generate() # using the default parameters again
>>> k
<keyczar.keys.AesKey object at 0x196dc50>
>>> k.size  # default AES key size is 128
128
>>> str(k.mode)  # default AES mode is CBC
'CBC'

The encryption and decryption works pretty much like before:

>>> ciphertext = k.Encrypt('whatever data you want encrypted')
>>> k.Decrypt(ciphertext)
'whatever data you want encrypted'

Storing Keys

So, I think there's some way of storing and managing keys using classes in keyczar.keyczart, but I never do it that way... it seems way too complicated for me. Instead, they provide a simple way to serialize keys to JSON. Just convert the key to a string, and out comes the JSON. Of course you can also easily import keys that have been dumped to JSON; each key class has a static method called Read() that does just that. This works for all of the types of keys that I've used so far (including RsaPublicKey objects).

>>> k
<keyczar.keys.AesKey object at 0x196dc50>
>>> str(k)
'{"hmacKey": {"hmacKeyString": "ONkkhdkmGaZY4hLmUAfLy-_klfCIX4vqjndI6DTkTWI",
"size": 256}, "aesKeyString": "0w7wZcSjB752DSGuUnh_Bg", "mode": "CBC", "size":
128}'
>>> k2 = AesKey.Read(str(k))
>>> k2
<keyczar.keys.AesKey object at 0x1c3b510>
>>> k == k2
True

So that's usually what I use for my encryption needs. There are a bunch of other crypto libraries out there, but so far I like Keyczar the most. I also like the fact that there are bindings for other languages (currently Java and C++), and from what I gather, I think that it's something written by Google that they use internally. There's a lot more to it, and I'll do another blog post if I ever have a need to figure out the more complex stuff it offers like key rotation, versioning, and whatever else it does.