Christophe HENRY
3d71aa2e6f
It's not designed to be used for cryptographic stuff, unless you know what you're doing or you want to hide from your little sister. Xit processes files in the memory and is not designed to treat huge data.
117 lines
3.6 KiB
Python
117 lines
3.6 KiB
Python
#!/usr/bin/python3
|
|
|
|
import os, re, sys, random, hashlib
|
|
import sys
|
|
from utils import Sha1File
|
|
|
|
useUrandom = True
|
|
|
|
def xorIterable(data):
|
|
""" Xors the iterable data, each element againts all the others """
|
|
|
|
def xorList(data):
|
|
""" Computes [var0^var1^var2^... for (var0,var1,var2,...) in zip(*data)]
|
|
It's more effecient this way instead of
|
|
|
|
xoredData = bytearray()
|
|
for d in zip(*data):
|
|
acc = 0
|
|
for byte in d: acc ^= byte
|
|
xoredData.append(acc)
|
|
|
|
or this way:
|
|
|
|
xoredData = bytearray([functools.reduce(operator.xor,d) for d in zip(*data)])
|
|
"""
|
|
|
|
assert(len(data)>1)
|
|
variables = ["var"+str(i) for i in range(len(data))]
|
|
expressionGauche = "^".join(variables)
|
|
expressionDroite = "("+",".join(variables)+")"
|
|
expression = "["+expressionGauche + " for " + expressionDroite
|
|
#XNOR: expression = "[~("+expressionGauche + ")%256 for " + expressionDroite
|
|
expression += " in zip(*data)]"
|
|
return eval(expression)
|
|
|
|
assert(len(data))
|
|
xoredData = data[0] if len(data)==1 else xorList(data) # len=1 => xor([data]) == data
|
|
return bytearray(xoredData)
|
|
|
|
|
|
def resizeData(dataIterable, size=None):
|
|
""" Expands dataIterable elements so they reach the maximum length, truncate to size
|
|
|
|
Size can be either smaller than the smallest data or bigger than the bigest data
|
|
|
|
"""
|
|
|
|
if type(size) is int and size > 0:
|
|
for data in dataIterable:
|
|
del data[size:]
|
|
lenMax = max([len(data) for data in dataIterable]+[size if size else 0])
|
|
for data in dataIterable:
|
|
lenData = len(data)
|
|
for i in range(lenData, lenMax):
|
|
data.append(data[i%lenData])
|
|
|
|
|
|
def xorData(inData, count, size):
|
|
""" returns count random xored data from inData
|
|
|
|
Example: len(inData) == 3 and count == 4
|
|
So:
|
|
clear = inData[0] XOR inData[1] XOR inData[2]
|
|
xored = rand1, rand2, rand3, rand1 XOR rand2 XOR rand3 XOR clear
|
|
return shuffle(xored)
|
|
|
|
"""
|
|
if type(inData) is not list: inData = [inData]
|
|
|
|
# resize data, all of them of the same size
|
|
resizeData(inData, size if type(size) is int else None)
|
|
|
|
# From this point:
|
|
# if size is min, then fine, data will be truncated
|
|
# if size is max, then the looping was just made
|
|
# if size is even (default), then the size were successfuly checked
|
|
|
|
# Xors the input data
|
|
if len(inData):
|
|
clearContent = xorIterable(inData)
|
|
elif type(size) is int: # No input data, thus generating random file
|
|
clearContent = bytearray(getRandomBytes(size))
|
|
else:
|
|
raise Exception("No input file specified, use --size with an integer to build a random file.")
|
|
|
|
|
|
# If more than one outputs, adds random data, so that
|
|
# All of it is random, except the last one with the data
|
|
outData = [bytearray(getRandomBytes(len(clearContent))) for _ in range(count-1)] \
|
|
+ [clearContent]
|
|
|
|
# Xor the random data and the clear data and replaces the last element
|
|
# containing the clear data by the result
|
|
outData[-1] = xorIterable(outData)
|
|
|
|
# Until now, all outs are kind of "keys" and the last one is "encrypted"
|
|
# With shuffle, one won't tell the difference
|
|
random.shuffle(outData)
|
|
|
|
# Test
|
|
#assert(xorIterable(inData)==clearContent)
|
|
#assert(xorIterable(outData)==clearContent)
|
|
|
|
return outData
|
|
|
|
|
|
def getRandomBytes(size):
|
|
""" Returns random bytes
|
|
|
|
The non urandom way is slower and uses Python getrandbits().
|
|
"""
|
|
if useUrandom:
|
|
return os.urandom(size)
|
|
else:
|
|
return random.getrandbits(size<<2).to_bytes(size, sys.byteorder)
|
|
|