In 138b, this will encrypt/decrypt anything using the Vigenère cypher. Input is entered as solely lower case letters (no numbers, spaces, special characters etc). Outputs may be verified against http://sharkysoft.com/misc/vigenere/
As described on http://ub.ly/um (the parser chokes on the full URL), the essence of the Vigenère cypher is that it is a cyclic version of the Caesar shift cypher. It's not unbreakable but it's pretty good. Also, as a corollary we get rot13 (use "n" as an encoding parameter - yes, as originally defined there's a one byte offset from what you might expect...) and of course Caesar.
My initial attempts were encryption only (138b):
function(j,s,h,g,i,n){for(g="",i=0;i-j.length;g+=String.fromCharCode(n?n+64:90))n=(j.charCodeAt(i)+s.charCodeAt(i++%s.length)+15)%26;h(g)}
and encryption + decryption (151b):
function(j,s,h,t,g,i,n){for(g="",i=0;i-j.length;g+=String.fromCharCode(n?n+64:90))n=(j.charCodeAt(i)+t*s.charCodeAt(i++%s.length)+(t>0?15:27))%26;h(g)}
with t=+/- 1 being encryption/decryption. Thanks to all the help in the comments (especially @subzey!) this is now down to 138b, with both encryption and decryption.
The phrases "fromCharCode", "charCodeAt" and "String" are FAR too long =(
Savings don't always come where you expect them to (see @jed's ultimately unused 'harCode' hack in the comments). In fact, from my experience so far in 140byt.es, they most often come from some slight (or indeed major!) reworking of the algorithm (c.f. the successive contributions to fibonacci, base64 enc/dec etc).
http://esparser.qfox.nl/ is amazing
@jed: Thanks, I have no idea how I missed that!
Good call on the caching; my first count suggested I'd actually lose bytes (as the declaration plus semicolon is actually quite long and fromCharCode is only used twice). In fact, it does save a single byte, unless I find a better place to shave that semi colon!
[Edit]Oh hmm on second thoughts I need another two bytes for the x="charCodeAt" trick to avoid polluting the global scope - I do indeed lose 1 byte!
@mikesherov: are you sure your first suggestion works? It errors on Chrome for me.
I'll update the letters; originally they had meaning (e.g. j would have been 'i' for input, except that i was already used for iterating etc).
149b: