Skip to content

Instantly share code, notes, and snippets.

@lnsp
Created August 2, 2015 01:06
Show Gist options
  • Select an option

  • Save lnsp/ea8a047cccdef99c9820 to your computer and use it in GitHub Desktop.

Select an option

Save lnsp/ea8a047cccdef99c9820 to your computer and use it in GitHub Desktop.
super small and simple encryption / decryption library using sponge functions
# a super simple encryption / decryption library using sponge functions
# all credit for RC4 / Spritz goes to Ron Rivest / RSA
# Spritz implementation based on http://people.csail.mit.edu/rivest/pubs/RS14.pdf
import math
class RC4:
def initializeState(self):
self.i = self.j = 0
def ksa(self, K):
l = len(K)
self.S = bytearray(256)
self.i = 0
while self.i < 256:
self.S[self.i] = self.i
self.i += 1
self.j = self.i = 0
while self.i < 256:
self.j = (self.j + self.S[self.i] + K[self.i % l]) % 256
self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
self.i += 1
def prg(self):
self.i = (self.i + 1) % 256
self.j = (self.j + self.S[self.i]) % 256
self.S[self.i], self.S[self.j] = self.S[self.j], self.S[self.i]
z = self.S[(self.S[self.i] + self.S[self.j]) % 256]
return z
def sqz(self, M):
l = len(M)
C = bytearray(l)
self.i = self.j = 0
for n in range(l):
C[n] = M[n] ^ self.prg()
return C
def encrypt(self, K, M):
self.initializeState()
self.ksa(K)
C = self.sqz(M)
return bytes(C)
def decrypt(self, K, C):
self.initializeState()
self.ksa(K)
M = self.sqz(C)
return bytes(M)
class Plop:
def initializeState(self):
self.i = self.j = 0
self.z = 1
def lcg(self, m, a, b, y):
return (a * y + b) % m
def ksa(self, K):
l = len(K)
self.S = bytearray(256)
i = 0
while i < 256:
self.S[i] = i
i += 1
j = i = 0
while i < 256:
j = self.lcg(256, i, (i + j) % 256, self.S[K[j % l]])
self.S[j], self.S[i] = self.S[i], self.S[j]
i += 1
def prg(self):
self.i = (self.i + 1) % 256
self.j = (self.j + self.S[self.i]) % 256
self.z = (self.S[self.z] + self.S[self.i] + self.S[self.j] + self.j) % 256
return self.z
def sqz(self, r):
l = len(r)
O = bytearray(l)
for n in range(l):
O[n] = r[n] ^ self.prg()
return O
def encrypt(self, K, M):
self.initializeState()
self.ksa(K)
C = self.sqz(M)
return bytes(C)
def decrypt(self, K, C):
self.initializeState()
self.ksa(K)
M = self.sqz(C)
return bytes(M)
class Spritz:
def __init__(self):
self.N = 256
self.N_MINUS_1 = self.N - 1
self.N_OVER_TWO_FLOOR = math.floor(self.N / 2)
self.TWO_N = self.N * 2
def initializeState(self):
self.i = self.j = self.k = self.z = self.a = 0
self.w = 1
self.S = bytearray(self.N)
for v in range(self.N):
self.S[v] = v
def absorb(self, I):
l = len(I)
for v in range(l):
self.absorbByte(I[v])
def absorbByte(self, b):
self.absorbNibble(self.low(b))
self.absorbNibble(self.high(b))
def absorbNibble(self, x):
if self.a == self.N_OVER_TWO_FLOOR:
self.shuffle()
self.swap(self.a, self.madd(self.N_OVER_TWO_FLOOR, x))
self.a = self.madd(self.a, 1)
def absorbStop(self):
if self.a == self.N_OVER_TWO_FLOOR:
self.shuffle()
self.a = self.madd(self.a, 1)
def shuffle(self):
self.whip(self.TWO_N)
self.crush()
self.whip(self.TWO_N)
self.crush()
self.whip(self.TWO_N)
self.a = 0
def whip(self, r):
for v in range(r):
self.update()
while True:
self.w = self.madd(self.w, 1)
if self.gcd(self.w, self.N) == 1:
break
def crush(self):
index = 0
for v in range(self.N_OVER_TWO_FLOOR):
index = self.N_MINUS_1 - v
if self.S[v] > self.S[index]:
self.swap(v, index)
def squeeze(self, r):
if self.a > 0:
self.shuffle()
P = bytearray(r)
for v in range(r):
P[v] = self.drip()
return P
def drip(self):
if self.a > 0:
self.shuffle()
self.update()
return self.output()
def update(self):
self.i = self.madd(self.i, self.w)
self.j = self.madd(self.k, self.S[self.madd(self.j, self.S[self.i])])
self.j = self.madd(self.i + self.k, self.S[self.j])
self.swap(self.i, self.j)
def output(self):
self.z = self.S[
self.madd(self.j, self.S[
self.madd(self.i, self.S[
self.madd(self.z, self.k)
])
]
)
]
return self.z
def hash(self, M, r):
self.initializeState();
self.absorb(M);
self.absorbStop();
self.absorb([r & 0xff])
return self.squeeze(r)
def encrypt(self, K, M):
l = len(M)
C = bytearray(l)
self.keySetup(K)
O = self.squeeze(l)
for i in range(l):
C[i] = M[i] ^ O[i]
return bytes(C)
def decrypt(self, K, C):
l = len(C)
M = bytearray(l)
self.keySetup(K)
O = self.squeeze(l)
for i in range(l):
M[i] = C[i] ^ O[i]
return bytes(M)
def keySetup(self, K):
self.initializeState();
self.absorb(K)
def madd(self, a, b):
return (a + b) % self.N
def msub(self, a, b):
return self.madd(N, a - b)
def low(self, b):
return b & 0xf
def high(self, b):
return b >> 4 & 0xf
def swap(self, p1, p2):
self.S[p1], self.S[p2] = self.S[p2], self.S[p1]
def gcd(self, a, b):
t = 0
while b != 0:
t = b
b = a % b
a = t
return a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment