import random maxLongInt = (2**63)-1 def genkey(): """ Generate a key (an int representing 16 bytes of random data). """ return random.randint(0, maxLongInt) def _swapat(key, n): # n: 0-8; a swap is an 8-bit value; 2 ints between 0-15 return (key >> ((8 * (n))+4)) & 0xf, (key >> (8 * n)) & 0xf def _swap(l, a, b): l[a], l[b] = l[b], l[a] def webIDToStoreID(key, webid): """ Takes a webid (a 16-character str suitable for including in URLs) and a key (an int, a private key for decoding it) and produces a storeID. """ if len(webid) != 16: return None try: int(webid, 16) except TypeError: return None except ValueError: return None l = list(webid) for nybbleid in range(7, -1, -1): a, b = _swapat(key, nybbleid) _swap(l, b, a) i = int(''.join(l), 16) return i ^ key def storeIDToWebID(key, storeid): """ Takes a key (int) and storeid (int) and produces a webid (a 16-character str suitable for including in URLs) """ i = key ^ storeid l = list('%0.16x' % (i,)) for nybbleid in range(0, 8): a, b = _swapat(key, nybbleid) _swap(l, a, b) return ''.join(l) def _test(): for y in range(100): key = genkey() print 'starting with key', key, hex(key) for sid in range(1000): wid = storeIDToWebID(key, sid) sid2 = webIDToStoreID(key, wid) assert sid == sid2, '%s != %s [%r %r]' % (sid, sid2, wid, key) #print wid, '<=>', sid, ':', hex(key) def _simpletest(): key = 0xfedcba9876543210 web = storeIDToWebID(key, 100) print 'web', repr(web) sid = webIDToStoreID(key, web) print 'store', hex(sid) if __name__ == '__main__': _test()