This operation is sometimes called modulus 2 addition (or subtraction, which is identical). With this logic, a string of text can be encrypted by applying the bitwise XOR operator to every character using a given key. To decrypt the output, merely reapplying the XOR function with the key will remove the cipher.
XOR Encryption is an encryption method used to encrypt data and is hard to crack by brute-force method, i.e generating random encryption keys to match with the correct one.
The simple XOR cipher isn't used in production because it is impractical to use keys that are the same length as the message body. However, the XOR is still extremely useful. In fact, it is used in almost all symmetric encryption algorithms. XOR is the primary operation in the “add round key” step of AES-256.
The problem with XOR encryption is that for long runs of the same characters, it is very easy to see the password. Such long runs are most commonly spaces in text files. Say your password is 8 chars, and the text file has 16 spaces in some line (for example, in the middle of ASCII-graphics table).
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)
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.
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);}}
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))))
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
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.
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)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With