Module: one_way_encrypt.py

"""
One way encryption methods for the demo.

Imports module hmac which provides the HMAC algorithm according to
RFC 1024

Current version uses SHA256 for hash mapping.

"""

import hmac
import hashlib
import random

def make_one_way_key():
    random.seed()
    x1 = random.randrange(0, 0Xffffffff)
    x2 = random.randrange(0, 0Xffffffff)
    x3 = random.randrange(0, 0Xffffffff)
    x4 = random.randrange(0, 0Xffffffff)
    return "%x%x%x%x" % (x1, x2, x3, x4)

class OneWayEncrypt:
    def __init__(self, key):
        self.key = key
	self.m = hmac.new(key, "", hashlib.sha256)
	# keep code books of translated values
	self.codes = {}
	self.scale_factors = {}

    def _derive(self, name):
        """
Derive a scale and offset from the encrypted value of the name.
The scale and offset can be used to conceal floating point numbers
while retaining their numerical order relationship.
"""
        # return stored value if we have it otherwise calculate
        if self.scale_factors.has_key(name):
            scale = self.scale_factors[name]
        else:
            # encrypt the name into a string of 64 hex digits
            namestr = self.encrypt_word(name)
            
            #  Use the last 15 hexidecimal digits for the scale1 
            s_scale = namestr[-15:]
            hexstring = "0X%s" % s_scale
            scale1 = float( eval(hexstring) )

            # use 15 digits to the left for scale2 
            s_offset = namestr[-30:-15]
            hexstring2 = "0X%s" % s_offset
            scale2 = float( eval(hexstring2 ))

            scale = scale1 + scale2

##            print "scale %s %s %g " % (s_scale, hexstring, scale)
##            print "offset %s %s %g " % (s_offset, hexstring, offset)

            #save scale factor
            self.scale_factors[name] = scale

        return scale
	

    def encrypt_word(self, word):
        """ Encrypt a string """
	h = self.m.copy()
	h.update(word)
	digest = h.hexdigest()
	self.codes[digest] = ["w", word]
	return digest

    def encrypt_int(self, k):
        """
Encrypt an integer value - encrypted integers cannot be
compared for relative value.
"""
        s = str(k)
	h = self.m.copy()
	h.update(s)
	digest = h.hexdigest()
	self.codes[digest] = ["i", k]
	return digest

    def encrypt_float(self, name, x):
        """
Encrypt a real value -- actually conceal the value, this is not
true encryption. The result may be compared for relative value.
"""
       # derive scale
        scale = self._derive(name)
        # apply and return
        return scale * x

    def encrypt_range(self, name, range_pair):
        """
Encrypt or conceal a pair of real values representing a range as xmin->xmax.
Return as a pair of concealed real values with the first smaller than the second.
"""
        return ( self.encrypt_float(name, range_pair[0]),  self.encrypt_float(name, range_pair[1]))