Implement a One-Time Pad
GolfScript, 53 chars
n%(0=2%{~.,[{26rand 65+}*]:K]}*zip{{-}*~)26%65+}%K]n*
This is a task for which GolfScript seems just about perfectly suited.
To keep the code short, I'm using the same code for both encryption and decryption: to decrypt, I subtract the key from the ciphertext, while for encryption, I first generate a random ciphertext and then subtract the plaintext from it. Even so, the extra code for implementing encryption mode takes just a little over half the length of the program.
De-golfed version with comments:
n % # split input into an array of lines
# KEY GENERATION FOR ENCRYPTION MODE:
( # extract the first line from the array
0 = 2 % # check if the first char of that line is odd (E = 69)...
{ # ...and execute this block if it is:
~ # dump the remaining lines (of which the should be only one) on the stack
. , # calculate the length of the last line...
[ { 26 rand 65 + } * ] # ...make an array of that many random letters...
:K # ...and assign it to K
] # collect all the lines, including K, back into an array
} *
# ENCRYPTION / DECRYPTION ROUTINE:
zip # transpose the array of 2 n-char strings into n 2-char strings...
{ # ...and execute this block for each 2-char string:
{-} * # subtract the second char code from the first
~ ) # negate the result (using the two's complement trick -x = ~x+1)
26 % 65 + # reduce modulo 26 and add 65 = A
} %
# OUTPUT:
K ] n* # join the result and K (if defined) with a newline, stringifying them
Ruby (200 185)
sample runs + wc:
$ ruby onetimepad.rb
ENCODE
ANOTHERTESTINPUTZZZ
ZYCLGHDWLDASFUTHWKC
BPMIBXOXTPTQIVBMDPX
$ ruby onetimepad.rb
DECODE
ZYCLGHDWLDASFUTHWKC
BPMIBXOXTPTQIVBMDPX
ANOTHERTESTINPUTZZZ
$ wc onetimepad.rb
4 7 185 onetimepad.rb
def f;gets.scan(/./).map{|b|b.ord-65};end
s=->a{a.map{|b|(b+65).chr}*''}
r=->b,a,o{s[a.zip(b).map{|a,b|(a.send o,b)%26}]}
puts(gets=~/^D/?r[f,f,:+]:[s[k=(p=f).map{rand 26}],r[k,p,:-]])
APL (Dyalog Unicode), 46 bytes
⎕A[26|{'N'∊⍞:⍉x,⍪(⎕A⍳w)+x←26?⍨⍴w←⍞⋄-⌿⎕A⍳↑⍞⍞}1]
Try it online!
The current full program is the result of a 2hr long session at The APL Orchard., with a lot of golfing input from Adám (-13 bytes!).
Requires ⎕IO←0
(0-indexing).
Explanation
⎕A[26|{'N'∊⍞:⍉x,⍪(⎕A⍳w)+x←26?⍨⍴w←⍞⋄-⌿⎕A⍳↑⍞⍞}1]
{ }1 inner fn(called with junk param)
⍞ first input
'N'∊ is 'N' present in it?
:⍉x,⍪(⎕A⍳w)+x←26?⍨⍴w←⍞ if so, eNcrypt:
w←⍞ store message in w
26?⍨⍴ generate 26 random numbers,
x← store in x
(⎕A⍳w)+ add that to the indices in the alphabet
⍪ table them
x, join with the random numbers
⍉ transpose to get key and encrypted value
⋄-⌿⎕A⍳↑⍞⍞ else, decrypt:
⍞⍞ input key and value
↑ convert to matrix
⎕A⍳ get the indices of both in the alphabet
-⌿ difference of all columns
26| mod the result of the inner fn.
[ ] index the result of the program in
⎕A the capitalized alphabet.