Thursday, June 7, 2012

Hash libraries and encryption

      Albeit not a subject matter that I have significant expertise, and generally while I would think that hashing simple password were still not a great idea.  I'd demonstrate briefly why:

Okay so if you have python installed, you'd probably have access to some basic encryption stuff here. 

You could do some basic password encryption as follows:

import hashlib
m = hashlib.sha1()
m.update(b"abcde")
print(m.hexdigest())

you'd get some output like

>>>
03de6c570bfe24bfc328ccd7ca46b76eadaf4334

which is pretty large looking bit of string that could take awhile to cipher.

The problem is that if I using a set of common password strings, hashed the same string 'abcde'

I'd get the same hash ed return value, and I'd have solved the cipher ed code quickly, but the good news is that there are a number of hashing routines (different encryption methods) other then .sha1() for instance,  and a hack would have to have any number of common passwords translated by way of any number of hash methods , so you might more safe when it comes to the gamble of hashing a very easy password, and given likely inter web securities, hacks might have so many chances before being locked out potentially of password attempts, but it still might be wise to pick a more difficult password that included mixed case alpha numerics that were greater then several character/digits in length.  Now if you had some custom hashing encryption method that were decent enough, I'd imagine you might be safer with even a easier password, but at the moment.  If you are using more common encryption software that hadn't generated unique keys for the hashing method that only you had access to...the above method, for instance, wouldn't be so great for simple passwords in my opinion.

The following is a variation from a method that I posted online.  While this creates a random sequence added to the 5 places of the encrypted password, it customizes and mixes the hashing process for password generation.  Here you presumably need to hold onto the saltkey data key.  You'd need to likely store this somewhere on your personal computer or write it down.  Its only 5 places/digits in length here, and then make sure it is recalled back in the class function either from memory or adding to a global variable in your python file...real world implementation would be slightly different also having disabled the set_password function in the encryption class upon instantiation.  Generally speaking I would tend to think using the method, your very simple password saved alongside your personal saltkey would be a much harder encryption to break.

import hashlib
alphanumer = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
              'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
              'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
              'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8',
              '9', '0', ' ', '.', '!', ',', '@', '#', '$', '%', '^', '&',
              '*', '(', ')', '-', '_', '+', '=', '[', ']', '{', '}', ':',
              ';', "'", '"', '?', '/', '>', '<']
class encryption:
    def generate_privatekey(self):
        import random
        
        randomkey = str(random.random()) + '$' + str(random.random())
        randomkeyutf16 = bytes(randomkey, 'utf-16')
        #store this salt, alongside your raw_password
        salt = hashlib.sha1()    
        salt.update(randomkeyutf16)
        saltkey = salt.hexdigest()[:7]
        return saltkey
        
    def encrypt_message(self, raw_message):

        
        privatekey = self.generate_privatekey()
        encryptmessage = ''
        for letter in raw_message:
            preencryptpart = privatekey + letter
            pencryptutf16 = bytes(preencryptpart, 'utf-16')
            hshlb = hashlib.sha1()
            hshlb.update(pencryptutf16)
            hsh = hshlb.hexdigest()
            encryptmessage += hsh
        return encryptmessage, privatekey

    def gen_decrypttables(self, privatekey, encryptmessage):
        #this works in a limited context for western latin based scripts
        #you'd have to make sure to import the correct character set for
        #alternate languages.  I'd recommend encrypting into the private
        #key a language code to reduce computation times on character sets.
        decryptiondict = {}
        for letter in alphanumer:
            keystring = privatekey + letter
            bkeystring = bytes(keystring, 'utf-16')
            hshlb = hashlib.sha1()
            hshlb.update(bkeystring)
            hsh = hshlb.hexdigest()
            decryptiondict[hsh] = letter
        decryptmessage = ''
        count = 0
        while len(encryptmessage) > 0:
##            print(decryptmessage)
            for hsh in decryptiondict:
                if encryptmessage.find(hsh) == 0:
                    decryptmessage += decryptiondict[hsh]
                    hshlen = len(hsh)
                    encryptmessage = encryptmessage[hshlen:
                                                    len(encryptmessage)]
                    break
            count += 1
            if count > 9999999999999:
                break
            
        return decryptmessage
        
    def set_password(self, raw_password, saltkey = None):
        import random
        randomkey = str(random.random()) + '$' + str(random.random())
        randomkeyutf16 = bytes(randomkey, 'utf-16')
        #store this salt, alongside your raw_password
        if saltkey == None:
            salt = hashlib.sha1()    
            salt.update(randomkeyutf16)
            saltkey = salt.hexdigest()[:5]
        preencryptpass = saltkey + '$' + raw_password
        pencryptutf16 = bytes(preencryptpass, 'utf-16')
        hshlb = hashlib.sha1()
        hshlb.update(pencryptutf16)
        hsh = hshlb.hexdigest()
        self.password = '%s$%s' % (saltkey, hsh)

    def check_password(self, raw_password):
        """
        Returns a boolean of whether the raw_password was correct. Handles
        encryption formats behind the scenes.
        """
        
        saltkey, hsh = self.password.split('$')
        preencryptpass = saltkey + '$' + raw_password
        pencryptutf16 = bytes(preencryptpass, 'utf-16')
        hshlb = hashlib.sha1()
        hshlb.update(pencryptutf16)
        hsh2 = hshlb.hexdigest()
        return hsh == hsh2

    def __init__(self, rawpassword):
        self.set_password(rawpassword)
        
rawpass = 'abcdeabcde'
a = encryption(rawpass)
print(a.password)
b = a.check_password('abcdeabcde')
encryptmessage, privatekey = a.encrypt_message('The cat walked home.  The eagle has landed.  The eagle has landed.')
print('encryptmessage: ', encryptmessage)
print('privatekey: ', privatekey)
decryptmessage = a.gen_decrypttables(privatekey, encryptmessage)
print (decryptmessage)
Basically a bit untested but example of thought code using an encryption method, couldn't speak as to its relative strengths or weakness here, but at least it provides a working encryption example here. Variations that I could think on the method above: extend the private key (creating more higher permutation sets on the encrypted message, and then create a modulus set that refer to the select truncation of the encrypted script object in an ordered way. For the later example, consider this you could instead choose a fragment of the original encrypted message, and then construct yet another set of random keys to be added to the present private key which instructs the user by way of ordering to search the overall hash object say with a 4 position truncation of the original message say starting at index position 3 of the original message. Thus a modulus set added to private key could look like: 02345. Which is  electing index 0 for the emessage fragment, index position 2 for the second,..., index 5 for fifth position. Then repeating this cycle of indexing on the whole of the message for letter encryption. Generally speaking the method above with a 7 position length private key, assuming a hack knew exactly the size of the private key to be generated, via brute force method could take 91^7 = 51,676,101,935,731 computations which is already up there in so far as code cracking algorithms. Adding larger private key sets extends this so that traditional brute force methods I would imagine are wholly impractical, and adding the modulus key for fragmenting parts of the original encryption method, reduces the size of the message more practically to that of the original.
Thus a stronger encryption version could look like this:
import hashlib
import random
alphanumer = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
              'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
              'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
              'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8',
              '9', '0', ' ', '.', '!', ',', '@', '#', '$', '%', '^', '&',
              '*', '(', ')', '-', '_', '+', '=', '[', ']', '{', '}', ':',
              ';', "'", '"', '?', '/', '>', '<']

class encryption:
    def generate_moduluskeyset(self, epart, moduluskeyset):
        #where epart is the encrypted partition
        epartlen = len(epart)
        mk = random.randint(0,len(epart)-6)
        moduluskeyset +=  str(mk) + ' ' 
        return moduluskeyset

    def generatemsetlen(self, epart):
        #7 set length, although you could extend this if you wanted
        #to.
        setrange = range(0, 7)
        moduluskeyset = ''
        for i in setrange:
            moduluskeyset = self.generate_moduluskeyset(epart,
                                                        moduluskeyset)
        return moduluskeyset, moduluskeyset.split(' ')
        
    def generate_privatekey(self):
        
        randomkey = str(random.random()) + '$' + str(random.random())
        randomkeyutf16 = bytes(randomkey, 'utf-16')
        #store this salt, alongside your raw_password
        salt = hashlib.sha1()    
        salt.update(randomkeyutf16)
        saltkey = salt.hexdigest()
        return saltkey

        
    def encrypt_message(self, raw_message):

        
        privatekey = self.generate_privatekey()
        encryptmessage = ''
        capture = False
        lindex = 0
        for letter in raw_message:
            preencryptpart = privatekey + letter
            pencryptutf16 = bytes(preencryptpart, 'utf-16')
            hshlb = hashlib.sha1()
            hshlb.update(pencryptutf16)
            hsh = hshlb.hexdigest()
            if not capture:
                moduluskeyset, mset = self.generatemsetlen(hsh)
                mset = mset[0:len(mset)-1]
##                print('e mset: ', mset)
                capture = True
                modk = len(mset)
            mpos = lindex % modk
##            print('mset ', mset[mpos])
            mstart = int(mset[mpos])
            mend = int(mset[mpos]) + 6
            encryptmessage += hsh[mstart:mend]
            lindex += 1
        privatekey += ' ' + moduluskeyset
        return encryptmessage, privatekey

    def gen_decrypttables(self, privatekeyg, encryptmessage):
        #this works in a limited context for western latin based scripts
        #you'd have to make sure to import the correct character set for
        #alternate languages.  I'd recommend encrypting into the private
        #key a language code to reduce computation times on character sets.
        keytables = privatekeyg.split(' ')
        privatekey = keytables[0]
##        print('private key: ', privatekey)
        mset = keytables[1:len(keytables)-1]
##        print(mset)
        modk = len(mset)
        decryptiondict = {}
        for letter in alphanumer:
            keystring = privatekey + letter
            bkeystring = bytes(keystring, 'utf-16')
            hshlb = hashlib.sha1()
            hshlb.update(bkeystring)
            hsh = hshlb.hexdigest()
            decryptiondict[hsh] = letter
        decryptmessage = ''
        count = 0
        
        while len(encryptmessage) > 0:
##            print(decryptmessage)
            mpos = count % modk
            mstart = int(mset[mpos])
            mend = int(mset[mpos]) + 6
            for hsh in decryptiondict:
                hshtrunc = hsh[mstart: mend]
                if encryptmessage.find(hshtrunc) == 0:
                    decryptmessage += decryptiondict[hsh]
                    hshlen = len(hshtrunc)
                    encryptmessage = encryptmessage[hshlen:
                                                    len(encryptmessage)]
                    break
            count += 1
            if count > 9999999999999:
                break
            
        return decryptmessage
        
    def set_password(self, raw_password, saltkey = None):
        
        randomkey = str(random.random()) + '$' + str(random.random())
        randomkeyutf16 = bytes(randomkey, 'utf-16')
        #store this salt, alongside your raw_password
        if saltkey == None:
            salt = hashlib.sha1()    
            salt.update(randomkeyutf16)
            saltkey = salt.hexdigest()[:5]
        preencryptpass = saltkey + '$' + raw_password
        pencryptutf16 = bytes(preencryptpass, 'utf-16')
        hshlb = hashlib.sha1()
        hshlb.update(pencryptutf16)
        hsh = hshlb.hexdigest()
        self.password = '%s$%s' % (saltkey, hsh)

    def check_password(self, raw_password):
        """
        Returns a boolean of whether the raw_password was correct. Handles
        encryption formats behind the scenes.
        """
        
        saltkey, hsh = self.password.split('$')
        preencryptpass = saltkey + '$' + raw_password
        pencryptutf16 = bytes(preencryptpass, 'utf-16')
        hshlb = hashlib.sha1()
        hshlb.update(pencryptutf16)
        hsh2 = hshlb.hexdigest()
        return hsh == hsh2

    def __init__(self, rawpassword):
        self.set_password(rawpassword)
        
rawpass = 'abcdeabcde'
a = encryption(rawpass)
print(a.password)
b = a.check_password('abcdeabcde')
encryptmessage, privatekey = a.encrypt_message('The cat walked home.  The eagle has landed.  The eagle has landed.')
print('encryptmessage: ', encryptmessage)
print('privatekey: ', privatekey)
decryptmessage = a.gen_decrypttables(privatekey, encryptmessage)
print (decryptmessage)
Here pattern predictions in theory or more likely broken up with respect to partitions of the original encrypted letter and privatekey. In theory repetitions of the encrypted letter alongside private key, are less likely repeated in the process of constructing the encrypted message. Thus making for it harder say for pattern recognition on the subset string blocks.

One could further increase the difficulty in patterning of encrypted partition segments on the overall message, by creating another modulus code set that relates to the lengths of the actual partition segments.  Thus instead of having say always 6 unit length segments, one could vary this pattern over the set of the entire message.  Thus a  space ' ' could represent in one instance 'a7'  and in another instance '7ahme'  in another instance, so that frequency distributions and expectations of patterns are further scrambled.  One should be careful in limiting partition lengths of the original encrypted message as nearly single place or two place representations can possibly lead to equivalences with hashed character sets.  Thus the finally I have:


import hashlib
import random
alphanumer = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
              'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
              'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
              'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8',
              '9', '0', ' ', '.', '!', ',', '@', '#', '$', '%', '^', '&',
              '*', '(', ')', '-', '_', '+', '=', '[', ']', '{', '}', ':',
              ';', "'", '"', '?', '/', '>', '<']

class encryption:
    def generate_moduluslenkeyset(self, epart):
        epartlen = len(epart)
        setrange = range(0, 7)
        rmodlenkeyset = []
        for i in setrange:
            if epartlen > 12:
                ml = random.randint(6,12)
            else:
                ml = random.randint(6, epartlen)
            rmodlenkeyset.append(ml)
        return rmodlenkeyset
        
    
    def generate_moduluskeyset(self, epart, rmodlenkey, moduluskeyset):
        #where epart is the encrypted partition
        epartlen = len(epart)
        mk = random.randint(0,len(epart)-rmodlenkey)
        moduluskeyset +=  str(mk) + ' ' 
        return moduluskeyset

    def generatemsetlen(self, epart):
        #7 set length, although you could extend this if you wanted
        #to.
        setrange = range(0, 7)
        moduluskeyset = ''
        rmodlenkeyset = self.generate_moduluslenkeyset(epart)
        index = 0
        for i in setrange:
            rmodlenkey = rmodlenkeyset[i]
            moduluskeyset = self.generate_moduluskeyset(epart, rmodlenkey,
                                                        moduluskeyset)
            index += 1

        mset = moduluskeyset.split(' ')

        for rmodlenkey in rmodlenkeyset:
            moduluskeyset += str(rmodlenkey) + ' '
            
        return moduluskeyset, mset, rmodlenkeyset 
        
    def generate_privatekey(self):
        
        randomkey = str(random.random()) + '$' + str(random.random())
        randomkeyutf16 = bytes(randomkey, 'utf-16')
        #store this salt, alongside your raw_password
        salt = hashlib.sha1()    
        salt.update(randomkeyutf16)
        saltkey = salt.hexdigest()
        return saltkey

        
    def encrypt_message(self, raw_message):

        
        privatekey = self.generate_privatekey()
        encryptmessage = ''
        capture = False
        lindex = 0
        for letter in raw_message:
            preencryptpart = privatekey + letter
            pencryptutf16 = bytes(preencryptpart, 'utf-16')
            hshlb = hashlib.sha1()
            hshlb.update(pencryptutf16)
            hsh = hshlb.hexdigest()
            if not capture:
                moduluskeyset, mset, rmodlenkeyset = self.generatemsetlen(hsh)
                mset = mset[0:len(mset)-1]
##                print('e mset: ', mset)
                capture = True
                modk = len(mset)
                modl = len(rmodlenkeyset)
            mpos = lindex % modk
            mlpos = lindex % modl
##            print('mset ', mset[mpos])
##            print('mlset', rmodlenkeyset[mlpos])
            mstart = int(mset[mpos])
            mend = int(mset[mpos]) + rmodlenkeyset[mlpos]
            encryptmessage += hsh[mstart:mend]
            lindex += 1
        privatekey += ' ' + moduluskeyset
        print('mset ', mset)
        print('mlset ',rmodlenkeyset)
        
        return encryptmessage, privatekey

    def gen_decrypttables(self, privatekeyg, encryptmessage):
        #this works in a limited context for western latin based scripts
        #you'd have to make sure to import the correct character set for
        #alternate languages.  I'd recommend encrypting into the private
        #key a language code to reduce computation times on character sets.
        keytables = privatekeyg.split(' ')
        privatekey = keytables[0]
##        print('private key: ', privatekey)
        msetmlset = keytables[1:len(keytables)-1]

        setrange = range(0, 7)
        mset = []
        mlset = []
        for i in setrange:
            mset.append(msetmlset[i])
            mlset.append(msetmlset[i + 7])
        print('mset: ', mset)
        print('mlset: ',mlset)
        
        modk = len(mset)
        modl = len(mlset)
        decryptiondict = {}
        for letter in alphanumer:
            keystring = privatekey + letter
            bkeystring = bytes(keystring, 'utf-16')
            hshlb = hashlib.sha1()
            hshlb.update(bkeystring)
            hsh = hshlb.hexdigest()
            decryptiondict[hsh] = letter
        decryptmessage = ''
        count = 0
        
        while len(encryptmessage) > 0:
##            print(decryptmessage)
            mpos = count % modk
            mlpos = count % modl
            mstart = int(mset[mpos])
            mend = int(mset[mpos]) + int(mlset[mlpos])
            for hsh in decryptiondict:
                hshtrunc = hsh[mstart: mend]
                if encryptmessage.find(hshtrunc) == 0:
                    decryptmessage += decryptiondict[hsh]
                    hshlen = len(hshtrunc)
                    encryptmessage = encryptmessage[hshlen:
                                                    len(encryptmessage)]
                    break
            count += 1
            if count > 9999999999999:
                break
            
        return decryptmessage
        
    def set_password(self, raw_password, saltkey = None):
        
        randomkey = str(random.random()) + '$' + str(random.random())
        randomkeyutf16 = bytes(randomkey, 'utf-16')
        #store this salt, alongside your raw_password
        if saltkey == None:
            salt = hashlib.sha1()    
            salt.update(randomkeyutf16)
            saltkey = salt.hexdigest()[:5]
        preencryptpass = saltkey + '$' + raw_password
        pencryptutf16 = bytes(preencryptpass, 'utf-16')
        hshlb = hashlib.sha1()
        hshlb.update(pencryptutf16)
        hsh = hshlb.hexdigest()
        self.password = '%s$%s' % (saltkey, hsh)

    def check_password(self, raw_password):
        """
        Returns a boolean of whether the raw_password was correct. Handles
        encryption formats behind the scenes.
        """
        
        saltkey, hsh = self.password.split('$')
        preencryptpass = saltkey + '$' + raw_password
        pencryptutf16 = bytes(preencryptpass, 'utf-16')
        hshlb = hashlib.sha1()
        hshlb.update(pencryptutf16)
        hsh2 = hshlb.hexdigest()
        return hsh == hsh2

    def __init__(self, rawpassword):
        self.set_password(rawpassword)
        
rawpass = 'abcdeabcde'
a = encryption(rawpass)
print(a.password)
b = a.check_password('abcdeabcde')
encryptmessage, privatekey = a.encrypt_message('The cat walked home.  The eagle has landed.  The eagle has landed.')
print('encryptmessage: ', encryptmessage)
print('privatekey: ', privatekey)
decryptmessage = a.gen_decrypttables(privatekey, encryptmessage)
print (decryptmessage)

This last generation of encryption leads to variable character set partition for character encryption representations.  This further compounds to difficulty in detecting not only frequency of character distributions by way of pattern matching, but also increases difficulty in detecting total character lengths of an inset message.  One could suspect really long messages and files that are encrypted still could have some relative frequency of string encryption occurring with higher proximity.  It seems that even further methods could be devised in randomizing encrypted character partition string distributions, however, or if really interested I am sure you could find advanced research in the area of this topic elsewhere on the internet.

encryptionscript in python

This works off python's native modules so you hadn't need download or install any other modules to operate.

No comments:

Post a Comment

Oblivion

 Between the fascination of an upcoming pandemic ridden college football season, Taylor Swift, and Kim Kardashian, wildfires, crazier weathe...