Skip to content

Commit

Permalink
Fix int to bytes conversion in python3 (#16)
Browse files Browse the repository at this point in the history
* Fix int -> bytes conversion in python3

* Update version to 0.3.0
  • Loading branch information
jatinderjit authored and Amit Upadhyay committed Jun 1, 2018
1 parent 00f2c04 commit d9626b9
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,8 @@ docs/_build/
# PyBuilder
target/

#Ipython Notebook
# Ipython Notebook
.ipynb_checkpoints

# Editors
.idea/
4 changes: 4 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
django-encrypted-id
===================

**Note**: Encrypted IDs generated by version 0.3.0 onwards will be different
from those generated by version 0.2.0. But versions 0.3.x will decrypt the IDs
generated by the version 0.2.0.

**Note**: Version 0.2.0 is a breaking change from versions
`0.1.x <https://github.com/amitu/django-encrypted-id/tree/v0.1>`_.
If you've been using *ekey* in permalinks, then it is recommended for you to
Expand Down
43 changes: 40 additions & 3 deletions encrypted_id/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from django.shortcuts import get_object_or_404 as go4


__version__ = "0.2.0"
__version__ = "0.3.0"
__license__ = "BSD"
__author__ = "Amit Upadhyay"
__email__ = "[email protected]"
Expand All @@ -39,7 +39,7 @@ def __init__(self, msg="Failed to decrypt, invalid input."):
def encode(the_id, sub_key):
assert 0 <= the_id < 2 ** 64

crc = binascii.crc32(bytes(the_id)) & 0xffffffff
crc = binascii.crc32(str(the_id).encode('utf-8')) & 0xffffffff

message = struct.pack(b"<IQxxxx", crc, the_id)
assert len(message) == 16
Expand All @@ -49,13 +49,50 @@ def encode(the_id, sub_key):
cypher = AES.new(key[:32], AES.MODE_CBC, iv)

eid = base64.urlsafe_b64encode(cypher.encrypt(message)).replace(b"=", b"")
return eid.decode('utf-8')
return (b"$" + eid).decode("utf-8")


def decode(e, sub_key):
if isinstance(e, basestring):
e = bytes(e.encode("ascii"))

if not e.startswith(b"$"):
return decode2(e, sub_key)
e = e[1:]

try:
padding = (3 - len(e) % 3) * b"="
e = base64.urlsafe_b64decode(e + padding)
except (TypeError, AttributeError, binascii.Error):
raise EncryptedIDDecodeError()

for key in getattr(settings, "SECRET_KEYS", [settings.SECRET_KEY]):
iv = hashlib.sha256((key + sub_key).encode('ascii')).digest()[:16]
cypher = AES.new(key[:32], AES.MODE_CBC, iv)
try:
msg = cypher.decrypt(e)
except ValueError:
raise EncryptedIDDecodeError()

try:
crc, the_id = struct.unpack(b"<IQxxxx", msg)
except struct.error:
raise EncryptedIDDecodeError()

try:
if crc != binascii.crc32(str(the_id).encode('utf-8')) & 0xffffffff:
continue
except (MemoryError, OverflowError):
raise EncryptedIDDecodeError()

return the_id
raise EncryptedIDDecodeError("Failed to decrypt, CRC never matched.")


def decode2(e, sub_key):
if isinstance(e, basestring):
e = bytes(e.encode("ascii"))

try:
padding = (3 - len(e) % 3) * b"="
e = base64.urlsafe_b64decode(e + padding)
Expand Down

0 comments on commit d9626b9

Please sign in to comment.