Reputation: 51787
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.
Upvotes: 37
Views: 7321
Reputation: 171178
C#, 168:
using System.IO;class a{static void Main(string[] b){File.WriteAllBytes(b[0],File.ReadAllBytes(b[0]).Select((x,i)=>x^File.ReadAllBytes(b[1])[i%d.Length]).ToArray());}}
A functional solution. I saved variables by inlining the read operation which causes it to be executed over and over.
Upvotes: 0
Reputation:
Added flush and removed unnecessary seek.
golfed:
#include <stdio.h>
int*p,l;char*k;main(int c,char**v){FILE*f=fopen(*++v,"rb+");k=p=*++v;while(fgets(&l,2,f)){fseek(f,-1,1);putc(l^*k++,f);fflush(f);if(!*k)k=p;}}
ungolfed:
#include <stdio.h>
int*p,l;
char*k;
main(int c,char**v){
FILE*f=fopen(*++v,"rb+");
k=p=*++v;
while(fgets(&l,2,f)){
fseek(f,-1,1);
putc(l^*k++,f);
fflush(f);
if(!*k)k=p;
}
}
Upvotes: 0
Reputation: 5218
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.
Upvotes: 0
Reputation: 892
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)))
Upvotes: 0
Reputation: 15819
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)
Upvotes: 25
Reputation: 1108537
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.
Upvotes: 7
Reputation: 2537
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
Upvotes: 0
Reputation: 37
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)¬ 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)¬ 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
Upvotes: 3
Reputation: 15184
Another
(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
Upvotes: 4
Reputation: 172200
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
.
Upvotes: 3
Reputation: 304117
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)))
Upvotes: 6
Reputation: 304117
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))
Upvotes: 2
Reputation: 35520
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 Went ahead and did it\n
from the input key with k=a.chomp;
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.
Upvotes: 4
Reputation: 15008
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...
Upvotes: 1
Reputation: 118595
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.
Upvotes: 22
Reputation:
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)});
Upvotes: 0
Reputation: 8941
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
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
Upvotes: 0
Reputation: 45057
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!
Upvotes: 2
Reputation: 181705
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
Upvotes: 3
Reputation: 118595
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
Upvotes: 8
Reputation: 47075
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))))
Upvotes: 8
Reputation: 164281
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.
Upvotes: 4
Reputation: 59443
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);}}
Upvotes: 12