views:

1478

answers:

21

From: Encryption Co.
To: x$*sj4 (that's you)

Your mission, should you choose to accept it, is to create a program in the shortest number of keystrokes that

  • Takes two filenames parameters (either command line or stdin), the first is a file containing the key and the second some message. Both files will be plain text.

  • Applies the key to the message using XOR encryption, overwriting the file.

Example:

Input File:

StackOverflow is Cool

Key:

Code Golf

Hex dump of Encrypted Output file:

0000000: 101b 0506 4b08 1909 1425 030b 1200 2e1c  ....K....%......
0000010: 4c25 2c00 080d 0a                        L%,....

For simplicity, assume files can fit in memory


This message will self-encrypt in 5... 4... 3... 2... 1...

     #####
    #### _\_  ________
    ##=-[.].]| \      \
    #(    _\ |  |------|
     #   __| |  ||||||||
      \  _/  |  ||||||||
   .--'--'-. |  | ____ |
  / __      `|__|[o__o]|
_(____nm_______ /____\____ 

XOR Encryption is impossible to crack if the size of the key is greater or equal to the size of the message and the key is generated by an unbiased random process. See: One-time pad. So no "Poor Encryption" here.

+4  A: 

F#, 168 chars

open System.IO
[<EntryPoint>]
let main a=
let k=File.ReadAllBytes a.[1]
let z i v=v^^^k.[i%k.Length]
File.WriteAllBytes(a.[0], Array.mapi z (File.ReadAllBytes a.[0]))
0

Note: Mostly IO, the key is Array.mapi. Also, some F# Guru will probably beat the hell out of this solution - I am a C# programmer by trade, and never used F# for anything else than learning for fun.

driis
You can get rid of entrypoint/main/0 and just have the body of main as 'top-level code', which is good code-golf-savings.
Brian
@Brian, I think (based on 2 minutes of googling), that declaring main is the shortest way to get the command line parameters ? Otherwise I'd have to call Environment.GetCommandLineArgs, which is a whole 30 characters. If there is a better way, please correct me :-)
driis
Oh, I missed that bit - touche!
Brian
Looks good, though I think you switched the command line args around. (The key filename is supposed to come before the message filename.) Also, you need some identation (one space suffices) before the statements in the body of `main`.
bcat
+11  A: 

C# 190 characters

using System.IO;class a{static void Main(string[] b){var c=File.ReadAllBytes(b[0]);var d=File.ReadAllBytes(b[1]);for(int e=0;e<c.Length;e++) c[e]^=d[e%d.Length];File.WriteAllBytes(b[0],c);}}
Jeffrey L Whitledge
Awesome, at least in the ballpark with Python code. Impressive for .Net verbose languages. :)
Russell
+8  A: 

Python, 162 characters

m,r,o=map,raw_input,open
a,b=r(),r()
t,k=m(lambda x:list(o(x).read()[:-1]),[a,b])
o(a,'w').write(''.join(m(chr,m(lambda c:ord(c[0])^ord(c[1]),zip(t,len(t)*k)))))

Python 3, 143 characters

i,o=input,open
a,b=i(),i()
t,k=map(lambda x:list(o(x,'rb').read()[:-1]),[a,b])
o(a,'wb').write(bytes(map(lambda c:c[0]^c[1],zip(t,len(t)*k))))
Federico Ramponi
Epic. I couldn't get mine below 290 :(
hb2pencil
List comprehension is shorter than `map`/`lambda`.
KennyTM
A: 

Python, 154 characters

import sys,struct;_,f,k=sys.argv
open(f,'r+b').write(''.join(struct.pack('B',ord(a)^ord(b))for a,b in zip(open(f,'r+b').read(),open(k,'rb').read()*1000)))
hb2pencil
+20  A: 

Perl, 40 char

It's a little fragile.

print$/=!1,($_=<>)^substr<>x 1E4,0,y///c

Perl has a built-in string xor operator. To solve this problem, the hard part is getting the two strings to have the same length.

$/=!1

Sets the "record separator" to the undefined value, and doesn't cause anything to be printed. With this setting, the file readline operator will slurp in an entire file.

$_=<>

Loads the entire first file (containing the message) into the variable $_.

substr <> x 1E4, 0, y///c

Creates another string out of the second file (the key) and adds it to itself 10,000 times. Hopefully, (1) this really long string will be longer than the message string, and (2) it won't be so long that it causes the program to run out of memory (that's how this solution is fragile). y///c is an operation to count the number of characters in $_, and it's one character shorter than saying length. This shortens the key string to the same size as the message string.

mobrule
Quite mind blowing. Could you include an explanation for us Perl ignorants ?
driis
+1 for the nice play by play.
quixoto
This program doesn't conform to the specifications, it won't overwrite the input message.
rubber boots
+8  A: 

GolfScript, 28 char

n.+/~:k;.,.)k.,@\/)*<{\(@^}%

To use, pass the message file, followed by a new line, followed by the key file to the script's standard input:

$ (cat message-file ; echo ; cat key-file) | ruby golfscript.rb poorencrypt.gs

$ (echo StackOverflow is Cool;echo;echo Code Golf) | \
          ruby golfscript.rb poorencrypt.gs > encoded-file
$ (cat encoded-file;echo;echo Code Golf) | ruby golfscript.rb poorencrypt.gs
StackOverflow is Cool
mobrule
Welcome to the dark side :)
gnibbler
gnibbler
+3  A: 

Haskell, 181 chars

I/O is a bitch when golfing in Haskell, and binary I/O doubly so. This solution can probably be vastly improved. Feel free!

import Data.Bits
import Data.ByteString as B
u=unpack
g o[l,n]=o$pack$Prelude.zipWith xor(u n)(cycle$u l)
f x=mapM B.readFile x>>=g(B.writeFile$x!!1)
main=Prelude.getLine>>=f.words

Usage:

$ ghc --make encrypt.hs
$ echo -n 'Code Golf' > key
$ echo -n 'StackOverflow is Cool' > message
$ echo 'key message' | ./encrypt
$ od -tx1 message
Thomas
Can't you strip of some chars by stripping the `Prelude` prefixes?
FUZxxl
@FUZxxl: No, these functions conflict with identically named functions from `Data.ByteString` (which was designed to be imported qualified). If I recall correctly, importing only the necessary functions turned out to be longer.
Thomas
AFAIK, if you imported them with Prefix, you can still call the Prelude functions without prefix, that's why this "prefix import" exists. (I'm really not shure).
FUZxxl
You would think so, but unfortunately not. At least, GHC 6.12.1 rejects it as ambiguous.
Thomas
+2  A: 

Ruby - 158 chars

def a(b);File.readlines(b).join("\n").chomp;end;t=a($*[0]);k=a($*[1]);File.open($*[0],"w"){|f|0.upto(t.length-1){|i|f.putc((t[i]^k[i.modulo(k.length)]).chr)}}

Prettier version:

def a(b)
    File.readlines(b).join("\n").chomp
end

t = a($*[0])
k = a($*[1])

File.open($*[0],"w") {|f|
    0.upto(t.length - 1) {|i|
        f.putc((t[i] ^ k[i.modulo(k.length)]).chr)
    }
}

This solution takes advantage of the following aspect of the problem:

Your mission, should you choose to accept it, is to create a program in the shortest number of keystrokes that...

This solution was written on my tablet using handwriting recognition for input. No keys were stroked in the creation of this code. Therefore, this program was developed in zero keystrokes. Game over, I win!

bta
There are lots of small improvements to be made here: `a=proc{|b|...}` saves 2 over `def a(b);...;end`. -2 for `t,k=$*.map{|f|a(f)}`. -1 for `File.new` instead of open. -2 for `(t.size-1).times` instead of the upto...
AShelly
And why would you spell out `modulo` vs `%`?
AShelly
+4  A: 

Ruby 72 62 chars

$<.inject{|k,l|l.each_byte{|b|$><<(b^(r=k.slice!0)).chr;k<<r}}

I could save 10 chars if I didn't have to strip a \n from the input key with k=a.chomp; Went ahead and did it

Limitations: only handles single-line keys.

How it works:

$< acts like an array containing all the lines of all the input files.

.inject iterates over the array,

{|k,l| : on the first pass, the arguments are the key line, and the first line of the input.

l.each_byte{|b| takes each character from the input lines as an int.

$><< means "print"

(b^(r.k.slice!0) XORs 'b' with the first character in the key (which it slices off and stores in 'r'

.chr; converts the integer back to ascii

k<<r rotates the first character of the key to the end.

}}The block yields the updated k, which will be used as the first argument in the next pass to inject; the 2nd argument will be the next line of input.

AShelly
So don't do it. Let the newline be part of the key, or use a key file that doesn't end in a newline.
mobrule
The ARGF Object is a adding a newline between the two input files. I'm stripping it to match the sample result. If that's not a requirement, I'll be happy to save the 10 chars.
AShelly
Also, this puts the output on stdout, you need command line magic to replace the input. But if golfscript can get away with that, I don't see why ruby can't.
AShelly
$><< is just begging for a cutesy name.
Jordan
+22  A: 

Repent, 13 7 chars (No file support), 14 char (With file support)

Repent is an esoteric stack-based toy language of my own, with inspiration from J, APL, Golfscript and Python. Here is a short solution. I will explain it, but is very late and this is doing my head in, so I'll explain it and release a Silverlight interpreter in the morning.

↓↷¦*⊕;€

Explanation:

↓     Copies the message string back onto the stack
↷    Puts the extra message string to the bottom of stack
¦     Find length of message string
*     Multiply key array by last number - repeats key for at least as long as message
⊕;    Apply XOR between each element corresponding of message array and repeated 
      key array, pushing XOR encoded message to stack
€     Print encoded message string/(char array) as string.

Use like:

Repent "↓↷¦*⊕;€" "Code Golf" "StackOverflow is Cool" > output.txt

Output (most chars do not display):

Ascii: K    % .L%, 
Hex:   10 1B 05 06 4B 08 19 09 14 25 03 0B 12 00 2E 1C 4C 25 2C 00 08 0D 0A

Using files it is:

↓↶▲⇄▲↓3↔⇄¦*⊕;▼

Language reference (unfinished)

Interpreter (unfinished)

Callum Rogers
Aww, why the downvote?
Callum Rogers
I wasn't the one who downvoted, but it could be because your solution doesn't do file IO.
bcat
Oh. OK then. I need to add support for that :(
Callum Rogers
+1 for coming up with just another weired upn language of your own that nobody but you read or execute. ;)
x4u
I think you can replace the ¦⇄¦⇄ with 香蕉 吗 ... nobody will understand either :D
belisarius
@belisarius Bananas FTW!
Yi Jiang
@Yi Jiang WoW! you speak Repent! :D
belisarius
23 bytes in UTF-8 though.
KennyTM
These are all valid complaints, I suppose I shouldn't golf with it until I have released it.
Callum Rogers
+1 for `esoteric stack-based toy language of my own`
PeterK
@bel yes we have none of them!
bmargulies
A: 

F#, 147 146 characters

This is heavily based on driis's solution. All I did was add the necessary indentation so it compiled, switched the order of the command line parameters, and tightened things up. I wouldn't be surprised if it can still be shortened a little, though. Note: You'll get a warning about incomplete pattern matches. Ordinarily I would be the first to complain about this, but I think code golf deserves an exception to the usual best practices. :)

open System.IO[<EntryPoint>]let m[|a;b|]=File.ReadAllBytes|>fun r->r a|>fun k->File.WriteAllBytes(b,Array.mapi(fun i->(^^^)k.[i%k.Length])(r b));0

F#, 147 characters, more readable

open System.IO
let r=File.ReadAllBytes
[<EntryPoint>]
let m[|a;b|]=
 let k=r a
 File.WriteAllBytes(b,Array.mapi(fun i->(^^^)k.[i%k.Length])(r b));0
bcat
A: 

PHP, 142 141 characters

Edit 1: fputs() instead of fwrite().

$t=fopen($argv[1],'r+');$s=fgets($t);rewind($t);$k=fgets(fopen($argv[2],'r'));for($i=0;$i<strlen($s);$i++)fputs($t,$s{$i}^$k{$i%strlen($k)});

Pretty print:

$t = fopen($argv[1],'r+');
$s = fgets($t);
rewind($t);
$k = fgets(fopen($argv[2],'r'));
for($i=0; $i<strlen($s); $i++)
  fputs($t, $s{$i} ^ $k{$i % strlen($k)});
Mark Trapp
+1  A: 

Java , 336 316 405 chars

EDIT: Forgot that it had to read from a file. *sigh

public class A {
public static void main(String[] a) throws Throwable {
    char[] p = new BufferedReader(new FileReader(a[1])).readLine().toCharArray();
    char[] t = new BufferedReader(new FileReader(a[0])).readLine().toCharArray();
    int u = t.length;
    int k = 0;
    for (int i = 0; i < u; i++) {
        new FileOutputStream (a[0]).write((char) ((int) t[i] ^ (int) p[k]));
        k = k = ++k % p.length;
    }
}
}

It was worth a try. However I don't think Java is the best language here...

TheLQ
`k = k = ++k % p.length;` ?? why not use, this? `k=(k+1)%p.length`
st0le
Also, you don't seem to use `u` in multiple places, so just use `t.length` directly, saves some chars.
st0le
`for (int i=0; i < u; i++) { t[i]^=p[i%p.length]; }` then move the `write` outside the loop,
st0le
You can shorten `int` declarations to `int u=t.length,k=0,i=0;`. Further, all those casts are unnecessary.
BalusC
+7  A: 

Java, 319 313 310 chars


  • Update 1: replaced char[]c=r(a[0]);char[]k=r(a[1]); by char[]c=r(a[0]),k=r(a[1]);, saved 6 chars.

  • Update 2: replaced for(int i=0;i<c.length;c[i]^=k[i++%k.length]); by int i=0;for(char p:c)c[i]^=k[i++%k.length];, saved 3 chars.


import java.io.*;class X{public static void main(String[]a)throws Exception{char[]c=r(a[0]),k=r(a[1]);int i=0;for(char p:c)c[i]^=k[i++%k.length];Writer w=new FileWriter(a[0]);w.write(c);w.close();}static char[]r(String a)throws Exception{return new BufferedReader(new FileReader(a)).readLine().toCharArray();}}

More readable version:

import java.io.*;
class X{
 public static void main(String[]a)throws Exception{
  char[]c=r(a[0]),k=r(a[1]);int i=0;for(char p:c)c[i]^=k[i++%k.length];
  Writer w=new FileWriter(a[0]);w.write(c);w.close();
 }
 static char[]r(String a)throws Exception{
  return new BufferedReader(new FileReader(a)).readLine().toCharArray();
 }
}

Java IO is pretty verbose. Refactoring two file-to-char[] reads into a method saved 4 chars. Yes, closing (flushing) the writer is absolutely necessary. Else the file is left empty. It would otherwise have been 298 292 289 chars.

BalusC
+1 for making a serious attempt in java. there's too little in code golf
seanizer
i managed to save 3 characters...change the `for loop` to `int i=0;for(char p:c)c[i]^=k[i++%k.length];`
st0le
@st0le: Interesting. I updated it as update 2.
BalusC
I was about to scream ripoff, but you take a different approach. +1
TheLQ
I'm impressed that you got something like this below 500 chars. Java is pretty verbose. +1, of course.
Wayne Werner
+2  A: 

Python - 127 chars

uses command line parameters for the keyfile and the datafile

import sys
a=sys.argv
_,k,t=[open(x).read()for x in a]
s=open(a[2],"w").write
[s(chr(ord(x)^ord(y)))for x,y in zip(k*len(t),t)]

writing to stdout - 109 chars

import sys
_,k,t=[open(x).read()for x in sys.argv]
print"".join(chr(ord(x)^ord(y))for x,y in zip(k*len(t),t))
gnibbler
+5  A: 

Python3 - 114 chars

takes parameters from stdin

a=input().split()
k,t=[open(x,"rb").read()for x in a]
open(a[1],"wb").write(bytes(x^y for x,y in zip(k*len(t),t)))
gnibbler
+1. So far, yours seems to be the shortest non-esoteric solution that actually conforms to the specification (= overwriting the input file).
Heinzi
+1  A: 

PowerShell, 125 115 chars

So far, this seems to be the shortest .net-based answer:

$k=[char[]](gc $args[1]);$i=0;sc $args[0] ([byte[]]([char[]](gc $args[0])|%{$_ -bXor $k[$i++%$k.Length]})) -en byte

Pretty version with command abbreviations spelled out:

$k=[char[]](get-content $args[1])
$i=0
set-content `
   $args[0] `
   ([byte[]] ([char[]] (get-content $args[0]) `
              | foreach {$_ -bXor $k[$i++ % $k.Length]})) `
   -encoding byte

Usage: powershell codegolf.ps1 message.txt key.txt. As requested, it overwrites message.txt.

Heinzi
+4  A: 

Another

Perl solution, 59 (42) chars

(conforming one-liner that seems to work so far:)

Program (59 chars) with computed key length:

 $.-1?$_^=substr($k x((length)/length($k)+1),0,length):$k=$_

will be 42 chars if using mobrule's 'fragile' approach to key length:

 $.-1?$_^=substr($k x 1e4,0,(length)):$k=$_

Command Line:

 $> perl -i -0777 -pe'<insert above>' keyfile messagefile

This will rewrite the message to its xor-ed form and back to it's clear text form:

 $> cat keyfile ; cat messagefile

 Code Golf
 StackOverflow is Cool

Apply command:

 $> perl -i.bak -0777 -pe'<insert above>' keyfile messagefile
 $> cat keyfile ; cat messagefile

 Code Golf
 ^P^[^E^FK^H^Y   ^Tl/^@^SEI4O/   e/e

Apply again:

 $> perl -i.bak -0777 -pe'<insert above>' keyfile messagefile
 $> cat keyfile ; cat messagefile

 Code Golf
 StackOverflow is Cool

Regards

rbo

rubber boots
+3  A: 

q, 88 char

Implemented using q from http://kx.com/ which is a language written by Arthur Whitney and inspired by APL and lisp.

a[0]1:"x"$2 sv'{(x|y)&not x&y}.'0b vs''flip{y:count[x]#y;(x;y)}.(read1')a:(hsym')`$'.z.x

So a little explanation of what is going on: (read Right to Left)

a:(hsym')`$'.z.x

Creates a list of two file handles from a list of runtime arguments and saves it for later use in variable "a".

(read1')

Loop over the two files, read them and return a list of list of bytes where byte=0x00..0xFF ((22 bytes),(10 bytes))

{y:count[x]#y;(x;y)}.

Shape the key to the same length as message. Key is truncated if too long and repeated if too short. The list is now well formatted, 2x22.

flip

Transpose the list and it's now 22x2.

0b vs''

Convert every element of the list to binary type

{(x|y)&not x&y}.'

XOR pair wise across all 22 elements, returns a list of list of 8 boolean

"x"$2 sv'

Convert 8 boolean bits to byte.

a[0]1:

Write file, overriding original message file.

Sample run:

$ cp message.txt message.txt.bk
$ q g.q message.txt key.txt    
$ diff -s message.txt message.txt.bk0
Binary files message.txt and message.txt.bk0 differ
$ q g.q message.txt key.txt          
$ diff -s message.txt message.txt.bk0
Files message.txt and message.txt.bk0 are identical
md0
A: 

KSH93 - 152 chars

m=$(<$1)
k=$(<$2)
for ((e=0;e<${#m};e++)) 
do
out="$out$(printf "%02X" $(("'${m:$e:1}"^"'${k:${e}%${#k}:1}")))"
done
echo "${out}0d0a" | xxd -p -r >$1
fpmurphy
A: 

Java - 306 Chars

Using BalusC's Java solution as a base:

import java.io.*;class X{public static void main(String[]a)throws Exception{final char[]c=r(a[0]),k=r(a[1]);int i=0;for(int p:c)c[i]^=k[i++%k.length];new FileWriter(a[0]){{write(c);}}.close();}static char[]r(String a)throws Exception{return new BufferedReader(new FileReader(a)).readLine().toCharArray();}}

More readable:

import java.io.*;
class X{
 public static void main(String[]a)throws Exception{
  final char[]c=r(a[0]),k=r(a[1]);int i=0;for(int p:c)c[i]^=k[i++%k.length];
  new FileWriter(a[0]){{write(c);}}.close();
 }
 static char[]r(String a)throws Exception{
  return new BufferedReader(new FileReader(a)).readLine().toCharArray();
 }
}

I didn't actually test the code, but I also didn't change anything drastic.

Andy