import os, hashlib, hmac
class BaseCipher(object):
PYTHON = False
CACHE = {}
def __init__(self, key, ota=False, setup_key=True):
if self.KEY_LENGTH > 0 and setup_key:
self.key = self.CACHE.get(b'key'+key)
if self.key is None:
keybuf = []
while len(b''.join(keybuf)) < self.KEY_LENGTH:
keybuf.append(hashlib.md5((keybuf[-1] if keybuf else b'') + key).digest())
self.key = self.CACHE[b'key'+key] = b''.join(keybuf)[:self.KEY_LENGTH]
else:
self.key = key
self.ota = ota
self.iv = None
def setup_iv(self, iv=None):
self.iv = os.urandom(self.IV_LENGTH) if iv is None else iv
self.setup()
return self
def decrypt(self, s):
return self.cipher.decrypt(s)
def encrypt(self, s):
return self.cipher.encrypt(s)
@classmethod
def name(cls):
return cls.__name__.replace('_Cipher', '').replace('_', '-').lower()
class AEADCipher(BaseCipher):
PACKET_LIMIT = 16*1024-1
def setup_iv(self, iv=None):
self.iv = os.urandom(self.IV_LENGTH) if iv is None else iv
randkey = hmac.new(self.iv, self.key, hashlib.sha1).digest()
blocks_needed = (self.KEY_LENGTH + len(randkey) - 1) // len(randkey)
okm = bytearray()
output_block = b''
for counter in range(blocks_needed):
output_block = hmac.new(randkey, output_block + b'ss-subkey' + bytes([counter+1]), hashlib.sha1).digest()
okm.extend(output_block)
self.key = bytes(okm[:self.KEY_LENGTH])
self._nonce = 0
self._buffer = bytearray()
self._declen = None
self.setup()
return self
@property
def nonce(self):
ret = self._nonce.to_bytes(self.NONCE_LENGTH, 'little')
self._nonce = (self._nonce+1) & ((1<