#!/usr/bin/python
# -*- coding: utf-8 -*-
# Hive Appier Framework
# Copyright (c) 2008-2024 Hive Solutions Lda.
#
# This file is part of Hive Appier Framework.
#
# Hive Appier Framework is free software: you can redistribute it and/or modify
# it under the terms of the Apache License as published by the Apache
# Foundation, either version 2.0 of the License, or (at your option) any
# later version.
#
# Hive Appier Framework is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Apache License for more details.
#
# You should have received a copy of the Apache License along with
# Hive Appier Framework. If not, see .
__author__ = "João Magalhães "
""" The author(s) of the module """
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
""" The copyright for the module """
__license__ = "Apache License, Version 2.0"
""" The license for the module """
import array
from . import legacy
from . import exceptions
class Cipher(object):
def __init__(self, key):
self.key = key
@classmethod
def new(cls, cipher, key):
cipher = cls._cipher(cipher)
return cipher(key)
@classmethod
def _cipher(cls, name):
for subclass in cls.__subclasses__():
if not subclass.__name__.lower() == name:
continue
return subclass
return None
def encrypt(self, data):
raise exceptions.NotImplementedError()
def decrypt(self, data):
raise exceptions.NotImplementedError()
class RC4(Cipher):
"""
Class that implements the basis for the
encryption using the RC4 stream cipher.
The implementation of the algorithm follows
the typical implementation details.
:see: http://en.wikipedia.org/wiki/RC4
"""
def __init__(self, key):
Cipher.__init__(self, key)
self._start()
def encrypt(self, data):
out = array.array("B", [0] * len(data))
self._encrypt(data, out)
return legacy.tobytes(out)
def decrypt(self, data):
return self.encrypt(data)
def _encrypt(self, data, out):
index = 0
box = self.box
i = self.i
j = self.j
for char in data:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], self.box[i]
k = box[(box[i] + box[j]) % 256]
ciph = legacy.ord(char) ^ k
out[index] = ciph
index += 1
self.i = i
self.j = j
def _start(self):
self.box = legacy.range(256)
self.i = 0
self.j = 0
x = 0
for i in range(256):
x = (x + self.box[i] + legacy.ord(self.key[i % len(self.key)])) % 256
self.box[i], self.box[x] = self.box[x], self.box[i]
class Spritz(Cipher):
"""
Class that implements the basis for the
encryption using the Spritz stream cipher
a variation of the original RC4 cipher.
The implementation of the algorithm follows
the typical implementation details.
:see: http://en.wikipedia.org/wiki/RC4#Spritz
"""
def __init__(self, key):
Cipher.__init__(self, key)
self._start()
self.absorb(self.key)
def encrypt(self, data):
data = bytearray(data)
sequezing = self.squeeze(len(data))
out = bytearray(self._add(b1, b2) for b1, b2 in zip(data, sequezing))
return bytes(out)
def decrypt(self, data):
data = bytearray(data)
sequezing = self.squeeze(len(data))
out = bytearray(self._add(b1, -b2) for b1, b2 in zip(data, sequezing))
return bytes(out)
def absorb(self, data):
data = bytearray(data)
for byte in data:
self._absorb_byte(byte)
def shuffle(self):
self.whip(512)
self.crush()
self.whip(512)
self.crush()
self.whip(512)
self.a = 0
def whip(self, r):
for _ in range(r):
self._update()
self.w = self._add(self.w, 2)
def crush(self):
for v in range(128):
if self.S[v] <= self.S[255 - v]:
continue
self._swap(v, 255 - v)
def squeeze(self, r):
if self.a > 0:
self.shuffle()
return bytearray([self.drip() for _ in range(r)])
def drip(self):
if self.a > 0:
self.shuffle()
self._update()
return self._output()
def _update(self):
self.i = self._add(self.i, self.w)
self.j = self._add(self.k, self.S[self._add(self.j, self.S[self.i])])
self.k = self._add(self.i, self.k, self.S[self.j])
self._swap(self.i, self.j)
def _output(self):
self.z = self.S[
self._add(
self.j, self.S[self._add(self.i, self.S[self._add(self.z, self.k)])]
)
]
return self.z
def _add(self, *args):
return sum(args) % 256
def _swap(self, i1, i2):
self.S[i1], self.S[i2] = self.S[i2], self.S[i1]
def _start(self):
self.i = 0
self.j = 0
self.k = 0
self.z = 0
self.a = 0
self.w = 1
self.S = bytearray(range(256))
def _absorb_byte(self, byte):
self._absorb_nibble(byte & 0xF)
self._absorb_nibble(byte >> 4)
def _absorb_nibble(self, nibble):
if self.a == 128:
self.shuffle()
self._swap(self.a, 128 + nibble)
self.a = self._add(self.a, 1)