diff --git a/src/core/lib/TEA.mjs b/src/core/lib/TEA.mjs
index 5883a8c1..d2027c2d 100644
--- a/src/core/lib/TEA.mjs
+++ b/src/core/lib/TEA.mjs
@@ -108,15 +108,16 @@ function teaDecryptBlock(block, key) {
*
* @param {number[]} block - 8 bytes (plaintext)
* @param {number[]} key - 16 bytes (128-bit key)
+ * @param {number} rounds - Number of rounds (default 32)
* @returns {number[]} - 8 bytes (ciphertext)
*/
-function xteaEncryptBlock(block, key) {
+function xteaEncryptBlock(block, key, rounds) {
const v = bytesToUint32(block);
const k = bytesToUint32(key);
let v0 = v[0], v1 = v[1];
let sum = 0;
- for (let i = 0; i < ROUNDS; i++) {
+ for (let i = 0; i < rounds; i++) {
v0 = (v0 + ((((v1 << 4) ^ (v1 >>> 5)) + v1) ^ (sum + k[sum & 3]))) >>> 0;
sum = (sum + DELTA) >>> 0;
v1 = (v1 + ((((v0 << 4) ^ (v0 >>> 5)) + v0) ^ (sum + k[(sum >>> 11) & 3]))) >>> 0;
@@ -130,15 +131,16 @@ function xteaEncryptBlock(block, key) {
*
* @param {number[]} block - 8 bytes (ciphertext)
* @param {number[]} key - 16 bytes (128-bit key)
+ * @param {number} rounds - Number of rounds (default 32)
* @returns {number[]} - 8 bytes (plaintext)
*/
-function xteaDecryptBlock(block, key) {
+function xteaDecryptBlock(block, key, rounds) {
const v = bytesToUint32(block);
const k = bytesToUint32(key);
let v0 = v[0], v1 = v[1];
- let sum = (DELTA * ROUNDS) >>> 0;
+ let sum = (DELTA * rounds) >>> 0;
- for (let i = 0; i < ROUNDS; i++) {
+ for (let i = 0; i < rounds; i++) {
v1 = (v1 - ((((v0 << 4) ^ (v0 >>> 5)) + v0) ^ (sum + k[(sum >>> 11) & 3]))) >>> 0;
sum = (sum - DELTA) >>> 0;
v0 = (v0 - ((((v1 << 4) ^ (v1 >>> 5)) + v1) ^ (sum + k[sum & 3]))) >>> 0;
@@ -464,10 +466,12 @@ export function decryptTEA(cipherText, key, iv, mode = "ECB", padding = "PKCS5")
* @param {number[]} iv - 8-byte IV
* @param {string} mode - Block cipher mode
* @param {string} padding - Padding type
+ * @param {number} rounds - Number of rounds (default 32)
* @returns {number[]} - Ciphertext bytes
*/
-export function encryptXTEA(message, key, iv, mode = "ECB", padding = "PKCS5") {
- return encryptWithMode(message, key, iv, mode, padding, xteaEncryptBlock);
+export function encryptXTEA(message, key, iv, mode = "ECB", padding = "PKCS5", rounds = 32) {
+ const encFn = (block, k) => xteaEncryptBlock(block, k, rounds);
+ return encryptWithMode(message, key, iv, mode, padding, encFn);
}
/**
@@ -477,10 +481,13 @@ export function encryptXTEA(message, key, iv, mode = "ECB", padding = "PKCS5") {
* @param {number[]} iv - 8-byte IV
* @param {string} mode - Block cipher mode
* @param {string} padding - Padding type
+ * @param {number} rounds - Number of rounds (default 32)
* @returns {number[]} - Plaintext bytes
*/
-export function decryptXTEA(cipherText, key, iv, mode = "ECB", padding = "PKCS5") {
- return decryptWithMode(cipherText, key, iv, mode, padding, xteaEncryptBlock, xteaDecryptBlock);
+export function decryptXTEA(cipherText, key, iv, mode = "ECB", padding = "PKCS5", rounds = 32) {
+ const encFn = (block, k) => xteaEncryptBlock(block, k, rounds);
+ const decFn = (block, k) => xteaDecryptBlock(block, k, rounds);
+ return decryptWithMode(cipherText, key, iv, mode, padding, encFn, decFn);
}
/** Block size in bytes (exported for operation validation) */
diff --git a/src/core/operations/XTEADecrypt.mjs b/src/core/operations/XTEADecrypt.mjs
index f2988451..e3b6560b 100644
--- a/src/core/operations/XTEADecrypt.mjs
+++ b/src/core/operations/XTEADecrypt.mjs
@@ -23,7 +23,7 @@ class XTEADecrypt extends Operation {
this.name = "XTEA Decrypt";
this.module = "Ciphers";
- this.description = "XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed by David Wheeler and Roger Needham in 1997 as a successor to TEA, correcting several weaknesses identified in the original algorithm. It operates on 64-bit blocks using a 128-bit key and performs 32 cycles (64 Feistel rounds) with an improved key schedule that uses sum-dependent key word selection to resist related-key attacks.
XTEA retains the simplicity and compact implementation of TEA whilst providing significantly improved security. It is frequently encountered in malware analysis and CTF challenges due to its straightforward implementation.
Key: Must be exactly 16 bytes (128 bits).
IV: The Initialisation Vector should be 8 bytes (64 bits). If not entered, it will default to null bytes.
Padding: In CBC and ECB mode, the PKCS#5 padding scheme is used.";
+ this.description = "XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed by David Wheeler and Roger Needham in 1997 as a successor to TEA, correcting several weaknesses identified in the original algorithm. It operates on 64-bit blocks using a 128-bit key with an improved key schedule that uses sum-dependent key word selection to resist related-key attacks.
XTEA retains the simplicity and compact implementation of TEA whilst providing significantly improved security. It is frequently encountered in malware analysis and CTF challenges due to its straightforward implementation.
Key: Must be exactly 16 bytes (128 bits).
IV: The Initialisation Vector should be 8 bytes (64 bits). If not entered, it will default to null bytes.
Rounds: The recommended number of rounds is 32 (default). The reference implementation by Wheeler & Needham accepts a configurable round count.
Padding: In CBC and ECB mode, the PKCS#5 padding scheme is used.";
this.infoURL = "https://wikipedia.org/wiki/XTEA";
this.inputType = "string";
this.outputType = "string";
@@ -59,6 +59,13 @@ class XTEADecrypt extends Operation {
"name": "Padding",
"type": "option",
"value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
+ },
+ {
+ "name": "Rounds",
+ "type": "number",
+ "value": 32,
+ "min": 1,
+ "max": 255
}
];
}
@@ -71,12 +78,12 @@ class XTEADecrypt extends Operation {
run(input, args) {
const key = Utils.convertToByteArray(args[0].string, args[0].option),
iv = Utils.convertToByteArray(args[1].string, args[1].option),
- [,, mode, inputType, outputType, padding] = args;
+ [,, mode, inputType, outputType, padding, rounds] = args;
if (key.length !== 16)
throw new OperationError(`Invalid key length: ${key.length} bytes
-XTEA uses a key length of 16 bytes (128 bits).
+XTEA requires a key length of 16 bytes (128 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
if (iv.length !== TEA_BLOCK_SIZE && iv.length !== 0 && mode !== "ECB")
@@ -85,11 +92,16 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
XTEA uses an IV length of ${TEA_BLOCK_SIZE} bytes (${TEA_BLOCK_SIZE * 8} bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
+ throw new OperationError(`Invalid number of rounds: ${rounds}
+
+Rounds must be an integer between 1 and 255. Standard XTEA uses 32 rounds.`);
+
// Default IV to null bytes if empty (like AES)
const actualIv = iv.length === 0 ? new Array(TEA_BLOCK_SIZE).fill(0) : iv;
input = Utils.convertToByteArray(input, inputType);
- const output = decryptXTEA(input, key, actualIv, mode, padding);
+ const output = decryptXTEA(input, key, actualIv, mode, padding, rounds);
return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
}
diff --git a/src/core/operations/XTEAEncrypt.mjs b/src/core/operations/XTEAEncrypt.mjs
index bdba4eec..7d4bc1c1 100644
--- a/src/core/operations/XTEAEncrypt.mjs
+++ b/src/core/operations/XTEAEncrypt.mjs
@@ -23,7 +23,7 @@ class XTEAEncrypt extends Operation {
this.name = "XTEA Encrypt";
this.module = "Ciphers";
- this.description = "XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed by David Wheeler and Roger Needham in 1997 as a successor to TEA, correcting several weaknesses identified in the original algorithm. It operates on 64-bit blocks using a 128-bit key and performs 32 cycles (64 Feistel rounds) with an improved key schedule that uses sum-dependent key word selection to resist related-key attacks.
XTEA retains the simplicity and compact implementation of TEA whilst providing significantly improved security. It is frequently encountered in malware analysis and CTF challenges due to its straightforward implementation.
Key: Must be exactly 16 bytes (128 bits).
IV: The Initialisation Vector should be 8 bytes (64 bits). If not entered, it will default to null bytes.
Padding: In CBC and ECB mode, the PKCS#5 padding scheme is used.";
+ this.description = "XTEA (eXtended Tiny Encryption Algorithm) is a block cipher designed by David Wheeler and Roger Needham in 1997 as a successor to TEA, correcting several weaknesses identified in the original algorithm. It operates on 64-bit blocks using a 128-bit key with an improved key schedule that uses sum-dependent key word selection to resist related-key attacks.
XTEA retains the simplicity and compact implementation of TEA whilst providing significantly improved security. It is frequently encountered in malware analysis and CTF challenges due to its straightforward implementation.
Key: Must be exactly 16 bytes (128 bits).
IV: The Initialisation Vector should be 8 bytes (64 bits). If not entered, it will default to null bytes.
Rounds: The recommended number of rounds is 32 (default). The reference implementation by Wheeler & Needham accepts a configurable round count.
Padding: In CBC and ECB mode, the PKCS#5 padding scheme is used.";
this.infoURL = "https://wikipedia.org/wiki/XTEA";
this.inputType = "string";
this.outputType = "string";
@@ -59,6 +59,13 @@ class XTEAEncrypt extends Operation {
"name": "Padding",
"type": "option",
"value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
+ },
+ {
+ "name": "Rounds",
+ "type": "number",
+ "value": 32,
+ "min": 1,
+ "max": 255
}
];
}
@@ -71,7 +78,7 @@ class XTEAEncrypt extends Operation {
run(input, args) {
const key = Utils.convertToByteArray(args[0].string, args[0].option),
iv = Utils.convertToByteArray(args[1].string, args[1].option),
- [,, mode, inputType, outputType, padding] = args;
+ [,, mode, inputType, outputType, padding, rounds] = args;
if (key.length !== 16)
throw new OperationError(`Invalid key length: ${key.length} bytes
@@ -85,11 +92,16 @@ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
XTEA uses an IV length of ${TEA_BLOCK_SIZE} bytes (${TEA_BLOCK_SIZE * 8} bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
+ throw new OperationError(`Invalid number of rounds: ${rounds}
+
+Rounds must be an integer between 1 and 255. Standard XTEA uses 32 rounds.`);
+
// Default IV to null bytes if empty (like AES)
const actualIv = iv.length === 0 ? new Array(TEA_BLOCK_SIZE).fill(0) : iv;
input = Utils.convertToByteArray(input, inputType);
- const output = encryptXTEA(input, key, actualIv, mode, padding);
+ const output = encryptXTEA(input, key, actualIv, mode, padding, rounds);
return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
}
diff --git a/tests/operations/tests/TEA.mjs b/tests/operations/tests/TEA.mjs
index c8b76dd8..aa1043fe 100644
--- a/tests/operations/tests/TEA.mjs
+++ b/tests/operations/tests/TEA.mjs
@@ -188,7 +188,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -203,7 +203,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -218,7 +218,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -233,7 +233,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -248,7 +248,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "00000000000000000000000000000000"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -263,7 +263,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "00000000000000000000000000000000"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -278,7 +278,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "00000000000000000000000000000000"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -293,7 +293,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "00000000000000000000000000000000"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -308,7 +308,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456712345678234567893456789a"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -323,7 +323,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456712345678234567893456789a"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -338,7 +338,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456712345678234567893456789a"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -355,7 +355,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456789abcdef0123456789abcdef"},
{"option": "Hex", "string": "fedcba9876543210"},
- "CBC", "Raw", "Hex", "PKCS5"
+ "CBC", "Raw", "Hex", "PKCS5", 32
]
},
{
@@ -363,7 +363,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456789abcdef0123456789abcdef"},
{"option": "Hex", "string": "fedcba9876543210"},
- "CBC", "Hex", "Raw", "PKCS5"
+ "CBC", "Hex", "Raw", "PKCS5", 32
]
}
],
@@ -380,7 +380,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "deadbeefdeadbeefdeadbeefdeadbeef"},
{"option": "Hex", "string": "0102030405060708"},
- "OFB", "Raw", "Hex", "NO"
+ "OFB", "Raw", "Hex", "NO", 32
]
},
{
@@ -388,7 +388,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "deadbeefdeadbeefdeadbeefdeadbeef"},
{"option": "Hex", "string": "0102030405060708"},
- "OFB", "Hex", "Raw", "NO"
+ "OFB", "Hex", "Raw", "NO", 32
]
}
],
@@ -405,7 +405,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "deadbeefdeadbeefdeadbeefdeadbeef"},
{"option": "Hex", "string": "0000000000000001"},
- "CTR", "Raw", "Hex", "NO"
+ "CTR", "Raw", "Hex", "NO", 32
]
},
{
@@ -413,7 +413,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "deadbeefdeadbeefdeadbeefdeadbeef"},
{"option": "Hex", "string": "0000000000000001"},
- "CTR", "Hex", "Raw", "NO"
+ "CTR", "Hex", "Raw", "NO", 32
]
}
],
@@ -430,7 +430,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456789abcdef0123456789abcdef"},
{"option": "Hex", "string": "aabbccddeeff0011"},
- "CFB", "Raw", "Hex", "NO"
+ "CFB", "Raw", "Hex", "NO", 32
]
},
{
@@ -438,7 +438,47 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456789abcdef0123456789abcdef"},
{"option": "Hex", "string": "aabbccddeeff0011"},
- "CFB", "Hex", "Raw", "NO"
+ "CFB", "Hex", "Raw", "NO", 32
+ ]
+ }
+ ],
+ },
+
+ // ==================== XTEA NON-DEFAULT ROUNDS TEST ====================
+ {
+ name: "XTEA Encrypt then Decrypt: round-trip ECB with 16 rounds",
+ input: "4142434445464748",
+ expectedOutput: "4142434445464748",
+ recipeConfig: [
+ {
+ "op": "XTEA Encrypt",
+ "args": [
+ {"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
+ {"option": "Hex", "string": ""},
+ "ECB", "Hex", "Hex", "NO", 16
+ ]
+ },
+ {
+ "op": "XTEA Decrypt",
+ "args": [
+ {"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
+ {"option": "Hex", "string": ""},
+ "ECB", "Hex", "Hex", "NO", 16
+ ]
+ }
+ ],
+ },
+ {
+ name: "XTEA Encrypt: ECB, 16 rounds differs from 32 rounds",
+ input: "4142434445464748",
+ expectedOutput: "497df3d072612cb5",
+ recipeConfig: [
+ {
+ "op": "XTEA Encrypt",
+ "args": [
+ {"option": "Hex", "string": "000102030405060708090a0b0c0d0e0f"},
+ {"option": "Hex", "string": ""},
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -470,7 +510,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "00000000000000000000000000000000"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Hex", "NO"
+ "ECB", "Hex", "Hex", "NO", 32
]
}
],
@@ -510,7 +550,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456789abcdef0123456789abcdef"},
{"option": "Hex", "string": ""},
- "ECB", "Raw", "Hex", "PKCS5"
+ "ECB", "Raw", "Hex", "PKCS5", 32
]
},
{
@@ -518,7 +558,7 @@ TestRegister.addTests([
"args": [
{"option": "Hex", "string": "0123456789abcdef0123456789abcdef"},
{"option": "Hex", "string": ""},
- "ECB", "Hex", "Raw", "PKCS5"
+ "ECB", "Hex", "Raw", "PKCS5", 32
]
}
],