You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.6 KiB
117 lines
3.6 KiB
#!/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)
|
|
|