Skip to content

Commit 6a409da

Browse files
committed
Fix bugs in python and javascript both
1 parent e3ac010 commit 6a409da

File tree

4 files changed

+73
-45
lines changed

4 files changed

+73
-45
lines changed

nodejs/ece.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ function extractDH(header, mode) {
125125
return {
126126
secret: key.computeSecret(header.dh),
127127
context: Buffer.concat([
128-
decode(header.keylabels[header.keyid]),
128+
Buffer.from(header.keylabels[header.keyid], 'ascii'),
129129
Buffer.from([0]),
130130
lengthPrefix(receiverPubKey), // user agent
131131
lengthPrefix(senderPubKey) // application server

nodejs/test.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,17 @@ function validate() {
7979
}
8080

8181
function generateInput(len) {
82-
if (typeof len === 'undefined') {
83-
len = 0;
84-
}
85-
var input = plaintext ||
86-
crypto.randomBytes(Math.max(minLen, Math.min(len, maxLen)));
87-
if (input.length < minLen) {
88-
throw new Error('Plaintext is too short');
82+
var input;
83+
if (plaintext) {
84+
if (plaintext.length < minLen) {
85+
throw new Error('Plaintext is too short');
86+
}
87+
input = plaintext;
88+
} else {
89+
if (typeof len === 'undefined') {
90+
len = Math.floor((Math.random() * (maxLen - minLen) + minLen));
91+
}
92+
input = crypto.randomBytes(Math.max(minLen, Math.min(len, maxLen)));
8993
}
9094
logbuf('Input', input);
9195
return input;
@@ -197,11 +201,7 @@ function useKeyId(version) {
197201
keymap: keymap
198202
};
199203

200-
var keyData = {
201-
keyid: keyid,
202-
key: base64.encode(keyid)
203-
}
204-
encryptDecrypt(input, params, params, keyData);
204+
encryptDecrypt(input, params, params);
205205
}
206206

207207
function useDH(version) {

python/http_ece/__init__.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ def length_prefix(key):
115115
elif version == "aes128gcm":
116116
keyinfo = b"Content-Encoding: aes128gcm\x00"
117117
nonceinfo = b"Content-Encoding: nonce\x00"
118+
if dh is None:
119+
# Only mix the authentication secret when using DH for aes128gcm
120+
auth_secret = None
118121

119122
if auth_secret is not None:
120123
if version == "aes128gcm":
@@ -292,7 +295,7 @@ def encrypt_record(key, nonce, counter, buf):
292295
data += encryptor.tag
293296
return data
294297

295-
def compose_aes128gcm(salt, content, rs=4096, key_id=""):
298+
def compose_aes128gcm(salt, content, rs, keyid):
296299
"""Compose the header and content of an aes128gcm encrypted
297300
message body
298301
@@ -302,25 +305,22 @@ def compose_aes128gcm(salt, content, rs=4096, key_id=""):
302305
:type content: str
303306
:param rs: Override for the content length
304307
:type rs: int
305-
:param key_id: The optional key_id to use for this message
306-
:type key_id: str
308+
:param keyid: The keyid to use for this message
309+
:type keyid: str
307310
308311
"""
309312
if len(salt) != 16:
310313
raise ECEException("Invalid salt")
311-
if key_id is None:
312-
key_id = ''
313-
if len(key_id) > 255:
314-
raise ECEException("key_id is too long")
314+
if len(keyid) > 255:
315+
raise ECEException("keyid is too long")
315316
header = salt
316-
rs = rs or len(content)
317317
if rs < MIN_BUFFER_SIZE:
318318
raise ECEException("Too little content")
319319
if rs > MAX_BUFFER_SIZE:
320320
raise ECEException("Too much content")
321321
header += struct.pack("!L", rs)
322-
header += struct.pack("!B", len(key_id))
323-
header += key_id.encode('utf-8')
322+
header += struct.pack("!B", len(keyid))
323+
header += keyid
324324
return header + content
325325

326326
if version not in versions:
@@ -343,16 +343,21 @@ def compose_aes128gcm(salt, content, rs=4096, key_id=""):
343343
keyid=keyid, keymap=keymap, keylabels=keylabels)
344344
if rs <= pad_size:
345345
raise ECEException(u"Record size too small")
346-
rs -= pad_size # account for padding
346+
chunk_size = rs - pad_size
347347

348348
result = b""
349349
counter = 0
350350

351-
# the extra pad_size on the loop ensures that we produce a padding only
352-
# record if the data length is an exact multiple of rs-pad_size
353-
for i in list(range(0, len(content) + pad_size, rs)):
354-
result += encrypt_record(key_, nonce_, counter, content[i:i + rs])
351+
# the extra one on the loop ensures that we produce a padding only
352+
# record if the data length is an exact multiple of the chunk size
353+
for i in list(range(0, len(content) + 1, chunk_size)):
354+
result += encrypt_record(key_, nonce_, counter,
355+
content[i:i + chunk_size])
355356
counter += 1
356357
if version == "aes128gcm":
357-
return compose_aes128gcm(salt, result, rs, key_id=keyid)
358+
if keyid == '' and keyid in keymap:
359+
kid = keymap[keyid].get_pubkey()
360+
else:
361+
kid = (keyid or '').encode('utf-8')
362+
return compose_aes128gcm(salt, result, rs, keyid=kid)
358363
return result

python/http_ece/tests/test_ece.py

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -380,36 +380,59 @@ def setUp(self):
380380
self.legacy_data = json.loads(f.read())
381381
f.close()
382382

383-
def test_decrypt(self):
383+
def _run(self, mode):
384+
if mode == 'encrypt':
385+
func = ece.encrypt
386+
local = 'sender'
387+
remote = 'receiver'
388+
inp = 'input'
389+
outp = 'encrypted'
390+
else:
391+
func = ece.decrypt
392+
local = 'receiver'
393+
remote = 'sender'
394+
inp = 'encrypted'
395+
outp = 'input'
396+
384397
for data in self.legacy_data:
385-
print(data)
398+
print(mode)
399+
print(repr(data))
400+
p = data['params'][mode]
401+
keyid=p.get('keyid', '')
386402
if 'keys' in data:
387-
dh = b64d(data['keys']['sender']['public'])
403+
dh = b64d(data['keys'][remote]['public'])
388404
key = None
389405
keymap = {
390-
'static': pyelliptic.ECC(
391-
pubkey=b64d(data['keys']['receiver']['public']),
392-
privkey=b64d(data['keys']['receiver']['private']),
406+
keyid: pyelliptic.ECC(
407+
curve='prime256v1',
408+
pubkey=b64d(data['keys'][local]['public']),
409+
privkey=b64d(data['keys'][local]['private']),
393410
)
394411
}
395412
else:
396413
dh = None
397-
key = b64d(data['params']['decrypt']['key'])
414+
key = b64d(p['key'])
398415
keymap = {}
399416

400-
if 'authSecret' in data['params']['decrypt']:
401-
auth_secret = b64d(data['params']['decrypt']['authSecret'])
417+
if 'authSecret' in p:
418+
auth_secret = b64d(p['authSecret'])
402419
else:
403420
auth_secret = None
404-
decrypted = ece.decrypt(
405-
b64d(data['encrypted']),
406-
salt=b64d(data['params']['decrypt']['salt']),
421+
result = func(
422+
b64d(data[inp]),
423+
salt=b64d(p['salt']),
407424
key=key,
408425
dh=dh,
409426
auth_secret=auth_secret,
410-
keyid='static',
427+
keyid=keyid,
411428
keymap=keymap,
412-
rs=data['params']['decrypt']['rs'],
413-
version=data['version'],
429+
rs=p.get('rs', 4096),
430+
version=p['version'],
414431
)
415-
eq_(b64d(data['input']), decrypted)
432+
eq_(b64d(data[outp]), result)
433+
434+
def test_decrypt(self):
435+
self._run('decrypt')
436+
437+
def test_encrypt(self):
438+
self._run('encrypt')

0 commit comments

Comments
 (0)