Skip to content

Commit 683234a

Browse files
committed
Python v0.2.0
1 parent c58c5e8 commit 683234a

7 files changed

Lines changed: 73 additions & 24 deletions

File tree

python/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build/
2+
dist/
3+
*.egg-info/

python/MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include README.rst

python/README.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
encrypted-content-encoding
2+
==========================
3+
4+
A simple implementation of the `HTTP encrypted
5+
content-encoding <https://tools.ietf.org/html/draft-nottingham-http-encryption-encoding>`_
6+
7+
# Use
8+
9+
```python
10+
import http_ece
11+
import os, base64
12+
13+
key = os.urandom(16)
14+
salt = os.urandom(16)
15+
data = os.urandom(100)
16+
17+
encrypted = http_ece.encrypt(data, salt=salt, key=key)
18+
decrypted = http_ece.decrypt(encrypted, salt=salt, key=key)
19+
assert data == decrypted
20+
```
21+
22+
This also supports the static-ephemeral ECDH mode.
23+
24+
# TODO
25+
26+
Provide a streaming API

python/http_ece/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def decryptRecord(key, nonce, counter, buffer):
5656
backend=default_backend()
5757
).decryptor()
5858
data = decryptor.update(buffer[:-16]) + decryptor.finalize()
59-
(pad,) = struct.unpack("!B", data[0]);
59+
(pad,) = struct.unpack("!B", data[0:1]);
6060
if data[1:1+pad] != (b"\x00" * pad):
6161
raise Exception(u"Bad padding")
6262
data = data[1+pad:]
@@ -71,7 +71,7 @@ def decryptRecord(key, nonce, counter, buffer):
7171

7272
result = b""
7373
counter = 0
74-
for i in xrange(0, len(buffer), rs):
74+
for i in list(range(0, len(buffer), rs)):
7575
result += decryptRecord(key_, nonce_, counter, buffer[i:i+rs])
7676
++counter
7777
return result
@@ -96,7 +96,7 @@ def encryptRecord(key, nonce, counter, buffer):
9696
counter = 0
9797
# the extra one ensures that we produce a padding only record if the data
9898
# length is an exact multiple of rs-1
99-
for i in xrange(0, len(buffer) + 1, rs):
99+
for i in list(range(0, len(buffer) + 1, rs)):
100100
result += encryptRecord(key_, nonce_, counter, buffer[i:i+rs])
101101
++counter
102102
return result

python/setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[bdist_wheel]
2+
universal=1

python/setup.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22

33
setup(
44
name='http_ece',
5-
version='1.0.0',
5+
version='0.2.0',
66
author='Martin Thomson',
77
author_email='martin.thomson@gmail.com',
88
scripts=[],
99
packages=['http_ece'],
1010
description='Encrypted Content Encoding for HTTP',
11-
long_description='Enciper HTTP Messages',
11+
long_description='Encipher HTTP Messages',
12+
classifiers=[
13+
'Development Status :: 3 - Alpha',
14+
'License :: OSI Approved :: MIT License',
15+
'Programming Language :: Python :: 2.7',
16+
'Programming Language :: Python :: 3.4',
17+
],
18+
keywords='crypto http',
1219
install_requires=[
1320
'pyelliptic', 'cryptography'
1421
],

python/test.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import http_ece as ece
2-
import base64
32
import os
43
import struct
54
import sys
@@ -14,22 +13,33 @@
1413

1514
def log(arg):
1615
if (count == 1):
17-
print arg
16+
print(arg)
17+
def b64e(arg):
18+
import base64
19+
return base64.urlsafe_b64encode(arg).decode()
1820

1921
def rlen():
2022
return struct.unpack_from('=H', os.urandom(2))[0]
2123

2224
def encryptDecrypt(length, encryptParams, decryptParams=None):
2325
if decryptParams is None:
2426
decryptParams = encryptParams
25-
log('Salt: ' + base64.urlsafe_b64encode(encryptParams['salt']))
27+
log('Salt: ' + b64e(encryptParams['salt']))
2628
input = os.urandom(min(length, maxLen))
2729
# input = new Buffer('I am the walrus')
28-
log('Input: ' + base64.urlsafe_b64encode(input))
29-
encrypted = ece.encrypt(input, salt=encryptParams.get('salt'), key=encryptParams.get('key'), keyid=encryptParams.get('keyid'), dh=encryptParams.get('dh'), rs=encryptParams.get('rs'))
30-
log('Encrypted: ' + base64.urlsafe_b64encode(encrypted))
31-
decrypted = ece.decrypt(encrypted, salt=decryptParams.get('salt'), key=decryptParams.get('key'), keyid=decryptParams.get('keyid'), dh=decryptParams.get('dh'), rs=decryptParams.get('rs'))
32-
log('Decrypted: ' + base64.urlsafe_b64encode(decrypted))
30+
log('Input: ' + b64e(input))
31+
encrypted = ece.encrypt(input, salt=encryptParams.get('salt'),
32+
key=encryptParams.get('key'),
33+
keyid=encryptParams.get('keyid'),
34+
dh=encryptParams.get('dh'),
35+
rs=encryptParams.get('rs'))
36+
log('Encrypted: ' + b64e(encrypted))
37+
decrypted = ece.decrypt(encrypted, salt=decryptParams.get('salt'),
38+
key=decryptParams.get('key'),
39+
keyid=decryptParams.get('keyid'),
40+
dh=decryptParams.get('dh'),
41+
rs=decryptParams.get('rs'))
42+
log('Decrypted: ' + b64e(decrypted))
3343
assert input == decrypted
3444
log("----- OK");
3545

@@ -40,7 +50,7 @@ def useExplicitKey():
4050
'salt': os.urandom(16),
4151
'rs': rlen() + 1
4252
}
43-
log('Key: ' + base64.urlsafe_b64encode(params['key']))
53+
log('Key: ' + b64e(params['key']))
4454
encryptDecrypt(rlen() + 1, params)
4555

4656

@@ -75,7 +85,7 @@ def detectTruncation():
7585

7686

7787
def useKeyId():
78-
keyid = base64.urlsafe_b64encode(os.urandom(16))
88+
keyid = b64e(os.urandom(16))
7989
key = os.urandom(16)
8090
ece.keys[keyid] = key
8191
params = {
@@ -90,26 +100,26 @@ def useKeyId():
90100
# doesn't even do ECDH; so this doesn't actually work
91101
def useDH():
92102
def isUncompressed(k):
93-
b1 = k.get_pubkey()[0]
103+
b1 = k.get_pubkey()[0:1]
94104
assert struct.unpack("B", b1)[0] == 4, 'is an uncompressed point'
95105

96106
# the static key is used by the receiver
97107
staticKey = pyelliptic.ECC(curve='prime256v1')
98108
isUncompressed(staticKey)
99-
staticKeyId = base64.urlsafe_b64encode(staticKey.get_pubkey()[1:])
109+
staticKeyId = b64e(staticKey.get_pubkey()[1:])
100110
ece.keys[staticKeyId] = staticKey
101111

102-
log('Receiver private: ' + base64.urlsafe_b64encode(staticKey.get_privkey()))
103-
log('Receiver public: ' + base64.urlsafe_b64encode(staticKey.get_pubkey()))
112+
log('Receiver private: ' + b64e(staticKey.get_privkey()))
113+
log('Receiver public: ' + b64e(staticKey.get_pubkey()))
104114

105115
# the ephemeral key is used by the sender
106116
ephemeralKey = pyelliptic.ECC(curve='prime256v1')
107117
isUncompressed(ephemeralKey)
108-
ephemeralKeyId = base64.urlsafe_b64encode(ephemeralKey.get_pubkey()[1:])
118+
ephemeralKeyId = b64e(ephemeralKey.get_pubkey()[1:])
109119
ece.keys[ephemeralKeyId] = ephemeralKey
110120

111-
log('Sender private: ' + base64.urlsafe_b64encode(ephemeralKey.get_privkey()))
112-
log('Sender public: ' + base64.urlsafe_b64encode(ephemeralKey.get_pubkey()))
121+
log('Sender private: ' + b64e(ephemeralKey.get_privkey()))
122+
log('Sender public: ' + b64e(ephemeralKey.get_pubkey()))
113123

114124
encryptParams = {
115125
'keyid': ephemeralKeyId,
@@ -127,11 +137,11 @@ def isUncompressed(k):
127137
encryptDecrypt(rlen(), encryptParams, decryptParams)
128138

129139
if __name__ == '__main__':
130-
for i in range(0,count):
140+
for i in list(range(0,count)):
131141
useExplicitKey()
132142
exactlyOneRecord()
133143
detectTruncation()
134144
useKeyId()
135145
useDH()
136146

137-
print 'All tests passed.'
147+
print('All tests passed.')

0 commit comments

Comments
 (0)