def s4_decode(keys,output): interpolator = PGF256Interpolator() zero = GF256elt(0) data = "" for i in keys: i.seek(0) # End Of Key eok = False while not eok: points = [] for i in xrange(0,len(keys)): while True: b = keys[i].read(1) if 0 == len(b): eok = True break # Skip points with X value of 0, they were added to respect the entropy of the output X = ord(b) if 0 == X: keys[i].seek(keys[i].tell() + 1) else: break if eok: break # Extract X/Y Y = ord(keys[i].read(1)) # Push point points.append((GF256elt(X),GF256elt(Y))) if eok: if 0 != i: raise Exception('Unexpected EOF while reading key %d' % i) break # Decode next byte byte = interpolator.interpolate(points).f(zero) data += chr(byte) # check for successful decode signature = data[0:8] data = data[8:] rv = True if ('GF256OK_' in signature) else False output.write(data) output.seek(0) return rv
def __Lj(self,points,j): result = GF256elt(1) x = PGF256((GF256elt(0),GF256elt(1))) for i in xrange(0,len(points)): if j == i: continue # P = x P = x P = (P - points[i][0]) * (GF256elt(1) / (points[j][0] - points[i][0])) result = P * result return result
def __sub__(self, other): if isinstance(other, GF256elt): c = self.coeffs() c[0] -= other return PGF256(c) if not isinstance(other, PGF256): raise Exception() minDeg = min(self.deg(), other.deg()) maxDeg = max(self.deg(), other.deg()) coeffs = [] for i in xrange(0, minDeg + 1): coeffs.append(self.coeff(i) - other.coeff(i)) zero = GF256elt(0) for i in xrange(minDeg + 1, maxDeg + 1): if self.deg() > other.deg(): coeffs.append(self.coeff(i)) else: coeffs.append(zero - other.coeff(i)) return PGF256(coeffs)
def coeff(self, i): "Return the coefficient for x^i." if i >= len(self.__coefficients): return GF256elt(0) else: return self.__coefficients[i]
def pickRandomPolynomial(degree,zero): """Pick a random PGF256 polynomial P such that P(0) = zero""" coeffs = [] # Set f(0) coeffs.append(zero) # Pick coefficients for x^n with n < degree for c in xrange(1,degree): coeffs.append(GF256elt(random.randint(0,255))) # Pick non null coefficient for x^degree coeffs.append(GF256elt(random.randint(1,255))) return PGF256(coeffs)
def decode(keys,output): interpolator = PGF256Interpolator() zero = GF256elt(0) data = "" # End Of Key eok = False while not eok: points = [] for i in xrange(0,len(keys)): while True: b = keys[i].read(1) if 0 == len(b): eok = True break # Skip points with X value of 0, they were added to respect the entropy of the output X = ord(b) if 0 == X: keys[i].seek(keys[i].tell() + 1) else: break if eok: break # Extract X/Y Y = ord(keys[i].read(1)) # Push point points.append((GF256elt(X),GF256elt(Y))) if eok: if 0 != i: raise Exception('Unexpected EOF while reading key %d' % i) break # Decode next byte byte = interpolator.interpolate(points).f(zero) output.write(chr(byte))
def coeffs(self): "Return a clone of the array of coefficients" c = [] zero = GF256elt(0) for i in xrange(0, self.deg() + 1): c.append(self.coeff(i) + zero) return c
def _s4_encodeByte(byte,n,k): # Allocate array to track duplicates picked = [False for i in xrange(0,256)] # Pick a random polynomial P = pickRandomPolynomial(k-1,GF256elt(byte)) # Generate the keys keys = ["" for i in xrange(0,n)] for i in xrange(0,n): # # Pick a not yet picked X value in [0,255], # we need a value in [1,255] but to have a credible entropy for bytes we pick it in [0,255] # and simply output garbage if we picked 0 # If we do not do that then the output keys will NEVER have 00 in even positions (starting # at 0) which would be a little suspicious for some random data # pick = random.randint(1,255) while picked[pick] or pick == 0: # 0 values will be discarded but output it anyway with trailing garbage if pick == 0: keys[i] += chr(0) keys[i] += chr(random.randint(0,255)) pick = random.randint(1,255) # Keep track of the value we just picked picked[pick] = True X = GF256elt(pick) Y = P.f(X) keys[i] += chr(int(X)) keys[i] += chr(int(Y)) return keys
def f(self, x): "Compute f(x) where f is the current polynomial. We use Horner's scheme for faster result." if not isinstance(x, GF256elt): raise Exception() result = GF256elt(0) for i in range(1, len(self.__coefficients) + 1): result = result * x result += self.__coefficients[len(self.__coefficients) - i] return result
def interpolate(self,points): """Returns a PGF256 polynomial interpolating all GF256xGF256 tuples in points.""" # # Check that all points have different X # for i in xrange(0,len(points)): if points[i][0] in map(lambda x: x[0],points[i+1:]): raise Exception("Duplicate point exception") # # Special case for k=2 # if (2 == len(points)): x = PGF256((GF256elt(0),GF256elt(1))) P = PGF256([points[1][1]]) * (x - points[0][0]) * (GF256elt(1) / (points[1][0] - points[0][0])) P = P + PGF256([points[0][1]]) * (x - points[1][0]) * (GF256elt(1) / (points[0][0] - points[1][0])); return P # # Build the interpolating polynomial # # L(x) = sigma(j=0,j <= k,yj * Lj(x)) # Where k = len(points) - 1 # and Lj(x) = pi(i=0,i <= k and i != j, (x-xi)/(xj - xi)) # Lj(xi) = kronecker_delta(i,j) # result = PGF256([GF256elt(0)]) for j in xrange(0,len(points)): result = result + (self.__Lj(points,j) * points[j][1]) return result
def __mul__(self, other): if isinstance(other, GF256elt): c = self.coeffs() return PGF256(map(lambda x: x * other, c)) if not isinstance(other, PGF256): raise Exception() rescoeffs = [ GF256elt(0) for i in xrange(0, self.deg() + other.deg() + 1) ] for i in xrange(0, self.deg() + 1): for j in xrange(0, other.deg() + 1): rescoeffs[i + j] += self.coeff(i) * other.coeff(j) return PGF256(rescoeffs)