Skip to content

Commit 8f640e7

Browse files
author
Roland Hedberg
committed
Merge pull request #37 from dallerbarn/py3_string
Python 2 and 3 string conversion
2 parents 2b139d8 + 23722a5 commit 8f640e7

File tree

8 files changed

+60
-37
lines changed

8 files changed

+60
-37
lines changed

src/jwkest/__init__.py

+26
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,29 @@ def constant_time_compare(a, b):
197197
for c, d in zip(a, b):
198198
r |= c ^ d
199199
return r == 0
200+
201+
202+
def as_bytes(s):
203+
"""
204+
Convert an unicode string to bytes.
205+
:param s: Unicode / bytes string
206+
:return: bytes string
207+
"""
208+
try:
209+
s = s.encode()
210+
except (AttributeError, UnicodeDecodeError):
211+
pass
212+
return s
213+
214+
215+
def as_unicode(b):
216+
"""
217+
Convert a byte string to a unicode string
218+
:param b: byte string
219+
:return: unicode string
220+
"""
221+
try:
222+
b = b.decode()
223+
except (AttributeError, UnicodeDecodeError):
224+
pass
225+
return b

src/jwkest/aes_key_wrap.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
PyCrypto's AES.
1717
"""
1818
from __future__ import division
19+
1920
try:
2021
from builtins import hex
2122
from builtins import range
@@ -39,7 +40,7 @@ def aes_unwrap_key_and_iv(kek, wrapped):
3940
B = decrypt(ciphertext)
4041
a = QUAD.unpack(B[:8])[0]
4142
r[i] = B[8:]
42-
return "".join(r[1:]), a
43+
return b"".join(r[1:]), a
4344

4445

4546
def aes_unwrap_key(kek, wrapped, iv=0xa6a6a6a6a6a6a6a6):

src/jwkest/jwe.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from Crypto.Cipher import PKCS1_v1_5
1919
from Crypto.Cipher import PKCS1_OAEP
2020

21-
from jwkest import b64d
21+
from jwkest import b64d, as_bytes
2222
from jwkest import b64e
2323
from jwkest import JWKESTException
2424
from jwkest import MissingKey
@@ -404,7 +404,7 @@ def encrypt(self, key, iv="", cek="", **kwargs):
404404

405405
# If no iv and cek are given generate them
406406
cek, iv = self._generate_key_and_iv(self["enc"], cek, iv)
407-
if isinstance(key, six.string_types):
407+
if isinstance(key, six.binary_type):
408408
kek = key
409409
else:
410410
kek = intarr2str(key)
@@ -415,7 +415,7 @@ def encrypt(self, key, iv="", cek="", **kwargs):
415415

416416
_enc = self["enc"]
417417

418-
ctxt, tag, cek = self.enc_setup(_enc, _msg, jwe.b64_encode_header(),
418+
ctxt, tag, cek = self.enc_setup(_enc, _msg.encode(), jwe.b64_encode_header(),
419419
cek, iv=iv)
420420
return jwe.pack(parts=[jek, iv, ctxt, tag])
421421

@@ -456,7 +456,7 @@ def encrypt(self, key, iv="", cek="", **kwargs):
456456
:return: A jwe
457457
"""
458458

459-
_msg = self.msg
459+
_msg = as_bytes(self.msg)
460460
if "zip" in self:
461461
if self["zip"] == "DEF":
462462
_msg = zlib.compress(_msg)
@@ -681,7 +681,7 @@ def decrypt(self, token, keys=None, alg=None):
681681
for key in keys:
682682
_key = key.encryption_key(alg=_alg, private=False)
683683
try:
684-
msg = decrypter.decrypt(bytes(token), _key)
684+
msg = decrypter.decrypt(as_bytes(token), _key)
685685
except (KeyError, DecryptionFailed):
686686
pass
687687
else:

src/jwkest/jwk.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from requests import request
1717

1818
from jwkest import base64url_to_long
19+
from jwkest import as_bytes
1920
from jwkest import base64_to_long
2021
from jwkest import long_to_base64
2122
from jwkest import JWKESTException
@@ -66,15 +67,15 @@ def intarr2str(arr):
6667

6768

6869
def sha256_digest(msg):
69-
return hashlib.sha256(msg).digest()
70+
return hashlib.sha256(as_bytes(msg)).digest()
7071

7172

7273
def sha384_digest(msg):
73-
return hashlib.sha384(msg).digest()
74+
return hashlib.sha384(as_bytes(msg)).digest()
7475

7576

7677
def sha512_digest(msg):
77-
return hashlib.sha512(msg).digest()
78+
return hashlib.sha512(as_bytes(msg)).digest()
7879

7980

8081
# =============================================================================
@@ -534,7 +535,7 @@ class SYMKey(Key):
534535

535536
def __init__(self, kty="oct", alg="", use="", kid="", key=None,
536537
x5c=None, x5t="", x5u="", k="", mtrl="", **kwargs):
537-
Key.__init__(self, kty, alg, use, kid, key, x5c, x5t, x5u, **kwargs)
538+
Key.__init__(self, kty, alg, use, kid, as_bytes(key), x5c, x5t, x5u, **kwargs)
538539
self.k = k
539540
if not self.key and self.k:
540541
if isinstance(self.k, str):

src/jwkest/jws.py

+7-10
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from Crypto.Util.number import bytes_to_long
2424
import sys
2525

26-
from jwkest import b64d
26+
from jwkest import b64d, as_unicode
2727
from jwkest import b64e
2828
from jwkest import constant_time_compare
2929
from jwkest import safe_str_cmp
@@ -74,11 +74,11 @@ class SignerAlgError(JWSException):
7474
def left_hash(msg, func="HS256"):
7575
""" 128 bits == 16 bytes """
7676
if func == 'HS256':
77-
return b64e(sha256_digest(msg)[:16])
77+
return as_unicode(b64e(sha256_digest(msg)[:16]))
7878
elif func == 'HS384':
79-
return b64e(sha384_digest(msg)[:24])
79+
return as_unicode(b64e(sha384_digest(msg)[:24]))
8080
elif func == 'HS512':
81-
return b64e(sha512_digest(msg)[:32])
81+
return as_unicode(b64e(sha512_digest(msg)[:32]))
8282

8383

8484
def mpint(b):
@@ -249,10 +249,7 @@ class JWx(object):
249249
"""
250250

251251
def __init__(self, msg=None, with_digest=False, **kwargs):
252-
if six.PY3 and isinstance(msg, six.string_types):
253-
self.msg = msg.encode("utf-8")
254-
else:
255-
self.msg = msg
252+
self.msg = msg
256253

257254
self._dict = {}
258255
self.with_digest = with_digest
@@ -492,9 +489,9 @@ def sign_compact(self, keys=None, protected=None):
492489
raise UnknownAlgorithm(_alg)
493490

494491
_input = jwt.pack(parts=[self.msg])
495-
sig = _signer.sign(_input, key.get_key(alg=_alg, private=True))
492+
sig = _signer.sign(_input.encode("utf-8"), key.get_key(alg=_alg, private=True))
496493
logger.debug("Signed message using key with kid=%s" % key.kid)
497-
return b".".join([_input, b64encode_item(sig)])
494+
return ".".join([_input, b64encode_item(sig).decode("utf-8")])
498495

499496
def verify_compact(self, jws, keys=None, allow_none=False, sigalg=None):
500497
"""

src/jwkest/jwt.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import six
3-
from jwkest import b64d
3+
from jwkest import b64d, as_unicode
44
from jwkest import b64e
55
from jwkest import BadSyntax
66

@@ -58,7 +58,7 @@ def unpack(self, token):
5858
part = split_token(token)
5959
self.b64part = part
6060
self.part = [b64d(p) for p in part]
61-
self.headers = json.loads(self.part[0].decode("utf-8"))
61+
self.headers = json.loads(self.part[0].decode())
6262
return self
6363

6464
def pack(self, parts, headers=None):
@@ -77,10 +77,10 @@ def pack(self, parts, headers=None):
7777
_all = self.b64part = [ self.b64part[0] ]
7878
_all.extend([b64encode_item(p) for p in parts])
7979

80-
return b".".join(_all)
80+
return ".".join([a.decode() for a in _all])
8181

8282
def payload(self):
83-
_msg = self.part[1].decode("utf-8")
83+
_msg = as_unicode(self.part[1])
8484

8585
# If not JSON web token assume JSON
8686
if "cty" in self.headers and self.headers["cty"].lower() != "jwt":

tests/test_1_jwt.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_pack_jwt():
1313
jwt = _jwt.pack(parts=[{"iss": "joe", "exp": 1300819380,
1414
"http://example.com/is_root": True}, ""])
1515

16-
p = jwt.split(b'.')
16+
p = jwt.split('.')
1717
assert len(p) == 3
1818

1919

@@ -40,12 +40,10 @@ def test_unpack_str():
4040
"http://example.com/is_root": True}
4141
jwt = _jwt.pack(parts=[payload, ""])
4242

43-
jwt = jwt.decode('utf-8')
44-
4543
_jwt2 = JWT().unpack(jwt)
4644
assert _jwt2
4745
out_payload = _jwt2.payload()
4846

4947

5048
if __name__ == "__main__":
51-
test_unpack_str()
49+
test_unpack_str()

tests/test_3_jws.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,13 @@ def test_hmac_from_keyrep():
193193

194194

195195
def test_left_hash_hs256():
196-
hsh = jws.left_hash(b'Please take a moment to register today')
197-
assert hsh == b'rCFHVJuxTqRxOsn2IUzgvA'
196+
hsh = jws.left_hash('Please take a moment to register today')
197+
assert hsh == 'rCFHVJuxTqRxOsn2IUzgvA'
198198

199199

200200
def test_left_hash_hs512():
201-
hsh = jws.left_hash(b'Please take a moment to register today', "HS512")
202-
assert hsh == b'_h6feWLt8zbYcOFnaBmekTzMJYEHdVTaXlDgJSWsEeY'
201+
hsh = jws.left_hash('Please take a moment to register today', "HS512")
202+
assert hsh == '_h6feWLt8zbYcOFnaBmekTzMJYEHdVTaXlDgJSWsEeY'
203203

204204

205205
def test_rs256():
@@ -349,7 +349,7 @@ def test_signer_ps256_fail():
349349
keys = [RSAKey(key=import_rsa_key_from_file(KEY))]
350350
#keys[0]._keytype = "private"
351351
_jws = JWS(payload, alg="PS256")
352-
_jwt = _jws.sign_compact(keys)[:-5] + b'abcde'
352+
_jwt = _jws.sign_compact(keys)[:-5] + 'abcde'
353353

354354
_rj = JWS()
355355
try:
@@ -428,9 +428,9 @@ def test_signer_protected_headers():
428428

429429
exp_protected = protected.copy()
430430
exp_protected['alg'] = 'ES256'
431-
enc_header, enc_payload, sig = _jwt.split(b'.')
432-
assert json.loads(b64d(enc_header).decode("utf-8")) == exp_protected
433-
assert b64d(enc_payload).decode("utf-8") == payload
431+
enc_header, enc_payload, sig = _jwt.split('.')
432+
assert json.loads(b64d(enc_header.encode("utf-8")).decode("utf-8")) == exp_protected
433+
assert b64d(enc_payload.encode("utf-8")).decode("utf-8") == payload
434434

435435
_rj = JWS()
436436
info = _rj.verify_compact(_jwt, keys)
@@ -444,7 +444,7 @@ def test_verify_protected_headers():
444444
protected = dict(header1=u"header1 is protected",
445445
header2="header2 is protected too", a=1)
446446
_jwt = _jws.sign_compact(keys, protected=protected)
447-
protectedHeader, enc_payload, sig = _jwt.split(b".")
447+
protectedHeader, enc_payload, sig = _jwt.split(".")
448448
data = dict(payload=enc_payload, signatures=[
449449
dict(
450450
header=dict(alg=u"ES256", jwk=_key.serialize()),

0 commit comments

Comments
 (0)