lazarus/lazarus.py

111 lines
3.5 KiB
Python
Raw Normal View History

2020-06-25 11:44:13 +02:00
import hashlib
import math
2020-05-29 21:20:50 +02:00
2020-06-25 11:44:13 +02:00
from fastecdsa.curve import P256
from fastecdsa.point import Point
from fastecdsa import util
Q = 31415926535987932384626433832795*P256.G
class EccRNG():
def __init__(self, Q, seed, curve = P256):
self.curve = curve
self.state = int.from_bytes(seed, "big", seed, signed=False )
self.Q = Q
self.P = curve.G
self.tmp = None
assert Q.curve == curve
def gen(self):
new_point = self.state * self.P
r = new_point.x
rQ = r * self.P
random_int_to_return = int(str(bin((rQ).x))[16:], 2)
self.state = (r*self.Q).x
self.lsb = str(bin((rQ).x))
self.rQ = rQ
return random_int_to_return.to_bytes(math.ceil(random_int_to_return.bit_length()/8), byteorder='big')
class LazarusKeyScheduler():
def __init__(self, password: bytes, nonce: bytes):
self.ecc = EccRNG()
self.hashState = hashlib.sha3_256(password + nonce + password).digest()
self.eccState = self.ecc.gen()
for i in range(64):
self._stateStep()
def genToken(self):
self._stateStep()
return self.state + self.eccState
def getKey(self, length: int):
return hashlib.shake_256(self.genToken()).digest(length)
def _stateStep(self):
self.eccState = self.ecc.gen()
self.hashState = hashlib.sha3_256(self.hashState + self.eccState).digest()
class OmegaChain():
def __init__(self, key: bytes, primer: bytes):
self.blockSize = 16
self.prevBlock = primer
2020-05-29 21:20:50 +02:00
self.key = key
2020-06-25 11:44:13 +02:00
def encrypt(self, data: bytes):
blocks = self._dataToBlocks(data)
enc = bytes()
for block in blocks:
enc += self.encBlock(block)
def _encBlock(self, plainBlock: bytes):
chainedBlock = self._xor(self.prevBlock, plainBlock)
encBlock = self._xor(chainedBlock, self.key)
self.prevBlock = encBlock
return encBlock
def _xor(self, a: bytes, b: bytes):
if len(a)!=self.blockSize or len(b)!=self.blockSize:
raise Exception("Cannot xor") #TODO
return bytes([a[i]^b[i] for i in range(len(a))])
def _dataToBlocks(self, data: bytes):
padded = self._padData(data, blockSize = self.blockSize)
return [data[b*self.blockSize:self.blockSize] for b in range(int(len(padded)/self.blockSize))]
def _padData(self, data: bytes, blockSize: int = None):
if not blockSize:
blockSize = self.blockSize
bytesMissing = (blockSize-len(data)%blockSize)
if bytesMissing == blockSize:
return data
else:
return data + bytes(bytesMissing)
class Lazarus():
def encrypt(password: bytes, plaintext: bytes, nonce: bytes = None):
if not nonce:
#TODO: Random iv
nonce = b'bla'
scheduler = LazarusKeyScheduler(password, nonce)
omegaKey = scheduler.genToken()
primer = scheduler.getKey(16)
aesKey = scheduler.getKey(16)
aesIV = scheduler.getKey(16)
hmacInnerKey = scheduler.getKey(16)
hmacOuterKey = scheduler.getKey(16)
alpha = Lazarus._encryptAES(plaintext, aesKey, aesIV)
hmac = Lazarus._genHMAC(plaintext, hmacInnerKey, hmacOuterKey)
psi = alpha + hmac
omega = OmegaChain(omegaKey, primer)
return omega.encrypt(psi)
def omegaChain(prev: bytes, scheduler: LazarusKeyScheduler):
pass
def eccPerm(self, key: bytes):
pass
def primePerm(self, key: bytes):
pass