The routine posted by Evgeniy works well, but it's essentially a simple substitution cypher, so it's not very secure. What Microsoft did many years ago was use double substitution, using two keys. One key was 13 characters long and the other 11. I haven't coded this in lisp, so here's a flow chart. The index for the first character in a string is 0.
1. Initialixe x, y, and z each to 0
2. Get character #x from the string to encrypt or decrypt
3. Get character #y from the first key
4. XOR the characters from steps 2 and 3.
5. Get character #z from the second key
6. XOR the result from step 4 with the character from step 5.
7. Add the result from step 6 to the output steing.
8. Increment x by 1. If x > the length of the input string, you're done.
9. Increment y by 1. if y > the length of the first key reset y to 0.
10. Increment z by 1. if y > the length of the second key reset z to 0.
11. Go to step 2.
Evgeniy's routing uses a single character [128] as a key. By using two keys of 13 and 11 characters you get an effective key length of 143 characters, which is much more secure.
An XOR substitution works here because it's bidirectional:
01000001 XOR 00100011 = 01100010 (that's ASCII codes for 'A' XOR '#', which equals 'b')
01100010 XOR 00100011 = 01000001 (that's ASCII codes for 'b' XOR '#', which equals 'A')
I selected ASCII codes so that everything in the example is normal, printable characters.
If you use two keys it doesn't matter which key is used first:
(01000001 XOR 00100011) XOR 01010101 = 00110111
(01000001 XOR 01010101) XOR 00100011 = 00110111