8

I have a function in my views.py where at some line I make a GET request of an id. Once I get the id, I want to encrypt that id and then later decrypt that also. So I need two functions

def encrypt(id):#let say the id is 100
   #do something
   return encrypted_id # 6-digit let say 985634

def decrypt(encrypted_id): # Here enter 985634
    #do something     
    return decrypted_id  # i should get 100

I have read many posts but not finding an easy and clean way to apply this in my views.py Here what I have studied

sha1 : You can't decrypt that (implemented for encryption) Mee 2 M2 . AES it deals with 16-digit that multiple of 8 something

I tried to generate 6-digit random number also but that idea is also not promising. Can anybody tell a way how to do this ? Thanks in advance

Ahsan
  • 11,516
  • 12
  • 52
  • 79
the_game
  • 261
  • 1
  • 5
  • 16
  • some really nice ideas here: http://stackoverflow.com/questions/8554286/obfuscating-an-id – georg Mar 21 '12 at 12:57

2 Answers2

29

Use AES (from pycrypto), but pad the plain text prior to encrypting it.

This example pads the clear text with null characters (ASCII 0)

from Crypto.Cipher import AES
import base64

MASTER_KEY="Some-long-base-key-to-use-as-encryption-key"

def encrypt_val(clear_text):
    enc_secret = AES.new(MASTER_KEY[:32])
    tag_string = (str(clear_text) +
                  (AES.block_size -
                   len(str(clear_text)) % AES.block_size) * "\0")
    cipher_text = base64.b64encode(enc_secret.encrypt(tag_string))

    return cipher_text

After you decrypt, strip the null characters:

def decrypt_val(cipher_text):
    dec_secret = AES.new(MASTER_KEY[:32])
    raw_decrypted = dec_secret.decrypt(base64.b64decode(cipher_text))
    clear_val = raw_decrypted.decode().rstrip("\0")
    return clear_val
Martlark
  • 14,208
  • 13
  • 83
  • 99
Doug Harris
  • 3,169
  • 5
  • 29
  • 31
  • Because the AES algorithm works on blocks that are multiples of 16 bytes (AES.block_size = 16). – Doug Harris Mar 21 '12 at 13:11
  • Perfect Answer Doug. Is there a way we can avoid or build some logic where i can use my id which will come from request in django view function and then it fits the block size . I want to avoid that master key hardcoding can we make it dynamic . I am a newbie in encryption. But thanks for your help . Great answer !!!!! – the_game Mar 22 '12 at 06:40
  • @the_game I'm not sure I follow that. I have my master key hard coded in the file where I define these functions. If a bad guy can get to this file, he can do more evil than just find the master key. How would you envision the master key being dynamic? (also, I grabbed my master key from https://www.grc.com/passwords.htm ) – Doug Harris Mar 22 '12 at 13:27
  • Why on earth is there an eval() in there?! Not only is it incredibly dangerous, but it prevents the code from working at all. – fletom Sep 06 '13 at 22:26
  • I had adapted this code from a real-use scenario in which I was encrypting a python dict. In that scenario, the type of the decrypted value was known. Thanks for pointing this out. I've updated the example and also added imports to make this all work better. – Doug Harris Sep 09 '13 at 14:25
  • But the result comes with added slash(/) after encrypting any user id like 50, so if we pass this id in url, then Url breaks it in two parameters at this point this function does not work – Pankaj Nov 12 '16 at 12:54
  • Why am I getting this error when doing the decryption? "TypeError: a bytes-like object is required, not 'str'" – Phantom007 Sep 05 '17 at 14:18
9

I had exactly the same problem and solved it by using Hashids.

It is as simple as

hashids = Hashids(salt="this is my salt")
hashed = hashids.encode(id) # to encode
id = hashids.decode(hashed) # to decode
Andy
  • 1,231
  • 1
  • 15
  • 27