The following full fledged source illustrates why the eXtended Tiny Encryption Algorithm is a popular choice for embedded devices and legacy hardware. Overcoming the original TEA shortcomings, namely shared keys, XTEA is suitable for systems where memory and processing power is limited. It should be noted that XTEA has been superseded by Corrected Block TEA (or XXTEA for short), but has not yet been broken.
Being really geeky, TEA and its derivatives consist of 64-bit block Feistel network (the in situ input/output datum), a 128-bit key and a number of rounds (also known as cycles). The recommended value of rounds is 32, not 64, as each iteration of the loop does two Feistel-network rounds.
Feel free to cut 'n' paste the below source code, but remember using XTEA does not guarantee security. Full credit should go towards Cambridge Computer Laboratory and more importantly, the original creators, David Wheeler and Roger Needham, of TEA.
Example runs of the program:
echo "Attack at dawn" | ./xtea -key Secret -encrypt > encrypt.txt
cat encrypt.txt | ./xtea -key Secret -decrypt
Attack at dawn
For convenience, the source is provided in a MS Visual Studio project. Linux fans don't fret, it's also tested and complies on Linux. Clicky
/* File: xTEA.cpp; Mode: C++; Tab-width: 3; Author: Simon Flannery; */ /* The eXtended Tiny Encryption Algorithm (or "XTEA" for short) is a powerful, yet simple to implement, block cipher. It's small memory foot print makes it perfect for embedded devices and legacy hardware systems where memory is limited. */ #include <iostream> #include <cstdlib> #include <cstring> #define MAGIC_CONSTANT 0x9E3779B9 using namespace std; #ifdef _MSC_VER typedef unsigned __int32 uint32_t; #endif void encipher(uint32_t* v, uint32_t* key, uint32_t num_rounds = 32) { register uint32_t v0 = v[0], v1 = v[1]; register uint32_t sum = 0; for (uint32_t i = 0; i < num_rounds; ++i) { v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 0x03]); sum += MAGIC_CONSTANT; v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 0x03]); } v[0] = v0; v[1] = v1; return; } void decipher(uint32_t* v, uint32_t* key, uint32_t num_rounds = 32) { register uint32_t v0 = v[0], v1 = v[1]; register uint32_t sum = MAGIC_CONSTANT * num_rounds; for (uint32_t i = 0; i < num_rounds; ++i) { v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 0x03]); sum -= MAGIC_CONSTANT; v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 0x03]); } v[0] = v0; v[1] = v1; return; } void PrintHelp(ostream& os) { os << "Tiny Encryption Algorithm" << endl; os << "Version 0.2" << endl; os << "-help\tPrint this message" << endl; os << "-key value\tPass in key value" << endl; os << "-encrypt\tUse to encrypt" << endl; os << "-decrypt\tUse to decrypt" << endl; return; } int main(int argc, char* argv[]) { char* key = NULL; void (*crypt)(uint32_t*, uint32_t*, uint32_t) = NULL; /* Doh, we cannot use a default parameter, see section 8.3.6/3 of the C++ specification. */ for (int i = 0; i < argc; ++i) { if (strstr(argv[i], "-") == argv[i]) { ++argv[i]; if (strcmp(argv[i], "key") == 0) { ++i; key = argv[i]; } else if (strcmp(argv[i], "encrypt") == 0) { crypt = encipher; } else if (strcmp(argv[i], "decrypt") == 0) { crypt = decipher; } else if (strcmp(argv[i], "-help") == 0 || strcmp(argv[i], "help") == 0) { PrintHelp(cout); exit(0); } } } if (key == NULL || crypt == NULL) { PrintHelp(cout); exit(0); } /* Simple check for key length to limit the key to a maximum of 32 char's. */ uint32_t uKey[4]; size_t t = sizeof(uint32_t) * 4; if (strlen(key) > t) { key[t - 1] = 0; } memset(uKey, 0, t); memcpy(uKey, key, strlen(key)); /* Do the enciphering/deciphering here. */ char message[8] = {0}; cin.unsetf(ios::skipws); /* Do not skip whitespace. */ cin.read(message, 8); int i = cin.gcount(); /* Get the number of char's read. */ i = i - ((cin.eof() == false)? 0 : 1); while (i > 0) { crypt((uint32_t*) message, uKey, 32); cout.write(message, 8); memset(message, 0, 8); /* Clear and reset. */ cin.read(message, 8); i = cin.gcount(); i = i - ((cin.eof() == false)? 0 : 1); } return 0; }