TEA算法是由剑桥大学计算机实验室的David Wheeler和Roger Needham于1994年发明,TEA是Tiny Encryption Algorithm的缩写,以加密解密速度快,实现简单著称。TEA算法每一次可以操作64bit(8byte),采用128bit(16byte)作为key,算法采用迭代的形式,推荐的迭代轮数是64轮,最少32轮。为解决TEA算法密钥表攻击的问题,TEA算法先后经历了几次改进,从XTEA到BLOCK TEA,直至最新的XXTEA。XTEA也称做TEAN,它使用与TEA相同的简单运算,但四个子密钥采取不正规的方式进行混合以阻止密钥表攻击。Block TEA算法可以对32位的任意整数倍长度的变量块进行加解密的操作,该算法将XTEA轮循函数依次应用于块中的每个字,并且将它附加于被应用字的邻字。XXTEA使用跟Block TEA相似的结构,但在处理块中每个字时利用了相邻字,且用拥有两个输入量的MX函数代替了XTEA轮循函数。本文所描述的安全机制采用的加密算法就是TEA算法中安全性能最佳的改进版本-XXTEA算法。
XXTEA算法的结构非常简单,只需要执行加法、异或和寄存的硬件即可,且软件实现的代码非常短小,具有可移植性,非常适合嵌入式系统应用。由于XXTEA算法的以上优点,可以很好地应用于嵌入式RFID系统当中。
C语言实现:
#define MX (z>>5^y<<2) + (y>>3^z<<4)^(sum^y) + (k[p&3^e]^z);
long btea(long* v, long n, long* k) {
unsigned long z=v[n-1], y=v[0], sum=0, e, DELTA=0x9e3779b9;
long p, q ;
if (n > 1) {
q = 6 + 52/n;
while (q-- > 0) {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) y = v[p+1], z = v[p] += MX;
y = v[0];
z = v[n-1] += MX;
}
return 0 ;
} else if (n < -1) {
n = -n;
q = 6 + 52/n;
sum = q*DELTA ;
while (sum != 0) {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) z = v[p-1], y = v[p] -= MX;
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}
return 0;
}
return 1;
}
Lua语言实现---------------------------------------------------------------------
-- Author: Jørn Skaarud Karlsen
---------------------------------------------------------------------
require("bit")
require("hex")
---------------------------------------------------------------------
-- Constants
---------------------------------------------------------------------
delta = 0x9E3779B9
---------------------------------------------------------------------
-- Conversion
---------------------------------------------------------------------
function convertStringToBytes(str)
local bytes = {}
local strLength = string.len(str)
for i=1,strLength do
table.insert(bytes, string.byte(str, i))
end
return bytes
end
function convertBytesToString(bytes)
local bytesLength = table.getn(bytes)
local str = ""
for i=1,bytesLength do
str = str .. string.char(bytes[i])
end
return str
end
function convertHexStringToBytes(str)
local bytes = {}
local strLength = string.len(str)
for k=2,strLength,2 do
local hexString = "0x" .. string.sub(str, (k - 1), k)
table.insert(bytes, hex.to_dec(hexString))
end
return bytes
end
function convertBytesToHexString(bytes)
local str = ""
local bytesLength = table.getn(bytes)
for i=1,bytesLength do
local hexString = string.sub(hex.to_hex(bytes[i]), 3)
if string.len(hexString) == 1 then
hexString = "0" .. hexString
end
str = str .. hexString
end
return str
end
function convertBytesToUIntArray(bytes, includeLength)
local bytesLength = table.getn(bytes)
local result = {}
if includeLength then
local n = bit.brshift(bytesLength, 2) + 1
if bit.band(bytesLength, 3) ~= 0 then
n = n + 1
end
result[n] = bytesLength;
end
for i=0,(bytesLength - 1) do
local resultIndex = bit.brshift(i, 2) + 1
if result[resultIndex] == nil then
result[resultIndex] = 0
end
local resultValue = bit.blshift(bit.band(0x000000ff, bytes[i+1]), bit.blshift(bit.band(i, 3), 3))
result[resultIndex] = bit.bor(result[resultIndex], resultValue);
end
return result
end
function convertUIntArrayToBytes(data, includeLength)
local dataLength = table.getn(data)
local n = bit.blshift(dataLength, 2)
local result = {}
if includeLength then
local m = data[dataLength]
if m > n then
return nil
end
n = m
end
for i=0,(n-1) do
local value = bit.band(bit.brshift(data[bit.brshift(i, 2) + 1], (bit.blshift(bit.band(i, 3), 3))), 0xff)
table.insert(result, value)
end
return result
end
function convertToUInt32(value)
if value < 0 then
local absValue = math.abs(value)
local a = math.floor(absValue / 0xFFFFFFFF)
local b = value + a * 0xFFFFFFFF
local c = 0xFFFFFFFF + b + 1
return c
end
return math.mod(value, 0xFFFFFFFF) - math.floor(value / 0xFFFFFFFF)
end
---------------------------------------------------------------------
-- Encryption/decryption common
---------------------------------------------------------------------
function mx(sum, y, z, p, e, k)
local aa = bit.brshift(z, 5)
local ab = convertToUInt32(bit.blshift(y, 2))
local ac = bit.bxor(aa, ab)
local ba = bit.brshift(y, 3)
local bb = convertToUInt32(bit.blshift(z, 4))
local bc = bit.bxor(ba, bb)
local ca = bit.bxor(sum, y)
local dia = bit.band(p, 3)
local dib = bit.bxor(dia, e)
local da = k[dib + 1]
local db = bit.bxor(da, z)
local ea = convertToUInt32(ca + db)
local fa = convertToUInt32(ac + bc)
local ga = bit.bxor(fa, ea)
return ga
end
---------------------------------------------------------------------
-- Decryption
---------------------------------------------------------------------
function decryptIntArray(v, k)
local n = table.getn(v)
local z = v[n]
local y = v[1]
local e = 0
local p = 0
local q = 6 + math.floor(52 / n)
local sum = convertToUInt32(q * delta)
while sum ~= 0 do
e = bit.band(bit.brshift(sum, 2), 3)
for p=n,2,-1 do
z = v[p - 1]
v[p] = convertToUInt32(v[p] - mx(sum, y, z, (p-1), e, k))
y = v[p]
end
z = v[n]
v[1] = convertToUInt32(v[1] - mx(sum, y, z, p, e, k))
y = v[1]
local sumBefore = sum
sum = convertToUInt32(sum - delta)
end
return v
end
function decrypt(data, key)
local dataLength = string.len(data)
local keyLength = string.len(key)
if keyLength == 0 then
return data
end
local keyBytes = convertStringToBytes(key)
local encryptedBytes = convertHexStringToBytes(data)
local dataIntArray = convertBytesToUIntArray(encryptedBytes, false)
local keyIntArray = convertBytesToUIntArray(keyBytes, false)
local decryptedIntArray = decryptIntArray(dataIntArray, keyIntArray)
local decryptedBytes = convertUIntArrayToBytes(decryptedIntArray, true)
local decryptedString = convertBytesToString(decryptedBytes)
return decryptedString
end
---------------------------------------------------------------------
-- Encryption
---------------------------------------------------------------------
function encryptIntArray(v, k)
n = table.getn(v)
if n < 2 then
return v
end
local z = v[n]
local y = v[1]
local sum = 0
local e = 0
local p = 0
local initQ = 6 + math.floor(52 / n)
for q=initQ,1,-1 do
sum = convertToUInt32(sum + delta);
e = bit.band(bit.brshift(sum, 2), 3);
for p=1,(n-1) do
y = v[p + 1];
v[p] = convertToUInt32(v[p] + mx(sum, y, z, (p-1), e, k));
z = v[p]
end
y = v[1];
v[n] = convertToUInt32(v[n] + mx(sum, y, z, (n-1), e, k));
z = v[n]
end
return v;
end
function encrypt(data, key)
local dataLength = string.len(data)
local keyLength = string.len(key)
if (keyLength == 0) then
return data
end
local dataBytes = convertStringToBytes(data)
local keyBytes = convertStringToBytes(key)
local dataIntArray = convertBytesToUIntArray(dataBytes, true)
local keyIntArray = convertBytesToUIntArray(keyBytes, false)
local encryptedIntArray = encryptIntArray(dataIntArray, keyIntArray)
local encryptedBytes = convertUIntArrayToBytes(encryptedIntArray, false)
local encryptedString = convertBytesToHexString(encryptedBytes)
return encryptedString
end
---------------------------------------------------------------------
-- Program: replace
---------------------------------------------------------------------
unencryptedInput = "This is a test"
encryptionKeyInput = "xxxxxxxxxxxxxxxxxxxx" -- Place your encryption key here
encryptedOutput = encrypt(unencryptedInput, encryptionKeyInput)
print(encryptedOutput)
decryptedEncryptedOutput = decrypt(encryptedOutput, encryptionKeyInput)
print(decryptedEncryptedOutput)
AS3语言实现/**********************************************************\
| |
| The implementation of PHPRPC Protocol 3.0 |
| |
| XXTEA.as |
| |
| Release 3.0.0 |
| Copyright (c) 2005-2007 by Team-PHPRPC |
| |
| WebSite: http://www.phprpc.org/ |
| http://www.phprpc.net/ |
| http://www.phprpc.com/ |
| http://sourceforge.net/projects/php-rpc/ |
| |
| Authors: Ma Bingyao <andot@ujn.edu.cn> |
| |
| This file may be distributed and/or modified under the |
| terms of the GNU Lesser General Public License (LGPL) |
| version 3.0 as published by the Free Software Foundation |
| and appearing in the included file LICENSE. |
| |
\**********************************************************/
/* XXTEA encryption arithmetic library.
*
* Copyright (C) 2006-2007 Ma Bingyao <andot@ujn.edu.cn>
* Version: 1.7
* LastModified: Nov 5, 2007
* This library is free. You can redistribute it and/or modify it.
*/
package org.phprpc.util {
import flash.utils.ByteArray;
import flash.utils.Endian;
public class XXTEA {
private static const delta:uint = uint(0x9E3779B9);
private static function LongArrayToByteArray(data:Array, includeLength:Boolean):ByteArray {
var length:uint = data.length;
var n:uint = (length - 1) << 2;
if (includeLength) {
var m:uint = data[length - 1];
if ((m < n - 3) || (m > n)) {
return null;
}
n = m;
}
var result:ByteArray = new ByteArray();
result.endian = Endian.LITTLE_ENDIAN;
for (var i:uint = 0; i < length; i++) {
result.writeUnsignedInt(data[i]);
}
if (includeLength) {
result.length = n;
return result;
}
else {
return result;
}
}
private static function ByteArrayToLongArray(data:ByteArray, includeLength:Boolean):Array {
var length:uint = data.length;
var n:uint = length >> 2;
if (length % 4 > 0) {
n++;
data.length += (4 - (length % 4));
}
data.endian = Endian.LITTLE_ENDIAN;
data.position = 0;
var result:Array = [];
for (var i:uint = 0; i < n; i++) {
result[i] = data.readUnsignedInt();
}
if (includeLength) {
result[n] = length;
}
data.length = length;
return result;
}
public static function encrypt(data:ByteArray, key:ByteArray):ByteArray {
if (data.length == 0) {
return new ByteArray();
}
var v:Array = ByteArrayToLongArray(data, true);
var k:Array = ByteArrayToLongArray(key, false);
if (k.length < 4) {
k.length = 4;
}
var n:uint = v.length - 1;
var z:uint = v[n];
var y:uint = v[0];
var mx:uint;
var e:uint;
var p:uint;
var q:uint = uint(6 + 52 / (n + 1));
var sum:uint = 0;
while (0 < q--) {
sum = sum + delta;
e = sum >>> 2 & 3;
for (p = 0; p < n; p++) {
y = v[p + 1];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
z = v[p] = v[p] + mx;
}
y = v[0];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
z = v[n] = v[n] + mx;
}
return LongArrayToByteArray(v, false);
}
public static function decrypt(data:ByteArray, key:ByteArray):ByteArray {
if (data.length == 0) {
return new ByteArray();
}
var v:Array = ByteArrayToLongArray(data, false);
var k:Array = ByteArrayToLongArray(key, false);
if (k.length < 4) {
k.length = 4;
}
var n:uint = v.length - 1;
var z:uint = v[n - 1];
var y:uint = v[0];
var mx:uint;
var e:uint;
var p:uint;
var q:uint = uint(6 + 52 / (n + 1));
var sum:uint = q * delta;
while (sum != 0) {
e = sum >>> 2 & 3;
for (p = n; p > 0; p--) {
z = v[p - 1];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
y = v[p] = v[p] - mx;
}
z = v[n];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
y = v[0] = v[0] - mx;
sum = sum - delta;
}
return LongArrayToByteArray(v, true);
}
}
}
JS语言实现/* XXTEA encryption arithmetic library.
*
* Copyright (C) 2006 Ma Bingyao <andot@ujn.edu.cn>
* Version: 1.5
* LastModified: Dec 9, 2006
* This library is free. You can redistribute it and/or modify it.
*/
function long2str(v, w) {
var vl = v.length;
var n = (vl - 1) << 2;
if (w) {
var m = v[vl - 1];
if ((m < n - 3) || (m > n)) return null;
n = m;
}
for (var i = 0; i < vl; i++) {
v[i] = String.fromCharCode(v[i] & 0xff,
v[i] >>> 8 & 0xff,
v[i] >>> 16 & 0xff,
v[i] >>> 24 & 0xff);
}
if (w) {
return v.join('').substring(0, n);
}
else {
return v.join('');
}
}
function str2long(s, w) {
var len = s.length;
var v = [];
for (var i = 0; i < len; i += 4) {
v[i >> 2] = s.charCodeAt(i)
| s.charCodeAt(i + 1) << 8
| s.charCodeAt(i + 2) << 16
| s.charCodeAt(i + 3) << 24;
}
if (w) {
v[v.length] = len;
}
return v;
}
function xxtea_encrypt(str, key) {
if (str == "") {
return "";
}
var v = str2long(str, true);
var k = str2long(key, false);
if (k.length < 4) {
k.length = 4;
}
var n = v.length - 1;
var z = v[n], y = v[0], delta = 0x9E3779B9;
var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = 0;
while (0 < q--) {
sum = sum + delta & 0xffffffff;
e = sum >>> 2 & 3;
for (p = 0; p < n; p++) {
y = v[p + 1];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
z = v[p] = v[p] + mx & 0xffffffff;
}
y = v[0];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
z = v[n] = v[n] + mx & 0xffffffff;
}
return long2str(v, false);
}
function xxtea_decrypt(str, key) {
if (str == "") {
return "";
}
var v = str2long(str, false);
var k = str2long(key, false);
if (k.length < 4) {
k.length = 4;
}
var n = v.length - 1;
var z = v[n - 1], y = v[0], delta = 0x9E3779B9;
var mx, e, p, q = Math.floor(6 + 52 / (n + 1)), sum = q * delta & 0xffffffff;
while (sum != 0) {
e = sum >>> 2 & 3;
for (p = n; p > 0; p--) {
z = v[p - 1];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
y = v[p] = v[p] - mx & 0xffffffff;
}
z = v[n];
mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
y = v[0] = v[0] - mx & 0xffffffff;
sum = sum - delta & 0xffffffff;
}
return long2str(v, true);
}
PHP语言实现<?php
/* XXTEA encryption arithmetic library.
*
* Copyright (C) 2006 Ma Bingyao <andot@ujn.edu.cn>
* Version: 1.5
* LastModified: Dec 5, 2006
* This library is free. You can redistribute it and/or modify it.
*/
function long2str($v, $w) {
$len = count($v);
$n = ($len - 1) << 2;
if ($w) {
$m = $v[$len - 1];
if (($m < $n - 3) || ($m > $n)) return false;
$n = $m;
}
$s = array();
for ($i = 0; $i < $len; $i++) {
$s[$i] = pack("V", $v[$i]);
}
if ($w) {
return substr(join('', $s), 0, $n);
}
else {
return join('', $s);
}
}
function str2long($s, $w) {
$v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
$v = array_values($v);
if ($w) {
$v[count($v)] = strlen($s);
}
return $v;
}
function int32($n) {
while ($n >= 2147483648) $n -= 4294967296;
while ($n <= -2147483649) $n += 4294967296;
return (int)$n;
}
function xxtea_encrypt($str, $key) {
if ($str == "") {
return "";
}
$v = str2long($str, true);
$k = str2long($key, false);
if (count($k) < 4) {
for ($i = count($k); $i < 4; $i++) {
$k[$i] = 0;
}
}
$n = count($v) - 1;
$z = $v[$n];
$y = $v[0];
$delta = 0x9E3779B9;
$q = floor(6 + 52 / ($n + 1));
$sum = 0;
while (0 < $q--) {
$sum = int32($sum + $delta);
$e = $sum >> 2 & 3;
for ($p = 0; $p < $n; $p++) {
$y = $v[$p + 1];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$z = $v[$p] = int32($v[$p] + $mx);
}
$y = $v[0];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$z = $v[$n] = int32($v[$n] + $mx);
}
return long2str($v, false);
}
function xxtea_decrypt($str, $key) {
if ($str == "") {
return "";
}
$v = str2long($str, false);
$k = str2long($key, false);
if (count($k) < 4) {
for ($i = count($k); $i < 4; $i++) {
$k[$i] = 0;
}
}
$n = count($v) - 1;
$z = $v[$n];
$y = $v[0];
$delta = 0x9E3779B9;
$q = floor(6 + 52 / ($n + 1));
$sum = int32($q * $delta);
while ($sum != 0) {
$e = $sum >> 2 & 3;
for ($p = $n; $p > 0; $p--) {
$z = $v[$p - 1];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$y = $v[$p] = int32($v[$p] - $mx);
}
$z = $v[$n];
$mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$y = $v[0] = int32($v[0] - $mx);
$sum = int32($sum - $delta);
}
return long2str($v, true);
}
?>
参考资料
wiki百科 https://en.wikipedia.org/wiki/XXTEA
几乎所有语言的实现 https://github.com/xxtea/
AS3 & LUA语言实现 https://forums.coronalabs.com/topic/4738-xxtea-encryption-in-lua/
JS & PHP语言实现 http://www.coolcode.org/?action=show&id=128