Note that there are some explanatory texts on larger screens.

plurals
  1. POXOR ciphering works *most* of the time
    text
    copied!<p>I've been tasked with password-protecting a Java app with minimal concern for real security. So it seemed sensible to store username/password pairs in a text file and then encrypt it. For the encryption, it seemed appropriate to use XOR ciphers because they're easy and fast (remember--it just has to discourage the casual user, not be bulletproof).</p> <p>I wrote all the appropriate Java, and then realized I needed a way to encrypt the config file. I wrote an additional method, but it was clunky to use more than once or twice (and seemed to only work for some inputs), so I decided it was best to write something in Python, to be played with at a REPL.</p> <p>This is what I ended up with:</p> <pre><code>from itertools import izip, cycle KEY = "stackoverflow" def encrypt(text): return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(text,cycle(KEY))) def decrypt(text): return encrypt(text) def export(users, file): with open(file, "w") as f: for user, password in users.items(): f.write(encrypt('"%s" "%s"'%(user, password)) + "\n") def import_data(file): with open(file) as f: return [decrypt(i) for i in f.readlines()] </code></pre> <p>On the surface, it works:</p> <pre><code>&gt;&gt;&gt; x = encrypt("Hello world!") &gt;&gt;&gt; x ';\x11\r\x0f\x04O\x01\n\x00\n\x08N' &gt;&gt;&gt; decrypt(x) 'Hello world!' </code></pre> <p>But then things start to fall apart:</p> <pre><code>&gt;&gt;&gt; export({"foo" : "bar", "baz" : "quux", "spam" : "eggs"}, "users.dat") &gt;&gt;&gt; import_data("users.dat") ['"foo" "bar"e', '"baz" "quux"}', '"spam" "eggs"y'] </code></pre> <p>And here's how vim reads it - </p> <p><img src="https://i.stack.imgur.com/nan3F.png" alt="Vim rendition"></p> <p>And then:</p> <pre><code>&gt;&gt;&gt; export({"what" : "not", "this" : "that", "admin_istrator" : "quux"}, "users2.dat") &gt;&gt;&gt; import_data("users2.dat") ['"thi', "k97$ma{~'l", '"what" "not"}', '"admin_istrator" "quux', '7~'] </code></pre> <p>Vim:</p> <p><img src="https://i.stack.imgur.com/dVbJO.png" alt="Vim rendition of the second set"></p> <p>It occurred to me that I might be having a problem with a character's encrypted form being a newline, but as far as I see that doesn't explain the wacky behavior in the first example or <em>all</em> of the wacky behavior in the second one.</p> <p>Regarding the newlines, my Plan B is to encrypt the entire file--newlines and all--and then slurp it back up, decrypt it, split it on "\n", and proceed with my line-based parsing.</p> <p>Thanks in advance.</p> <hr> <p>Update: Here's my implementation of Plan B (described two paragraphs ago).</p> <pre><code>def import2(file): with open(file) as f: return decrypt(f.read()) </code></pre> <p>and then:</p> <pre><code>&gt;&gt;&gt; export({"foo" : "bar", "this" : "that", "admin_istrator" : "letmein"}, "users2.dat") &gt;&gt;&gt; import2("users2.dat") '"this" "that"y%smg&amp;91uux!}"admin_istrator" "letmein"y' </code></pre> <hr> <p>Update Two: Binary.</p> <p>[Code is the same as above, except that all <code>open</code>s are <code>open(file, "rb")</code> or <code>open(file, "wb")</code>.]</p> <pre><code>&gt;&gt;&gt; export({"foo" : "bar", "this" : "that", "admin_istrator" : "letmein"}, "users2.dat") &gt;&gt;&gt; import2("users2.dat") '"this" "that"y%smg&amp;91uux!}"admin_istrator" "letmein"y' &gt;&gt;&gt; import_data("users2.dat") ['"t', "k97$ma{~'", '"foo" "bar"', '"admin_istrator" "letmein"'] </code></pre> <hr> <p>Final update: Base 64, other shenanigans.</p> <pre><code>def import2(file): with open(file, "rb") as f: return filter(str.strip, [decrypt(i) for i in f.readlines()]) </code></pre> <p>where <code>encrypt</code> and <code>decrypt</code> <code>encode</code> in/<code>decode</code> base 64.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload