Ian Bicking: the old part of his blog

Homebrew encryption

I wrote a simple cryptographic algorithm this evening. Specifically it is meant to encrypt passwords into cookies, to allow for persistent logins. These were some of the requirements that made me want to roll my own:

Maybe this already exists, but most of the algorithms I've seen either aren't secure (e.g., rotor) or aren't compact. And anyway, it seemed fun. I'd be very curious if anyone sees particular vulnerabilities with this algorithm (besides the fact that it should only encrypt short plaintexts). The code is in simplecrypt.py. The algorithm:

First take the plaintext and encode it so that it is of minimum length and aligned in some way. By default it must be 10 characters long, and aligned to the next 5 characters (e.g., a 12 byte string becomes 15 bytes). Random characters are added to the end, and at least one random character is always used. We add a leading character telling what the actual length of the string is. (This way a very short password will not appear particularly short when encrypted.) This is the encoded plaintext.

Take a hash of the encoded plaintext and the key, possibly truncating it to save space. We will call this hash the signature.

Take an sha hash of the signature and the key. This hash will be the encoding key.

XOR the encoding key with the encoded plaintext. Prepend the signature. This is the full ciphertext.

Reverse the steps to decrypt. I use the SHA hash, which is 20 characters long. I think any plaintext over 20 characters could be vulnerable, since we have to reuse the encoding key when XORing it with the plaintext, and patterns may emerge.

Anyway, this seemed pretty simple, and seems to fit the bill. Am I missing anything?

Created 02 Jun '04
Modified 14 Dec '04


Remember that (A XOR C) XOR (B XOR C) is A XOR B, so yes, even a little bit of key reuse is bad.

Why aren't you just using HMAC? You probably already have a library for it...

I notice that I've acquired the habit of twitching violently when anyone says something like "homebrew encryption." I wonder where I picked that up.
# Karl

import hmac
# Fredrik

Python 2.2 does indeed have an hmac library -- I hadn't noticed it before. But I don't see how it changes much -- HMAC just seems to be a way to sign things, and an HMAC is not noticeably different than hashing the concatenation of the key and plaintext (except it standardizes aspects). Standardizing my homebrew encryption isn't that important ;)

Note that the key is in all cases secret, and is not reused. So (A XOR C) XOR (B XOR C) wouldn't happen -- i.e., someone couldn't submit a known plaintext (B), and use that to decode (A XOR C), since the two messages would actually be (A XOR C1) and (B XOR C2). But I think if, say, you had a 200 character plaintext, and a 20 character hash, you could potentially find out what the hash is, since character 1, 21, 41, 61, 81, 101, 121, 141, 161, and 181 would have been XORed with the same value, and you could start to guess (using knowledge about the likely distribution of characters) what that value of the key/mask had been. This would still only allow you to break that one message -- the key would remain secret even after a successful brute-force attack of this style.
# Ian Bicking

A SHA hash is a one way function. Why go through an encryption scheme, when no one can really get back to the original password? Use a SHA1 hash of the password and be done with it.
# Ryan

Because hashed passwords are hard to work with. Frequently a password is stored in a hashed form, so you'd have to be sure to hash the cookie in the exact same way, or do some sort of double-hashing. There are also many situations where you need the actual password to authenticate the person.

I have thought about storing some more arbitrary authentication, though -- basically hashing the username with a secret key. Then this would take the place of a password -- we'd rely on the fact that sometime in the past (when we originally set the cookie) the user had authenticated themself, and this the signed hash proves it is the same user. (Well, actually just the same browser, but that's a different issue)

If you store the password you also allow a person to implicitly invalidate persistent logins by changing the account's password.
# Ian Bicking

google for python crypto oneliners. There is ARC4 as line or two.
# Niki Spahiev

Never, ever, write your own encryption algorithm and assume it's secure. It never is. Try using one of the existing, proven ones. And keep the key secure. Blowfish might be a good bet. It's faster than AES/rijndael, and pretty secure.
# Frederik De Bleser

But Blowfish turns my iddy bitty 8-character password into 118 characters! Looking at the cookie standards, that's still well within the size limit, so maybe that's not so bad. Well, maybe that's not even true, it seems to be a particular implementation of Blowfish, which may be adding filename, a hash, and other information to the encrypted stream. The raw algorithm seems to cause little expansion (using this module: http://bofh.concordia.ca/blowfish.py )
# Ian Bicking

It might make it a bit more secure if you put the random chars at the begining instead of at the end.

But I think for any real security, one should use a proven algorythm.

I like this though because its light weight and would provide enough security as needed non widespread use, certain situations.

I tried to make one similar myself for storing passwords in inifiles, but I couldn't make it as secure as I wanted, so I just stored them xored with the repeating username then base64 encoded. (Oh no now my secrets out!)

No flames for the above insecure algorythm please, its just a step up from plain text It's just to protect against nosey pc repair guys. Even if they get the password, they have to build a twisted PB program to use it, and as soon as they do we'll know and change it.

Now that I've shared this info, I think I'll have to start using blowfish or something!. I think I'll use the hash of the username appended with a hardcoded key.

Thanks for sharing your algorythm.
# Matthew Sherborne

I've found that security via obscurity seems to be the only way to deal with some situations, particularly when you have a program that stores a password and needs to be able to get the plaintext password on its own, as in a client that does something on behalf of some user. You can use whatever encryption, but it doesn't really matter, because on some level you have a plaintext key. Passwords are secure only because our brains are an exceptionally obscure storage medium.

This is why DRM schemes are breakable -- it's certainly not that the designers don't understand encryption algorithms (DVD's CSS aside).
# Ian Bicking

Speed should not be an important requirement especially for small messages of the kind found in cookies. For less than a couple hundred bytes... speed won't matter.
# Larry

I've seen performance issues when encrypting credit card numbers, so speed is definitely a concern. That was public-key encryption, which is typically much slower, but I've noticed similar issues with the pure-Python AES implementation.
# Ian Bicking

BUT why send the password in the cookie in the first place. It is so much easier (and IMHO more secure) to just store the password locally and send a session id in the cookie. That way you have the possibility to add more 'cookie' data as you go along without having to send it all in a cookie.
Beats encryption anytime.

# Rob

Please do yourself a favor and read Applied Cryptography.