From 967da6de40e2f096a48ebcc77203eff7fd13cb62 Mon Sep 17 00:00:00 2001 From: PentesterTN Date: Tue, 17 Mar 2026 05:37:06 -0400 Subject: [PATCH 1/2] Add XTEA block cipher implementation Implemented XTEA (eXtended Tiny Encryption Algorithm) with encrypt and decrypt functions. Includes input validation and full doctest coverage. --- ciphers/xtea.py | 122 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 ciphers/xtea.py diff --git a/ciphers/xtea.py b/ciphers/xtea.py new file mode 100644 index 000000000000..84c54357b8e1 --- /dev/null +++ b/ciphers/xtea.py @@ -0,0 +1,122 @@ +""" +XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed to +correct weaknesses in TEA. It was published by David Wheeler and Roger +Needham in 1997. XTEA operates on 64-bit blocks with a 128-bit key and +uses a Feistel network with a recommended 64 rounds. + +It's still found in embedded systems and game networking protocols due +to its simplicity and small code footprint. + +Reference: https://en.wikipedia.org/wiki/XTEA +""" + +import struct + +DELTA = 0x9E3779B9 +MASK = 0xFFFFFFFF + + +def xtea_encrypt( + block: bytes, key: bytes, num_rounds: int = 64 +) -> bytes: + """ + Encrypt a single 64-bit block using XTEA. + + :param block: 8 bytes of plaintext + :param key: 16 bytes (128-bit key) + :param num_rounds: number of Feistel rounds (default 64) + :return: 8 bytes of ciphertext + + >>> key = b'\\x00' * 16 + >>> plaintext = b'\\x00' * 8 + >>> ciphertext = xtea_encrypt(plaintext, key) + >>> ciphertext.hex() + 'fc924d124ad0ed50' + + >>> xtea_encrypt(b'hello!!!', b'sixteenbyteskey!') + b'u\\x8d\\x00\\x17c\\xb8\\xf0*' + + >>> xtea_encrypt(b'short', key) + Traceback (most recent call last): + ... + ValueError: block must be 8 bytes + + >>> xtea_encrypt(plaintext, b'short') + Traceback (most recent call last): + ... + ValueError: key must be 16 bytes + """ + if len(block) != 8: + raise ValueError("block must be 8 bytes") + if len(key) != 16: + raise ValueError("key must be 16 bytes") + + v0, v1 = struct.unpack("!II", block) + k = struct.unpack("!4I", key) + + total = 0 + for _ in range(num_rounds): + v0 = (v0 + ((((v1 << 4) ^ (v1 >> 5)) + v1) ^ (total + k[total & 3]))) & MASK + total = (total + DELTA) & MASK + v1 = ( + v1 + ((((v0 << 4) ^ (v0 >> 5)) + v0) ^ (total + k[(total >> 11) & 3])) + ) & MASK + + return struct.pack("!II", v0, v1) + + +def xtea_decrypt( + block: bytes, key: bytes, num_rounds: int = 64 +) -> bytes: + """ + Decrypt a single 64-bit block using XTEA. + + :param block: 8 bytes of ciphertext + :param key: 16 bytes (128-bit key) + :param num_rounds: number of Feistel rounds (default 64) + :return: 8 bytes of plaintext + + Roundtrip test -- encrypt then decrypt returns original plaintext: + >>> key = b'\\x00' * 16 + >>> plaintext = b'\\x00' * 8 + >>> xtea_decrypt(xtea_encrypt(plaintext, key), key) == plaintext + True + + >>> msg = b'hello!!!' + >>> k = b'sixteenbyteskey!' + >>> xtea_decrypt(xtea_encrypt(msg, k), k) == msg + True + + >>> xtea_decrypt(b'short', key) + Traceback (most recent call last): + ... + ValueError: block must be 8 bytes + + >>> xtea_decrypt(b'\\x00' * 8, b'short') + Traceback (most recent call last): + ... + ValueError: key must be 16 bytes + """ + if len(block) != 8: + raise ValueError("block must be 8 bytes") + if len(key) != 16: + raise ValueError("key must be 16 bytes") + + v0, v1 = struct.unpack("!II", block) + k = struct.unpack("!4I", key) + + total = (DELTA * num_rounds) & MASK + for _ in range(num_rounds): + v1 = ( + v1 - ((((v0 << 4) ^ (v0 >> 5)) + v0) ^ (total + k[(total >> 11) & 3])) + ) & MASK + total = (total - DELTA) & MASK + v0 = (v0 - ((((v1 << 4) ^ (v1 >> 5)) + v1) ^ (total + k[total & 3]))) & MASK + + return struct.pack("!II", v0, v1) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() From c9c5250deee3bb3a70138bf099de47e37e169434 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:45:58 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ciphers/xtea.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ciphers/xtea.py b/ciphers/xtea.py index 84c54357b8e1..4d2aedde6c31 100644 --- a/ciphers/xtea.py +++ b/ciphers/xtea.py @@ -16,9 +16,7 @@ MASK = 0xFFFFFFFF -def xtea_encrypt( - block: bytes, key: bytes, num_rounds: int = 64 -) -> bytes: +def xtea_encrypt(block: bytes, key: bytes, num_rounds: int = 64) -> bytes: """ Encrypt a single 64-bit block using XTEA. @@ -65,9 +63,7 @@ def xtea_encrypt( return struct.pack("!II", v0, v1) -def xtea_decrypt( - block: bytes, key: bytes, num_rounds: int = 64 -) -> bytes: +def xtea_decrypt(block: bytes, key: bytes, num_rounds: int = 64) -> bytes: """ Decrypt a single 64-bit block using XTEA.