from transforms.base import *

class RC4(Transform):
    """
    RC4 stream cipher
    """
    category = "crypto (stream)"
    name = "rc4"
    icon = "wxART_DECRYPT"

    def run(self, data:bytes, key:bytes=b"\x00", init_update_rounds:int=0):
        if not key:
            return data
        x = 0
        sbox = list(range(256))
        for i in range(256):
            x = (x + sbox[i] + key[i % len(key)]) & 0xFF
            sbox[i], sbox[x] = sbox[x], sbox[i]
        x = 0
        y = 0
        out = []

        for i in range(init_update_rounds):
            x = (x + 1) & 0xFF
            y = (y + sbox[x]) & 0xFF
            sbox[x], sbox[y] = sbox[y], sbox[x]

        for char in data:
            x = (x + 1) & 0xFF
            y = (y + sbox[x]) & 0xFF
            sbox[x], sbox[y] = sbox[y], sbox[x]
            out.append(char ^ sbox[(sbox[x] + sbox[y]) & 0xFF])
        return bytes(out)


class ChaCha20(Transform):
    """
    ChaCha20 cipher
    key is 32 bytes
    nonce is 8, 12 or 24 bytes
    """
    category = "crypto (stream)"
    name = "chacha20"
    icon = "wxART_DECRYPT"

    def run(self, data:bytes, key:bytes=b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nonce:bytes=b"\x00\x00\x00\x00\x00\x00\x00\x00", counter:int=0):
        from Cryptodome.Cipher import ChaCha20
        cryptor = ChaCha20.new(key=key, nonce=nonce)
        if counter:
            cryptor.seek(counter*64)
        return cryptor.encrypt(data)
  
class Salsa20(Transform):
    """
    Salsa20 cipher
    key is 16 or 32 bytes
    nonce is 8 bytes
    """
    category = "crypto (stream)"
    name = "salsa20"
    icon = "wxART_DECRYPT"

    def run(self, data:bytes, key:bytes=b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", nonce:bytes=b"\x00\x00\x00\x00\x00\x00\x00\x00", counter:int=0):
        from Cryptodome.Cipher import Salsa20
        cryptor = Salsa20.new(key=key, nonce=nonce)
        if counter:
            cryptor.seek(counter*64)
        return cryptor.encrypt(data)
  
