Skip to content

Commit

Permalink
Experimenting with 1-dimensional maps and improved command line inter…
Browse files Browse the repository at this point in the history
…face
  • Loading branch information
Patrick Cieplak committed Apr 3, 2016
1 parent 1d372f2 commit 1f04142
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 127 deletions.
28 changes: 10 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,33 @@
# Yorke

Yorke is an experimental encryption library and command-line tool.
Yorke is an experimental stream cipher library and command-line tool.

# Usage

Encrypt a file using a randomly generated pad. The encrypted cipher text is
sent to STDOUT and the random pad is sent STDERR:
Encrypt a message with a random pad:

```
cat plain.txt | yorke random_pad 1> cipher.txt 2> key.txt
cat plain.txt | yorke rp 1> cipher.txt 2> key.txt
```

Decrypt a file using a previously generated pad:

```
yorke file_xor cipher.txt key.txt > plain.txt
yorke fxor key.txt cipher.txt > plain.txt
```bash
yorke xor <(echo "secret message") <(cat /dev/urandom | tee key.txt) > cipher.txt
yorke xor cipher.txt key.txt
```

# Installation

```
```bash
git clone https://github.com/ldgr/yorke.git
cd yorke
python setup.py install
```

# Testing

Library:
```
Run library tests:
```bash
pip install nose
nosetests
```

Command:
```
Run command tests:
```bash
./test.sh
```
56 changes: 24 additions & 32 deletions bin/yorke
Original file line number Diff line number Diff line change
@@ -1,52 +1,44 @@
#!/usr/bin/env python
import argparse
import hashlib
import sys

from yorke import RandomPad, Xor, byte_by_byte


def random_pad(args):
input = byte_by_byte(sys.stdin)
rp = RandomPad().encrypt_bytes(input)
sys.stdout.write(rp.cipher_text)
sys.stderr.write(rp.key_text)


def string_xor(args):
right = args.right or sys.stdin.read()
print Xor.str(Xor.strings(args.left, right))
from yorke import Xor, byte_by_byte, recurrence_relation


def file_xor(args):
with open(args.left, 'r') as left_fd:
if args.right:
with open(args.right, 'r') as right_fd:
sys.stdout.write(Xor.str(Xor.files(left_fd, right_fd)))
else:
sys.stdout.write(Xor.str(Xor.files(left_fd, sys.stdin)))
with open(args.right, 'r') as right_fd:
sys.stdout.write(Xor.str(Xor.files(left_fd, right_fd)))


def sha256(args):
x0 = args.x0
stream_generator = recurrence_relation(lambda x: hashlib.sha256(x).digest())
try:
for output in stream_generator(x0):
sys.stdout.write(output)
except IOError:
return


def init_parser():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='Subcommand', dest='mode')
random_pad_parser = subparsers.add_parser('rp')
random_pad_parser = subparsers.add_parser('random_pad')
for input_type in ('string_', 'file_', 's', 'f'):
xor_parser = subparsers.add_parser('{}xor'.format(input_type))
xor_parser.add_argument('left', type=str)
xor_parser.add_argument('right', nargs='?', type=str, default=None)
return parser

xor_parser = subparsers.add_parser('xor')
xor_parser.add_argument('left', type=str)
xor_parser.add_argument('right', nargs='?', type=str, default=None)

dispatch_table = dict(
random_pad=random_pad,
rp=random_pad,
sha256_parser = subparsers.add_parser('sha256')
sha256_parser.add_argument('x0', type=str)

return parser

string_xor=string_xor,
sxor=string_xor,

file_xor=file_xor,
fxor=file_xor,
dispatch_table = dict(
xor=file_xor,
sha256=sha256,
)

def main():
Expand Down
29 changes: 1 addition & 28 deletions test.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
from StringIO import StringIO
from unittest import TestCase

from yorke import RandomPad, Xor
from yorke import Xor


class TestXor(TestCase):

def test_strings(self):
str1 = '\xff\xfe\xfb'
str2 = '\xfb\xfe\xff'
xord = Xor.strings(str1, str2)
self.assertEqual(xord, [4, 0, 4])

def test_bytestreams(self):
stream1 = iter(map(ord, '\xff\xfe\xfb'))
stream2 = iter(map(ord, '\xfb\xfe\xff'))
Expand All @@ -32,24 +26,3 @@ def test_byte_list_to_string(self):

def test_str_alias(self):
self.assertEqual(Xor.str, Xor.byte_list_to_string)


class TestRandomPad(TestCase):

def test_encrypt(self):
rp = RandomPad()
self.assertEqual(rp.key_bytes, [])
self.assertEqual(rp.cipher_bytes, [])

plain = 'More secret than top secret'
self.assertEqual(rp, rp.encrypt_string(plain))
self.assertEqual(
rp.cipher_bytes,
[ord(c) ^ b for c, b in zip(plain, rp.key_bytes)]
)
self.assertEqual(rp.key_text, ''.join(map(chr, rp.key_bytes)))
self.assertEqual(rp.cipher_text, ''.join(map(chr, rp.cipher_bytes)))
self.assertEqual(
Xor.str(Xor.strings(rp.key_text, rp.cipher_text)),
plain
)
18 changes: 4 additions & 14 deletions test.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
#!/usr/bin/env bash
set -e

SECRET='More secret than top secret'

mkdir out || echo "directory ./out exists"
cd out

printf "$SECRET" | yorke random_pad 1> cipher.txt 2> key.txt
printf "$SECRET" | yorke rp 1> cipher.txt 2> key.txt

printf "$SECRET" > expected.txt

yorke file_xor cipher.txt key.txt > plain.txt
diff <(xxd plain.txt) <(xxd expected.txt)

yorke fxor key.txt cipher.txt > plain.txt
diff <(xxd plain.txt) <(xxd expected.txt)
echo 'More secret than top secret' > plain.txt

cat key.txt | yorke fxor cipher.txt > plain.txt
diff <(xxd plain.txt) <(xxd expected.txt)
yorke xor plain.txt <(cat /dev/urandom | tee key.txt) > cipher.txt
yorke xor cipher.txt key.txt > plain2.txt
diff <(xxd plain.txt) <(xxd plain2.txt)

echo "Tests Ran Successfully"
51 changes: 16 additions & 35 deletions yorke.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from random import randint


def byte_by_byte(file_descriptor):
Expand All @@ -9,11 +8,25 @@ def byte_by_byte(file_descriptor):
raise StopIteration


def recurrence_relation(mapping):
def stream_generator(x0, starting_offset=1):
x = x0
for _ in xrange(starting_offset):
x = mapping(x)
while 1:
x = mapping(x)
yield x
return stream_generator


class Xor(object):

@classmethod
def strings(cls, left, right):
return [ord(l) ^ ord(r) for l, r in zip(left, right)]
def files(cls, left_fd, right_fd):
left_stream = byte_by_byte(left_fd)
right_stream = byte_by_byte(right_fd)
for byte in cls.bytestreams(left_stream, right_stream):
yield byte

@classmethod
def bytestreams(cls, left_stream, right_stream):
Expand All @@ -22,40 +35,8 @@ def bytestreams(cls, left_stream, right_stream):
right_byte = right_stream.next()
yield left_byte ^ right_byte

@classmethod
def files(cls, left_fd, right_fd):
left_stream = byte_by_byte(left_fd)
right_stream = byte_by_byte(right_fd)
for byte in cls.bytestreams(left_stream, right_stream):
yield byte

@classmethod
def byte_list_to_string(cls, byte_list):
return ''.join(chr(b) for b in byte_list)

str = byte_list_to_string


class RandomPad(object):

def __init__(self):
self.key_bytes = []
self.cipher_bytes = []

def encrypt_bytes(self, byte_stream):
for byte in byte_stream:
random_byte = randint(0, 255)
self.key_bytes.append(random_byte)
self.cipher_bytes.append(byte ^ random_byte)
return self

def encrypt_string(self, plain_text):
return self.encrypt_bytes(map(ord, plain_text))

@property
def key_text(self):
return Xor.str(self.key_bytes)

@property
def cipher_text(self):
return Xor.str(self.cipher_bytes)

0 comments on commit 1f04142

Please sign in to comment.