Wayne Werner
Wayne Werner

Reputation: 51787

Code Golf: XOR Encryption

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

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

Answers (23)

usr
usr

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

user295190
user295190

Reputation:

C - 163 161 chars

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

Andy
Andy

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

hb2pencil
hb2pencil

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

Callum Rogers
Callum Rogers

Reputation: 15819

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)

Upvotes: 25

BalusC
BalusC

Reputation: 1108537

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.

Upvotes: 7

fpmurphy
fpmurphy

Reputation: 2537

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

Upvotes: 0

md0
md0

Reputation: 37

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

Upvotes: 3

rubber boots
rubber boots

Reputation: 15184

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

Upvotes: 4

Heinzi
Heinzi

Reputation: 172200

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.

Upvotes: 3

John La Rooy
John La Rooy

Reputation: 304117

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)))

Upvotes: 6

John La Rooy
John La Rooy

Reputation: 304117

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))

Upvotes: 2

AShelly
AShelly

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 \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.

Upvotes: 4

TheLQ
TheLQ

Reputation: 15008

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...

Upvotes: 1

mob
mob

Reputation: 118595

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.

Upvotes: 22

user113292
user113292

Reputation:

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)});

Upvotes: 0

bcat
bcat

Reputation: 8941

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

Upvotes: 0

bta
bta

Reputation: 45057

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!

Upvotes: 2

Thomas
Thomas

Reputation: 181705

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

Upvotes: 3

mob
mob

Reputation: 118595

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

Upvotes: 8

Federico A. Ramponi
Federico A. Ramponi

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

driis
driis

Reputation: 164281

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.

Upvotes: 4

Jeffrey L Whitledge
Jeffrey L Whitledge

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

Related Questions