JavaScript numbers
Javascript uses IEEE 754 for the representation of numbers, which are
64 bit double precision floating point numbers, which are exact for
integers up to 53 bits. Javascript performs the common arithmetic
operations such as addition and multiplication in sufficient
precision, i.e., 53 bits when no overflow occurs. However, Javascript
performs certain bit-wise operations (such as XOR '^', SHIFT
'<<', etcetera) in 32 bit precision. The results of such
operations are sign-extended (at least they are in Firefox/Linux and InternetExplorer/WinXP). That is,
if the result of such a 32-bit operation in an environment where a
64-bit value is required has bit 31 set to 1, the result is extended
to a negative number, and otherwise to a positive number.
This situation may lead to unexpected results. For instance, the value of (1<<31)+2*(1<<30)
is computed by your browser as 0, which may be unexpected because it is the sum of two large positive numbers.
More surprising is that both these numbers are expressible in 32 bits.
The reason for this idiosyncrasy is that 1<<31 has bit 1 set, and
is therefore extended to a negative number (-2147483648). In this case precisely
minus 2*(1<<30). Subsequent addition leads to erors that permeate within the lower 32 bits.
Unfortunately the TEA algorithm is a mesh of bit-wise and ordinary arithmetic operations by intention.
For instance, the algorithm contains a statement such as y += ((z << 4) ^ (z >> 5)) + (z ^ sum) + k[sum&3];.
That statement is bound to produce erroneous results in JavaScript, so the two implementations mentioned in Simon Shepherd's site are flawed (http://www.simonshepherd.supanet.com/tea_js.htm and http://www.simonshepherd.supanet.com/jstea.htm).
This may seem not so bad as all: encryption and decryption are inverse functions so as long as the flaw is symmetric, i.e., is reversed when a function's reverse is used, everything is ok. This seems to be the case in the mentioned implementations, because they are able to decrypt their encrypted data.
Two problems remain:
-
When the algorithm is used in agent-communication, where agents use different implementations (such as JavaScript-PHP client-server communication) decryption no longer works, asuming the second language doesn't exhibit the same behavior;
-
Perhaps more importantly, the desirable theoretic properties of TEA, diffusion and confusion, are reduced by this flaw. This implementation is theoretically less secure.
The solution shown
here
sets the result of every 32-bit operation to the appropriate positive value.
The JavaScript and PHP implementations are compatible and can decrypt each others data.
PHP
Note that the PHP implementation also truncates values at 32
bits. This is necessary to mimic 32-bit unsigned arithmetic. It
is required because the algorithm right-shifts bits that are more
significant than bit 32 back the least-significant bits.