Last active
April 29, 2016 11:00
-
-
Save amitu/80f53eb5154a2c0cccf0fb2b00a66fea to your computer and use it in GitHub Desktop.
Django Model base class for encoded key. Useful for when you want to pass id in URL or JSON, but do not leak data to world (about how many objects you have of that kind).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Crypto.Cipher import AES | |
from Crypto import Random | |
import base64 | |
import binascii | |
import struct | |
from django.db import models | |
from django.conf import settings | |
class EncodedKeyManager(models.Manager): | |
def get_by_ekey(self, ekey): | |
return self.get(pk=decode(ekey)) | |
def get_by_ekey_or_404(self, ekey): | |
from django.http import Http404 | |
try: | |
return self.get_by_ekey(ekey) | |
except models.ObjectDoesNotExist: | |
raise Http404 | |
class EncodedKeyModel(models.Model): | |
class Meta: | |
abstract = True | |
@property | |
def ekey(self): | |
return encode(self.pk) | |
def encode(m): | |
message = str(m) | |
length_bytes = struct.pack("i", len(message)) | |
crc_bytes = struct.pack("i", binascii.crc32(message)) | |
message = crc_bytes + length_bytes + message | |
if len(message) % 16: | |
message += " " * (16 - len(message) % 16) | |
cypher = AES.new( | |
settings.SECRET_KEY[:24], AES.MODE_CBC, settings.SECRET_KEY[-16:] | |
) | |
return base64.urlsafe_b64encode(cypher.encrypt(message)).replace("=", ".") | |
def decode(e): | |
e = base64.urlsafe_b64decode(str(e).replace(".", "=")) | |
for skey in getattr(settings, "SECRET_KEYS", [settings.SECRET_KEY]): | |
cypher = AES.new(skey[:24], AES.MODE_CBC, skey[-16:]) | |
msg = cypher.decrypt(e) | |
crc, length, msg = msg[:4], msg[4:8], msg[8:] | |
length_int = struct.unpack("i", length)[0] | |
crc = struct.unpack("i", crc)[0] | |
msg = msg[:length_int] | |
if crc != binascii.crc32(msg): | |
continue | |
return msg | |
raise ValueError("Failed to decrypt, CRC never matched.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment