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
Yeah, the code at the top doesn't include any of the suggestions from the commenters - I feel a tad disingenuous modifying it as none of the improvements were mine! What's protocol here? Subzey's last comment is the definitive version
(incidentally a JS vignere cypher was the first piece of script I ever wrote as a kid - it's amazing to see what that original monster has been condensed down to!)