# Trogramming

54726f6772616d6d696e672e636f6d

# Rubik’s Crypt

This one’s a recent release of mine, I spontaneously had the idea while walking to the shops.

It’s called Rubik’s Crypt due to the Rubik’s cube being the closest real world counterpart, as the inspiration.

The process runs as such:
Create an NxNxN grid where N is the ceiling of the cubed root of the length of your input)

The input is copied to the grid byte by byte, first placed left to right, then top to bottom, then forward to back

for example, in a 3^3 grid the alphabet would be:
[[[97, 98, 99], [100, 101, 102], [103, 104, 105]], [[106, 107, 108], [109, 110, 111], [112, 113, 114]], [[115, 116, 117], [118, 119, 120], [121, 122, _]]]

The final space is empty since there are 26 letters in the alphabet and 27 (3 cubed) spaces available, this blank space can be replaced with any character at all, or left as whitespace, in my version each vacant space is filled with a random char

Once the cube is initialised, you can rotate 2d sections of it independently from the rest, there are functions which rotate only even numbered cross sections, others only odd.

There are functions for mirroring and flipping, as well as swapping every (n2)th point with it’s right hand neighbour where one exists, and one for swapping each (n2+1)th point with it’s right hand neighbour; These functions are reverseable simply by performing them a second time, whereas the rotations can be reversed by using the opposite direction.

For the actual encryption instructions I am producing a SHA256 digest from user password and a salt, then using the resulting bytes as sequences of instructions for encrypting the cube, to decrypt it simply generated the same digest and run the inverse functions (i.e. 90 degrees right instead of left, flips and swaps are their own inverse) in the opposite order

To install it into your command line on windows (and therefore most programming languages with system() popen() or an equivalent) create a batch file rubikscrypt.bat as follows,
`@echo offpython c:/mypath/rubikscrypt.py> %*`
and make sure to put the batch file in on of the directories in your path (start menu search -> edit the system environment variables -> Environment Variables ->path)

## Usage

Options E to encrypt string, D to decrypt string
EF to encrypt file (must also have an output name after the password)
DF to decrypt file (must also have an output name after the password)

e.g.
rubikscrypt E “Encrypt This String” Password
rubikscrypt D “Decrypt This String” Password

## Security Warning

This is only a Transposition Cipher for shuffling the order of data, it wouldn’t withstand analysis as the frequency distribution of bytes will be the same as the input, it will make the presence and language of the communication obvious (with a large enough section of text).
If you’ve encoded plaintext it could be decoded by looking for anagrams in the form of valid grammar, assuming you use a legible grammar.
Similarly pulse code modulations could be recognized by a normal distribution around a certain value.

This was only a hobby project to scratch an itch.
If you want to use it for practical cryptography you would have to pair it with some sort of position-dependent character substitution before/after/during the shuffling process (transposition).

For real world cryptography please use a well-trusted build of a highly tested standard.

``````from math import ceil
from random import randint
from hashlib import sha256
import sys

Instructions="""
e.g.
rubikscrypt E "Encrypt This String" Password
rubikscrypt D "Decrypt This String" Password
"""
def random_char():
return randint(64,128)

def pack_cube(string,side):
if type(string)==bytes or type(string)==bytearray:
input_bytes=string
else:
input_bytes=[ord(i) for i in string]
n=0
cube=[]
for x in range(side):
a=[]
for y in range(side):
b=[]
for z in range(side):
if n<len(string):
b.append(input_bytes[n])
else:
b.append(random_char())
n+=1
a.append(b)
cube.append(a)
return cube

def unpack_cube(cube,outtype="bytes"):
side=len(cube)
s=""
b=bytearray(b"")
if outtype=="string":
for x in range(side):
for y in range(side):
for z in range(side):
val=cube[x][y][z]
s+=chr(val)
return s
elif outtype=="bytes":
for x in range(side):
for y in range(side):
for z in range(side):
val=cube[x][y][z]
b.append(val)
return b

def rotate_plane_left(plane):
return list(zip(*plane[::-1]))

def rotate_plane_right(plane):
return list(zip(*plane))[::-1]

testo=[[1,2,3],
[4,5,6],
[7,8,9]]

leftrot=rotate_plane_left(testo)
lrrot=rotate_plane_right(leftrot)
lrrot=testo
class rubiks_crypt:
def __init__(self,string):
self.string=string
self.length=len(string)
self.sidelength=ceil(self.length**(1.0/3))
self.cube=pack_cube(self.string,self.sidelength)
def switch_rows1(self):
newcube=[]
for x in range(self.sidelength):
a=[]
for y in range(0,self.sidelength,2):
if y+1<self.sidelength:
a.append(self.cube[x][y+1])
a.append(self.cube[x][y])
newcube.append(a)
self.cube=newcube
def reverse2_even(self):
for x in range(self.sidelength):
if x%2==0:
self.cube[x]=list(self.cube[x])
self.cube[x].reverse()
def reverse2_odd(self):
for x in range(self.sidelength):
if x%2==1:
self.cube[x]=list(self.cube[x])
self.cube[x].reverse()
def reverse3(self):
for x in range(self.sidelength):
for y in range(self.sidelength):
self.cube[x][y]=list(self.cube[x][y])
self.cube[x][y].reverse()
def reverse3_even(self):
for x in range(self.sidelength):
for y in range(self.sidelength):
self.cube[x][y]=list(self.cube[x][y])
if y%2==0:
self.cube[x][y].reverse()
def reverse3_odd(self):
for x in range(self.sidelength):
for y in range(self.sidelength):
self.cube[x][y]=list(self.cube[x][y])
if y%2==1:
self.cube[x][y].reverse()
def switch_rows2(self):
newcube=[]
for x in range(self.sidelength):
a=[self.cube[x][0]]
for y in range(1,self.sidelength,2):
if y+1<self.sidelength:
a.append(self.cube[x][y+1])
a.append(self.cube[x][y])
newcube.append(a)
self.cube=newcube
def switch_points1(self):
newcube=[]
for x in range(self.sidelength):
a=[]
for y in range(self.sidelength):
b=[]
for z in range(0,self.sidelength,2):
if z+1<self.sidelength:
b.append(self.cube[x][y][z+1])
b.append(self.cube[x][y][z])
a.append(b)
newcube.append(a)
self.cube=newcube

def switch_points2(self):
newcube=[]
for x in range(self.sidelength):
a=[]
for y in range(self.sidelength):
b=[self.cube[x][y][0]]
for z in range(1,self.sidelength,2):
if z+1<self.sidelength:
b.append(self.cube[x][y][z+1])
b.append(self.cube[x][y][z])
a.append(b)
newcube.append(a)
self.cube=newcube
def rotate_left(self):#rotates all left
newcube=[]
for plane in self.cube:
newcube.append(rotate_plane_left(plane))
self.cube=newcube
def rotate_right(self):#rotates all right
newcube=[]
for plane in self.cube:
newcube.append(rotate_plane_right(plane))
self.cube=newcube
def rotate_even_left(self):
newcube=[]
for n in range(self.sidelength):
plane=self.cube[n]
if n%2==0:
newcube.append(rotate_plane_left(plane))
else:
newcube.append(plane)
self.cube=newcube
def rotate_even_right(self):
newcube=[]
for n in range(self.sidelength):
plane=self.cube[n]
if n%2==0:
newcube.append(rotate_plane_right(plane))
else:
newcube.append(plane)
self.cube=newcube
def rotate_odd_left(self):
newcube=[]
for n in range(self.sidelength):
plane=self.cube[n]
if n%2==1:
newcube.append(rotate_plane_left(plane))
else:
newcube.append(plane)
self.cube=newcube
def rotate_odd_right(self):
newcube=[]
for n in range(self.sidelength):
plane=self.cube[n]
if n%2==1:
newcube.append(rotate_plane_right(plane))
else:
newcube.append(plane)
self.cube=newcube
def flip1(self):
outcube=[]
for i in range(self.sidelength):
outcube.append(self.cube[-i])
self.cube=outcube
def flip2(self):
outcube=[]
for x in range(self.sidelength):
a=[]
for y in range(self.sidelength):
a.append(self.cube[x][-y])
outcube.append(a)
self.cube=outcube
def make_string(self):
return unpack_cube(self.cube,"string")
def make_bytes(self):
return unpack_cube(self.cube,"bytes")
functions=[self.rotate_left,self.rotate_right,
self.rotate_even_left,self.rotate_odd_left,
self.rotate_even_right,self.rotate_odd_right,
self.switch_rows1,self.switch_rows2,
self.switch_points1,self.switch_points2,
self.reverse2_even,self.reverse2_odd,self.reverse3,self.reverse3_even,self.reverse3_odd,
self.flip1,self.flip2]
lf=len(functions)
hd=digest.hexdigest()
for i in range(32):
val=int(hd[i:i+2],16)
func=functions[val%lf]
func()
functions=[self.rotate_right,self.rotate_left,
self.rotate_even_right,self.rotate_odd_right,
self.rotate_even_left,self.rotate_odd_left,
self.switch_rows1,self.switch_rows2,
self.switch_points1,self.switch_points2,
self.reverse2_even,self.reverse2_odd,self.reverse3,self.reverse3_even,self.reverse3_odd,
self.flip1,self.flip2]
lf=len(functions)
hd=saltedhash.hexdigest()
for n in range(32):
i=31-n
val=int(hd[i:i+2],16)
func=functions[val%lf]
func()
s=""
ls=len(salt)
for i in range(lp2):
if i%2==0:
else:
s+=salt[int(i/2)%ls]
return s.encode('utf-8')

def file_to_bytes(Name):
file=open(Name,'rb')
bytestream=bytearray(b"")
while 1:
if val==b"":
break
bytestream.append(val[0])
return bytestream

inbytes=file_to_bytes(InFile)
crypt=rubiks_crypt(inbytes)
outbytes=crypt.make_bytes()
Outfile=open(OutFile,"wb")
from struct import pack
Outfile.write(pack("L",len(inbytes)))
Outfile.write(outbytes)

inbytes=file_to_bytes(InFile)
from struct import unpack
length=unpack("L",inbytes[0:4])[0]
inbytes=inbytes[4:]
crypt=rubiks_crypt(inbytes)
outbytes=crypt.make_bytes()[:length]
Outfile=open(OutFile,"wb")
Outfile.write(outbytes)

crypt=rubiks_crypt(String)
return crypt.make_string()

crypt=rubiks_crypt(String)
return crypt.make_string()

if len(sys.argv)==4:
#first is name, second is string ,3rd is password
if directive=="E":
elif directive=="D":
else:
print(Instructions)
elif len(sys.argv)==5: