Exemplo n.º 1
0
 def __init__(self, cipher: EncryptionAlg, nonce: bytes):
     """
     Parameters:
         cipher (EncryptionAlg): Instantiated encryption algorithm.
         nonce          (bytes): Bytes-like nonce.
     """
     Primitive.__init__(self)
     self.cipher = cipher
     self.nonce  = nonce
     self.ctr    = CTR(self.cipher, b'')
     self.cmac   = CMAC(self.cipher)
Exemplo n.º 2
0
    def __init__(self, cipher: EncryptionAlg, mac_len: int):
        """
        Parameters:
            cipher (EncryptionAlg): Instantiated encryption algorithm.
            mac_len          (int): Length of MAC to generate.
        """
        Primitive.__init__(self)
        self.cipher  = cipher
        self.cmac    = CBCMAC(self.cipher)
        self.mac_len = mac_len

        self.ctr = CTR(self.cipher, b'\x00' * 16)
Exemplo n.º 3
0
    def __init__(self, cipher: EncryptionAlg):
        """
        Parameters:
            cipher (EncryptionAlg): Instantiated encryption algorithm.
        """
        Primitive.__init__(self)
        self.cipher = cipher
        self.H = self.cipher.encrypt(b'\x00' * 16).int()
        self.ctr = CTR(self.cipher, b'\x00' * 8)

        # Precompute the product table
        self.product_table = [0] * 16
        self.product_table[reverse_bits(1)] = self.H

        for i in range(2, 16, 2):
            self.product_table[reverse_bits(i)] = self.gcm_shift(
                self.product_table[reverse_bits(i // 2)])
            self.product_table[reverse_bits(
                i + 1)] = self.product_table[reverse_bits(i)] ^ self.H
Exemplo n.º 4
0
    def test_all_vecs(self):
        for unparsed_vec in TEST_VECS:
            _alg, key, nonce, plaintext, ciphertext, _what = unparsed_vec.split(":")
            key_bytes, nonce, plaintext, expected_ciphertext = [codecs.decode(item.encode('utf-8'), 'hex_codec') for item in [key, nonce, plaintext, ciphertext]]

            key = Bytes(key_bytes).zfill(ceil(len(key_bytes) / 16) * 16)

            ctr = CTR(Rijndael(key), nonce[:15])
            ctr.counter = 1
            ciphertext = ctr.encrypt(plaintext)

            ctr = CTR(Rijndael(key), nonce[:15])
            ctr.counter = 1
            self.assertEqual(ciphertext, expected_ciphertext)
            self.assertEqual(plaintext, ctr.decrypt(ciphertext))
Exemplo n.º 5
0
def init_aes256_ctr(key_iv):
    key, iv = key_iv[:32], key_iv[32:]
    ctr = CTR(Rijndael(key), nonce=b'')
    ctr.counter = iv.int()

    return ctr
Exemplo n.º 6
0
class GCM(StreamingBlockCipherMode):
    """Galois counter mode (GCM) block cipher mode"""

    EPHEMERAL = EphemeralSpec(ephemeral_type=EphemeralType.NONCE,
                              size=SizeSpec(size_type=SizeType.SINGLE,
                                            sizes=96))
    AUTH_TAG_SIZE = SizeSpec(size_type=SizeType.SINGLE, sizes=128)
    USAGE_FREQUENCY = FrequencyType.PROLIFIC

    def __init__(self, cipher: EncryptionAlg):
        """
        Parameters:
            cipher (EncryptionAlg): Instantiated encryption algorithm.
        """
        Primitive.__init__(self)
        self.cipher = cipher
        self.H = self.cipher.encrypt(b'\x00' * 16).int()
        self.ctr = CTR(self.cipher, b'\x00' * 8)

        # Precompute the product table
        self.product_table = [0] * 16
        self.product_table[reverse_bits(1)] = self.H

        for i in range(2, 16, 2):
            self.product_table[reverse_bits(i)] = self.gcm_shift(
                self.product_table[reverse_bits(i // 2)])
            self.product_table[reverse_bits(
                i + 1)] = self.product_table[reverse_bits(i)] ^ self.H

    def __repr__(self):
        return f"<GCM: cipher={self.cipher}, H={self.H}, ctr={self.ctr}>"

    def __str__(self):
        return self.__repr__()

    def clock_ctr(self, nonce: bytes) -> Bytes:
        nonce = Bytes.wrap(nonce)
        if len(nonce) == 12:
            self.ctr.nonce = nonce
            self.ctr.counter = 1
        else:
            payload = nonce.pad_congruent_right(16) + (b'\x00' * 8) + Bytes(
                len(nonce) * 8).zfill(8)
            J_0 = Bytes(self.update(0, payload)).zfill(16)
            self.ctr.nonce = J_0[:15]
            self.ctr.counter = J_0[-1]

        return self.ctr.encrypt(Bytes(b'').zfill(16))

    def encrypt(self,
                nonce: bytes,
                plaintext: bytes,
                data: bytes = b'') -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            nonce     (bytes): Bytes-like nonce.
            plaintext (bytes): Bytes-like object to be encrypted.
            data      (bytes): Bytes-like additional data to be authenticated but not encrypted.
        
        Returns:
            Bytes: Resulting ciphertext.
        """
        tag_mask = self.clock_ctr(nonce)
        data = Bytes.wrap(data)

        ciphertext = self.ctr.encrypt(plaintext)
        tag = self.auth(ciphertext, data, tag_mask)

        return ciphertext + tag

    def decrypt(self,
                nonce: bytes,
                authed_ciphertext: bytes,
                data: bytes = b'') -> Bytes:
        """
        Decrypts `ciphertext`.

        Parameters:
            nonce             (bytes): Bytes-like nonce.
            authed_ciphertext (bytes): Bytes-like object to be decrypted.
            data              (bytes): Bytes-like additional data to be authenticated.
        
        Returns:
            Bytes: Resulting plaintext.
        """
        from samson.utilities.runtime import RUNTIME

        authed_ciphertext = Bytes.wrap(authed_ciphertext)
        ciphertext, orig_tag = authed_ciphertext[:-16], authed_ciphertext[-16:]

        tag_mask = self.clock_ctr(nonce)
        data = Bytes.wrap(data)
        tag = self.auth(ciphertext, data, tag_mask)

        if not RUNTIME.compare_bytes(tag, orig_tag):
            raise Exception('Tag mismatch: authentication failed!')

        return self.ctr.decrypt(ciphertext)

    def gcm_shift(self, x: int) -> int:
        high_bit_set = x & 1
        x >>= 1

        if high_bit_set:
            x ^= 0xe1 << (128 - 8)

        return x

    def mul(self, y):
        ret = 0

        for _ in range(0, 128, 4):
            high_bit = ret & 0xF
            ret >>= 4
            ret ^= GCM_REDUCTION_TABLE[high_bit] << (128 - 16)
            ret ^= self.product_table[y & 0xF]
            y >>= 4

        return ret

    def auth(self, ciphertext: Bytes, ad: Bytes, tag_mask: Bytes) -> Bytes:
        y = 0
        y = self.update(y, ad)
        y = self.update(y, ciphertext)
        y ^= (len(ad) << (3 + 64)) | (len(ciphertext) << 3)
        y = self.mul(y)
        y ^= tag_mask.int()
        return Bytes(int.to_bytes(y, 16, 'big'))

    def update(self, y: int, data: Bytes) -> int:
        for chunk in data.chunk(16):
            y ^= chunk.int()
            y = self.mul(y)

        extra = len(data) % 16

        if extra != 0:
            block = bytearray(16)
            block[:extra] = data[-extra:]
            y ^= int.from_bytes(block, 'big')
            y = self.mul(y)
        return y
Exemplo n.º 7
0
class CCM(StreamingBlockCipherMode):
    """
    Counter with CBC-MAC block cipher mode.

    CCM is only defined for ciphers with 128 bit block size.
    """

    USAGE_FREQUENCY = FrequencyType.UNUSUAL
    AUTH_TAG_SIZE   = SizeSpec(size_type=SizeType.RANGE, sizes=range(32, 129, 16), typical=[128])
    EPHEMERAL       = EphemeralSpec(ephemeral_type=EphemeralType.NONCE, size=SizeSpec(size_type=SizeType.RANGE, sizes=range(8, 97, 8), typical=[96]))

    def __init__(self, cipher: EncryptionAlg, mac_len: int):
        """
        Parameters:
            cipher (EncryptionAlg): Instantiated encryption algorithm.
            mac_len          (int): Length of MAC to generate.
        """
        Primitive.__init__(self)
        self.cipher  = cipher
        self.cmac    = CBCMAC(self.cipher)
        self.mac_len = mac_len

        self.ctr = CTR(self.cipher, b'\x00' * 16)


    def __repr__(self):
        return f"<CCM: cipher={self.cipher}, ctr={self.ctr}>"

    def __str__(self):
        return self.__repr__()


    def _calculate_formatting_params(self, nonce: bytes, plaintext: bytes, data: bytes):
        data_len = len(data)
        q        = 15 - len(nonce)
        flags    = (64 * (data_len > 0)) + 8 * (((self.mac_len) - 2) // 2) + (q - 1)
        b_0      = Bytes(flags) + nonce + int.to_bytes(len(plaintext), q, 'big')

        return data_len, q, flags, b_0


    # https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38c.pdf
    def _generate_mac(self, nonce: bytes, plaintext: bytes, data: bytes) -> bytes:
        data_len, _q, _flags, b_0 = self._calculate_formatting_params(nonce, plaintext, data)

        data_len_encoded = b''
        if data_len > 0:
            if data_len < ((2 ** 16) - (2 ** 8)):
                size = 2

            elif data_len < (2 ** 32):
                data_len_encoded = b'\xFF\xFE'
                size = 4

            else:
                data_len_encoded = b'\xFF\xFF'
                size = 8

            data_len_encoded += int.to_bytes(data_len, size, 'big')

        padded_data = Bytes.wrap(data_len_encoded + data).pad_congruent_right(16)
        padded_plaintext = Bytes.wrap(plaintext).pad_congruent_right(16)

        T = self.cmac.generate(b_0 + padded_data + padded_plaintext, pad=False)
        return T


    def _generate_keystream(self, nonce: bytes, q: int, length: int) -> Bytes:
        formatted_nonce  = Bytes(q - 1) + nonce
        self.ctr.nonce   = formatted_nonce
        self.ctr.counter = 0
        keystream = self.ctr.encrypt(Bytes(b'').zfill(length))

        return keystream



    def encrypt(self, nonce: bytes, plaintext: bytes, data: bytes) -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            nonce     (bytes): Bytes-like nonce.
            plaintext (bytes): Bytes-like object to be encrypted.
            data      (bytes): Bytes-like additional data to be authenticated but not encrypted.

        Returns:
            Bytes: Resulting ciphertext.
        """
        T = self._generate_mac(nonce, plaintext, data)
        _data_len, q, _flags, _b_0 = self._calculate_formatting_params(nonce, plaintext, data)

        keystream = self._generate_keystream(nonce, q, len(plaintext) + 16)
        return (keystream[len(T):] ^ (plaintext)) + (T ^ keystream[:len(T)])[:self.mac_len]



    def decrypt(self, nonce: bytes, ciphertext: bytes, data: bytes) -> Bytes:
        """
        Decrypts `ciphertext`.

        Parameters:
            nonce     (bytes): Bytes-like nonce.
            plaintext (bytes): Bytes-like object to be decrypted.
            data      (bytes): Bytes-like additional data to be authenticated.

        Returns:
            Bytes: Resulting plaintext.
        """
        _data_len, q, _flags, _b_0 = self._calculate_formatting_params(nonce, ciphertext, data)

        keystream = self._generate_keystream(nonce, q, len(ciphertext) + (16 - self.mac_len))

        total_plaintext = (keystream[16:] + keystream[:self.mac_len]) ^ ciphertext
        plaintext, mac  = total_plaintext[:-self.mac_len], total_plaintext[-self.mac_len:]

        T = self._generate_mac(nonce, plaintext, data)[:self.mac_len]

        if not hmac.compare_digest(T, mac):
            raise Exception("Authentication of data failed: MACs not equal")

        return plaintext
Exemplo n.º 8
0
def login_ctr(ciphertext):
    return b';admin=true;' in CTR(aes, nonce).encrypt(ciphertext)
Exemplo n.º 9
0
def encrypt_data_ctr(data):
    return CTR(aes, nonce).encrypt(format_data(data))
Exemplo n.º 10
0
def aes_ctr_oracle(message):
    aes = Rijndael(rand_bytes(key_size))
    ciphertext = CTR(aes, rand_bytes(block_size // 2)).encrypt(
        zlib.compress(message))
    return len(ciphertext)
Exemplo n.º 11
0
def encrypt_ctr(secret):
    return CTR(Rijndael(key), int.to_bytes(0, block_size // 2,
                                           'big')).encrypt(secret)
Exemplo n.º 12
0
class EAX(StreamingBlockCipherMode):
    """
    EAX block cipher mode
    http://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf
    """

    EPHEMERAL     = EphemeralSpec(ephemeral_type=EphemeralType.NONCE, size=SizeSpec(size_type=SizeType.DEPENDENT, selector=lambda block_mode: block_mode.cipher.BLOCK_SIZE))
    AUTH_TAG_SIZE = SizeSpec(size_type=SizeType.DEPENDENT, selector=lambda block_mode: block_mode.cipher.BLOCK_SIZE)

    def __init__(self, cipher: EncryptionAlg, nonce: bytes):
        """
        Parameters:
            cipher (EncryptionAlg): Instantiated encryption algorithm.
            nonce          (bytes): Bytes-like nonce.
        """
        Primitive.__init__(self)
        self.cipher = cipher
        self.nonce  = nonce
        self.ctr    = CTR(self.cipher, b'')
        self.cmac   = CMAC(self.cipher)


    def __repr__(self):
        return f"<EAX: cipher={self.cipher}, nonce={self.nonce}>"

    def __str__(self):
        return self.__repr__()



    def generate_tag(self, ciphertext: bytes, auth_data: bytes) -> Bytes:
        """
        Internal function. Generates a valid tag for the `ciphertext` and `auth_data`.
        """
        cipher_mac = self.cmac.generate(Bytes(2).zfill(self.cipher.block_size) + ciphertext)
        tag = cipher_mac ^ self.cmac.generate(Bytes(0).zfill(self.cipher.block_size) + self.nonce) ^ self.cmac.generate(Bytes(1).zfill(self.cipher.block_size) + Bytes.wrap(auth_data))

        return tag


    def encrypt(self, plaintext: bytes, auth_data: bytes) -> Bytes:
        """
        Encrypts `plaintext`.

        Parameters:
            plaintext (bytes): Bytes-like object to be encrypted.
            auth_data (bytes): Bytes-like additional data to be authenticated but not encrypted.
        
        Returns:
            Bytes: Resulting ciphertext.
        """
        self.ctr.counter = self.cmac.generate(Bytes(0).zfill(self.cipher.block_size) + self.nonce).int()

        ciphertext = self.ctr.encrypt(plaintext)
        tag = self.generate_tag(ciphertext, auth_data)

        return ciphertext + tag[:self.cipher.block_size]



    def decrypt(self, ciphertext: bytes, auth_data: bytes, verify: bool=True) -> Bytes:
        """
        Decrypts `ciphertext`.

        Parameters:
            ciphertext (bytes): Bytes-like object to be decrypted.
            auth_data  (bytes): Bytes-like additional data to be authenticated but not encrypted.
            verify      (bool): Whether or not to verify the authentication tag.
        
        Returns:
            Bytes: Resulting plaintext.
        """
        ciphertext, given_tag = ciphertext[:-16], ciphertext[-16:]
        tag = self.generate_tag(ciphertext, auth_data)

        if verify:
            assert tag == given_tag


        self.ctr.counter = self.cmac.generate(Bytes(0).zfill(self.cipher.block_size) + self.nonce).int()
        plaintext = self.ctr.decrypt(ciphertext)


        return plaintext