Author Topic: [Python] String Encryption (First completed project)  (Read 845 times)

0 Members and 1 Guest are viewing this topic.

Offline Kolsulfr

  • /dev/null
  • *
  • Posts: 5
  • Cookies: 0
    • View Profile
[Python] String Encryption (First completed project)
« on: January 08, 2016, 09:33:12 pm »
So, after a couple months of trial and error I've finally got this to the point I feel like I can call it "complete." There are still plenty of things I feel could be cleaner/more logically sound but I've decided to let the obsessive cycle of ripping it apart and putting it back together come to an end and let it be. Feel free to tear it to shreds, the more information I have about what could have been better the better.

It'd be trivial to crack, as I know absolutely nothing about encryption, but it was a fun first project.

Furthermore, it's in desperate need of comments (it has none) and protective measures to make sure you can't throw it inputs that'll break it (and if you do, get a clue as to what broke) but.. Put it off til last and then didn't get around to it. (Python also wasn't the best language for something like this.)

Anyway, first off, practical usage. For both the encrypt and decrypt functions (contained in the main FENRIS.py file) you just throw them a key as well as a string to be encrypted/decrypted, main point to note being the key, the key is a list where the first place contains a variable representing the number of axises you want in the grid (2, 3, 30,000) followed by any number of variables so long as each following variable keeps within the confines of (2 ** the grids dimensions) (the number of possible directions the branch can go towards it's given corner of the grid, but I'll get into that in a minute.)

It also comes with a pre-packaged key generator.

1000 axises with a 1000 step pattern takes about a minute to encrypt a 5 character string, and uses ALL my computers memory, so that's about upper bounds for me. More sensible keys work smoothly enough.

Now, trying to put into words what it does...

Basically, it creates a grid with whatever number of dimensions the user specifies and sends each character out towards the corners of the grid. So, for example, on a 2D grid, it would send the first character out towards (-1,-1), next one out (-1,1), then (1,-1), (1,1), and then the next character would go back over to (-1,-1), "pushing" the previous character out further towards the corner, occupying the space said previous character occupied prior.

It gets the full set of coordinates for all the corners by continuously adding 1 to a binary string and extracting the next set of results as each new character gets pushed out of the center (ultimately exhausting all possibilities of either 1 (a positive direction on that axis) or 0 (not a positive direction on that axis.))

Then, each time a character is sent outward in this way, it occupies a "branch" of coordinates based on the key, the total number of directions it can go in during any given step in the pattern and still be going towards the corner being (2 ** the grids dimensions); also gotten by adding 1 to a binary string, on each axis being either 1 (going towards that corner along that axis) or 0 (not moving along that axis.) Each identical "branching" of coordinate points containing the ordinal value of a character.

At this point, it takes each branch, and uses the combination of all of it's coordinate points as the seed for a random generator, generates a random value between 0-255 for each of the coordinate points in the branch, then takes the ordinal value, and fragments it unevenly along each point in the branch proportional to the random value generated. It then extracts the fragmented bits and pieces from all the coordinate points, and returns it all as a hex string.

Decryption is almost the exact opposite, but it takes the number of values in the encrypted string divided by the number of steps in the pattern (the number of characters in the un-encrypted string,) and sends out that many "blank" branches. It then gets all the same random seeds from all the same coordinate points, throws all the values back into the right slots backwards, defragments each branch and sucks them back all into the center of the structure, converts the numbers back to their character equivalent and you've got the string back.

FENRIS.PY
Code: [Select]
import FENRIS_Gridbox
import random

def encrypt(key, encStr):
    g = FENRIS_Gridbox.encGrid(key[0], key[1:])

    for c in encStr:
        g.abstractChar(c = c)

    g.bindAndFragmentAllPaths()
    return g.shuffleAndExtract()

def decrypt(key, encStr):
    g = FENRIS_Gridbox.decGrid(key[0], key[1:])
   
    g.storeEncStr(encStr)
    g.abstractBlanks()
    g.inputValues()
    g.extractFragments()
    g.defragmentAndExtractAllPaths()
   
    return g.finalizeAndReturn()
   
def generateKey(dimensions, length):
    return [dimensions,]+[random.randrange(1,(2**dimensions)) for i in range(length)]

FENRIS_Gridbox.PY
Code: [Select]
import FENRIS_Core

class encGrid(FENRIS_Core.grid):
    def __init__(self, dimensions, pattern):
        FENRIS_Core.grid.__init__(self, dimensions, pattern)
       
    def bindAndFragmentAllPaths(self):
        for p in self.pathRoots:
            self.pathRoots[p].bindAndFragment()

    def shuffleAndExtract(self):
        keys = self.points.keys()
        return ''.join(hex(self.points[k].getValue()) for k in keys)
       
class decGrid(FENRIS_Core.grid):
    def __init__(self, dimensions, pattern):
        FENRIS_Core.grid.__init__(self, dimensions, pattern)
       
    def storeEncStr(self, encStr):
        self.encStr = [int('0x' + x, 16) for x in encStr.split('0x')[1:]]
       
    def abstractBlanks(self):
        for i in range(len(self.encStr)/len(self.pattern)):
            self.abstractChar()
           
    def inputValues(self):
        keys = self.points.keys()
        for i in range(len(keys)):
            self.points[keys[i]].setValue(self.encStr[i])
   
    def extractFragments(self):
        for p in self.pathRoots:
            for b in self.pathRoots[p].getBranches():
                for c in b.getCoordList():
                    b.appendFragment(self.points[c].getValue())
                   
    def defragmentAndExtractAllPaths(self):
        for p in self.pathRoots:
            self.pathRoots[p].defragmentAndExtract()
           
    def finalizeAndReturn(self):
        returnString = []
        for i in range(len(self.encStr)/len(self.pattern)):
            self.cycle.next()
            returnString.append(self.pathRoots[self.cycle.send(True)].extractValue())
        return ''.join(chr(c) for c in returnString)[::-1]
       
class testGrid(encGrid, decGrid):
    def __init__(self, dimensions, pattern):
        FENRIS_Core.grid.__init__(self, dimensions, pattern)

FENRIS_Core.PY
Code: [Select]
import random

class point(object):
    def __init__(self):
        self.value = 0

    def setValue(self, value):
        self.value = value
    def getValue(self):
        return self.value

class branch(object):
    def __init__(self, coordList):
        self.coordList = coordList
        self.value = 0
        self.contortedCoordList = []
        self.contortedChunk = 0
        self.fragments = []
        self.calibrate()

    def calibrate(self):
        for c in self.coordList:
            random.seed(''.join(str(i) for i in c))
            self.contortedCoordList.append(random.randrange(0, 255))
       
        for c in self.contortedCoordList:
            self.contortedChunk += c
           
    def setValue(self, value):
        self.value = value
    def getValue(self):
        return self.value
    def getCoordList(self):
        return self.coordList
    def getFragments(self):
        return self.fragments
    def appendFragment(self, f):
        self.fragments.append(f)

    def fragment(self):
        whole = float(self.value + self.contortedChunk)
        for c in self.contortedCoordList:
            self.fragments.append(int((whole / self.contortedChunk) * c))

        self.fragments[-1] = self.fragments[-1] + int(whole - sum(self.fragments))
       
    def defragment(self):
        self.value = sum(self.fragments) - self.contortedChunk

class pathRoot(object):
    def __init__(self, rootGrid, direction):
        self.rootGrid = rootGrid
        self.direction = direction
        self.currPoint = list(direction)
        self.branches = []
        self.values = []
       
    def addValue(self, value):
        self.values = [value, ] + self.values
    def extractValue(self):
        return self.values.pop(0)
    def getBranches(self):
        return self.branches

    def createBranch(self, pattern):
        hold = []

        for i in range(len(pattern)):
            self.currPoint = [x + y for x, y in zip(self.currPoint, self.binaryToStep(self.rootGrid.binaryAdd(''.join('0' for d in range(len(self.direction))), pattern[i])))]
            hold.append(tuple(self.currPoint))
            self.rootGrid.createPoint(tuple(self.currPoint))
       
        self.branches = [branch(hold), ] + self.branches
       
    def binaryToStep(self, binStr):
        hold = []

        for i in range(len(binStr)):
            if int(binStr[i]) == 0:
                hold.append(0)
            elif self.direction[i] > 0:
                hold.append(1)
            else:
                hold.append(-1)

        return hold
       
    def bindAndFragment(self):
        for i in range(len(self.values)):
            self.branches[i].setValue(self.values[i])
            self.branches[i].fragment()
            for x in range(len(self.branches[i].getCoordList())):
                self.rootGrid.getPoints()[tuple(self.branches[i].getCoordList()[x])].setValue(self.branches[i].getFragments()[x])
                   
    def defragmentAndExtract(self):
        for b in self.branches:
            b.defragment()
            self.values.append(b.getValue())

class grid(object):
    def __init__(self, dimensions, pattern):
        self.dimensions = dimensions
        self.pattern = pattern
        self.pathRoots = {}
        self.points = {}

        self.cycle = self.cycleGen(''.join('0' for i in range(self.dimensions)))
       
    def getPoints(self):
        return self.points
               
    def cycleGen(self, binStr):
        cycle = [0, ]
        fbreak = 1
        frev = 1
        while True:
            rev = yield
            if rev == False:
                if len(self.pathRoots) < (2 ** self.dimensions):
                    self.pathRoots[cycle[0]] = pathRoot(self, self.binaryToDirectional(binStr))
                    binStr = self.binaryAdd(binStr)
                    yield cycle[0]
                    cycle = [cycle[0]+1, ] + cycle
                else:
                    if fbreak == 1:
                        cycle = cycle[1:]
                        cycle = [cycle[-1], ] + cycle[:-1]
                        fbreak = 0
                    yield cycle[0]
                    cycle = [cycle[-1], ] + cycle[:-1]
            elif rev == True:
                if fbreak == 1:
                    cycle = cycle[1:]
                    cycle = [cycle[-1], ] + cycle[:-1]
                    fbreak = 0
                if frev == 1:
                    cycle = cycle[1:] + [cycle[0], ]
                    frev = 0
                yield cycle[0]
                cycle = cycle[1:] + [cycle[0], ]
           
    def binaryToDirectional(self, binStr):
        return tuple([int(c) for c in binStr.replace('1','1 ').replace('0','-1 ').split(' ')[:-1]])
           
    def binaryAdd(self, num, amount = 1):
        x = bin(int('0b' + num, 2) + amount)[2:]
        return num[:-len(x)] + x       
       
    def abstractChar(self, c = None):
        self.cycle.next()
        cyclePoint = self.cycle.send(False)
       
        self.pathRoots[cyclePoint].createBranch(self.pattern)
        if c:
            self.pathRoots[cyclePoint].addValue(ord(c))
                   
        if ((cyclePoint + 1) % 2 == 0):
            pass
        else:
            self.advancePattern()
               
    def advancePattern(self):
        hold = []
        for i in self.pattern:
            if i == (2**self.dimensions)-1:
                hold.append(i)
            elif i == (2**self.dimensions)-2:
                hold.append(1)
            else:
                hold.append(i + 1)
        self.pattern = tuple(hold)
       
    def createPoint(self, coords):
        self.points[tuple(coords)] = point()
« Last Edit: January 17, 2016, 12:57:08 am by Kolsulfr »