Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django, python and link encryption

I need to arrange some kind of encrpytion for generating user specific links. Users will be clicking this link and at some other view, related link with the crypted string will be decrypted and result will be returned.

For this, I need some kind of encryption function that consumes a number(or a string) that is the primary key of my selected item that is bound to the user account, also consuming some kind of seed and generating encryption code that will be decrypted at some other page.

so something like this

my_items_pk = 36 #primary key of an item
seed = "rsdjk324j23423j4j2" #some string for crypting
encrypted_string = encrypt(my_items_pk,seed)
#generates some crypted string such as "dsaj2j213jasas452k41k"
and at another page:
decrypt_input = encrypt(decypt,seed)
print decrypt_input
#gives 36

I want my "seed" to be some kind of primary variable (not some class) for this purpose (ie some number or string).

How can I achieve this under python and django ?

like image 392
Hellnar Avatar asked Feb 18 '10 18:02

Hellnar


1 Answers

There are no encryption algorithms, per se, built in to Python. However, you might want to look at the Python Cryptography Toolkit (PyCrypt). I've only tinkered with it, but it's referenced in Python's documentation on cryptographic services. Here's an example of how you could encrypt a string with AES using PyCrypt:

from Crypto.Cipher import AES
from urllib import quote

# Note that for AES the key length must be either 16, 24, or 32 bytes
encryption_obj = AES.new('abcdefghijklmnop')
plain = "Testing"

# The plaintext must be a multiple of 16 bytes (for AES), so here we pad it
# with spaces if necessary.
mismatch = len(plain) % 16
if mismatch != 0:
  padding = (16 - mismatch) * ' '
  plain += padding

ciph = encryption_obj.encrypt(plain)

# Finally, to make the encrypted string safe to use in a URL we quote it
quoted_ciph = quote(ciph)

You would then make this part of your URL, perhaps as part of a GET request.

To decrypt, just reverse the process; assuming that encryption_obj is created as above, and that you've retrieved the relevant part of the URL, this would do it:

from urllib import unquote

# We've already created encryption_object as shown above

ciph = unquote(quoted_ciph)
plain = encryption_obj.decrypt(ciph)

You also might consider a different approach: one simple method would be to hash the primary key (with a salt, if you wish) and store the hash and pk in your database. Give the user the hash as part of their link, and when they return and present the hash, look up the corresponding pk and return the appropriate object. (If you want to go this route, check out the built-in library hashlib.)

As an example, you'd have something like this defined in models.py:

class Pk_lookup(models.Model):
  # since we're using sha256, set the max_length of this field to 32
  hashed_pk = models.CharField(primary_key=True, max_length=32)
  key = models.IntegerField()

And you'd generate the hash in a view using something like the following:

import hashlib
import Pk_lookup

hash = hashlib.sha256()
hash.update(str(pk)) # pk has been defined previously
pk_digest = hash.digest()

lookup = Pk_lookup(hashed_pk=pk_digest,key=pk)
lookup.save()

Note that you'd have to quote this version as well; if you prefer, you can use hexdigest() instead of digest (you wouldn't have to quote the resulting string), but you'll have to adjust the length of the field to 64.

like image 181
mjjohnson Avatar answered Nov 06 '22 09:11

mjjohnson