Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

8-bit XOR encryption takes a single byte and XORs every byte in the file by that byte. Here is a reference program in C++:

/*xorcipher.cpp
 *Encrypts a file using 8-bit xor encrytpion
 */

#include <iostream>
#include <fstream>
#include <stdlib.h>
using namespace std;

int main(int argc, char** argv){
   ifstream* in = NULL;
   ofstream* out = NULL;

   if(argc < 3){
      cerr << "Usage: xor <key> <filename...>" << endl;
      exit(1);
   }

   int key = atoi(argv[1]);

   for(int x = 2; x < argc; x++){
      in = new ifstream(argv[x], ios::binary);
      if(!in->good()){
         cerr << "Error reading from " << argv[x] << endl;
         exit(1);
      }

      //Get file size
      in->seekg(0, ios::end);
      int size = in->tellg();
      in->seekg(0, ios::beg);

      //Allocate memory
      int* data = new int[size];

      int c = 0;
      for(int y = 0; (c = in->get()) != EOF; y++)
         data[y] = c ^ key;

      in->close();
      delete in;
      in = NULL;

      out = new ofstream(argv[x], ios::binary);
      if(!out->good()){
         cerr << "Error writing to " << argv[x] << endl;
         exit(1);
      }

      for(int y = 0; y < size; y++)
         out->put(data[y]);

      out->flush();
      out->close();
      delete out;
      out = NULL;

      delete[] data;
      data = NULL;
   }
   cout << "Operation complete" << endl;

   return 0;
}

The shortest answer (whitespace doesn't count) that produces the same end result will be selected. It does not have to store everything in memory at once or open and close every file multiple times. It can do anything as long as a file encrypted with the reference program can be decrypted with the answer, and vice versa.


Edit: The above program is not a specification. The only requirement is that answers should be able to decrypt a file encrypted with the above program, and the above program should be able to decrypt a file encrypted with the answer. I'm sorry if that was unclear.

The above program can be compiled with:

g++ xorcipher.cpp -o ~/bin/xor

It can be run like this:

xor <key> <filename...>

For example, if the key is 42 and the file is alpha.txt, you would use:

xor 42 alpha.txt
share|improve this question
2  
A 10-line specification which gives acceptance criteria is a lot more useful than a 60-line program in a language which not everyone knows. –  Peter Taylor Dec 20 '12 at 7:58
3  
You know that saying 'whitespace doesn't count' means there's going to be a 0-character solution in Whitespace, right? –  marinus Dec 20 '12 at 17:22

7 Answers 7

up vote 4 down vote accepted

PHP 40 38 bytes

<?for(;;)echo@~fgetc(STDIN)^~$argv[1];

And updated version. Now handles all inputs correctly, and 2 bytes shorter as well.

Sample usage:

$ more in.dat
This is a test.
This is only a test.

$ php xor-cipher.php A < in.dat > out.dat

$ more out.dat
§)(2a(2a a5$25oK§)(2a(2a./-8a a5$25o

$ php xor-cipher.php A < out.dat
This is a test.
This is only a test.

Perl 30 bytes

$k=pop;s/./print$&^$k/egsfor<>

I/O is the same as for the PHP solution above.

share|improve this answer
    
+1: Beautiful solution. –  mjgpy3 Dec 20 '12 at 6:23
    
Does it work if the output contains a zero character? (e.g. encrypt This is a test with the key T)? –  ugoren Dec 20 '12 at 19:25
    
The Perl solution will work for all cases. The PHP will terminate prematurely if the generated character becomes a 0 (not character 0, literally a 0). I'll update my answer. –  primo Dec 20 '12 at 20:01

C, 61 59 bytes

Quite simple, and very similar to primo's solution.
First parameter is the key, in decimal, reads stdin, writes stdout.
The only tricky part is using ~getchar, so EOF becomes 0 and terminates the loop, then printing c^~key, where the additional ~ undoes the previous one.

main(c,v)int*v;{
    while(c=~getchar())putchar(c^~atoi(v[1]));
}
share|improve this answer
    
I like the bit inversion trick. Would ~c=getchar() also work (thereby saving the second inversion)? –  primo Dec 20 '12 at 9:00
    
@primo, ~(c=getchar()) works, but the parentheses are needed. The second inversion saves them. –  ugoren Dec 20 '12 at 9:01

Brainfuck - 269

,>,[<[>>+>+<<<-]>>>[<<<+>>>-]>>>++++++++[-<<<<<[->>+<<[->>->+<]>>[->>>
>+<<]<<<<]>>>[-<<<+>>>]<<[->+<[->->+>>>>>]>[->>>>>+>>]<<<<<<<<]>>[-<<+
>>]>>>[->>+<<]>[>[-<->]<[->+<]]>[[-]<<<[->+>-<<]>[-<+>]+>+++++++[-<[->
>++<<]>>[-<<+>>]<]<[->>>>+<<<<]>>]<<<]>>>>>.[-]<<<<<<<<<<,]
share|improve this answer

Python, 78 chars

from sys import argv as v

print ''.join(chr(ord(v[1])^ord(i)) for i in open(v[2]).read())

Must be run like:

python solution.py <key> <input_file> > <output_file>

Where solution.py is the python file that contains the above code, key is the single byte to XOR, input_file is the file to be encrypted and output_file will contain the decrypted output.

I am not sure if it matches your solution (as per "...that produces the same end result will be selected") since your example doesn't seem to produce output. However, it does successfully decrypt an encrypted file with the same key byte.

Since whitespace doesn't count, I used the following code to count chars:

>>> with open('solution.py') as f:
...     text = f.read()
... 
>>> len(text) - text.count('\n') - text.count(' ') # There are no tabs in this code
78
share|improve this answer
    
+1 You broke the ground here. :) –  luser droog Dec 20 '12 at 11:41

Python 75

import sys
for j in sys.stdin:print''.join(chr(int(sys.argv[1])^ord(i))for i in j),

The hardest requirement was not to keep the whole file in memory.

Usage:

python xor.py 123 <file.in >file.out
share|improve this answer
    
I only said it didn't have to keep the file in memory. This means it could. –  ctype.h Dec 20 '12 at 19:16

GolfScript, 16 characters

"#{$*}"~{^}+%:n;

Usage is as given above - the key (numeric) passed as parameter while input/output is through console:

golfscript.rb xor.gs 42 <in.txt >out.txt

Edit: The issues with the trailing newline are now solved.

share|improve this answer

Postscript 101 67

(]){exch def}def
ARGUMENTS aload pop(w)file/O](r)file/I]cvi/K]{O I read not{exit}if K xor write}loop

The 67 byte version is equivalent to the above with all executable system names replaced by binary tokens. It is produced as output by this program (which shows a hex representation).

(xorb.ps)(w)file
<
    285D297B923E92337D9233
    415247554D454E54539202927528772992412F4F5D
    28722992412F495D922C2F4B5D
    7B4F2049927B92707B92407D92544B92C192BC7D9265
>
writestring

Invoke with ghostscript's argument-processing option --.

josh@Z1 ~
$ gs -dNODISPLAY -- xorw.ps
GPL Ghostscript 9.06 (2012-08-08)
Copyright (C) 2012 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.

josh@Z1 ~
$ xxd xorb.ps
0000000: 285d 297b 923e 9233 7d92 3341 5247 554d  (]){.>.3}.3ARGUM
0000010: 454e 5453 9202 9275 2877 2992 412f 4f5d  ENTS...u(w).A/O]
0000020: 2872 2992 412f 495d 922c 2f4b 5d7b 4f20  (r).A/I].,/K]{O
0000030: 4992 7b92 707b 9240 7d92 544b 92c1 92bc  I.{.p{.@}.TK....
0000040: 7d92 65                                  }.e

josh@Z1 ~
$ gs -dNODISPLAY -- xorb.ps 42 xor.ps xor.ps.out
GPL Ghostscript 9.06 (2012-08-08)
Copyright (C) 2012 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.

josh@Z1 ~
$ gs -dNODISPLAY -- xorb.ps 42 xor.ps.out xor.rev
GPL Ghostscript 9.06 (2012-08-08)
Copyright (C) 2012 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.

josh@Z1 ~
$ diff xor.ps xor.rev

josh@Z1 ~
$
share|improve this answer
    
Subtracting whitespace only gives me -10. :( –  luser droog Dec 20 '12 at 6:53
    
There's only 1 byte of whitespace in the binary version, between the O and the I. –  luser droog Dec 22 '12 at 6:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.