You are here : Home » Learning security » Applications » Web applications » Javascript -Java compatible encryption

Javascript -Java compatible encryption

Implementation of Tiny Encryption Algorithm

D 7 April 2011     H 13:43     A Emeric Nasi     C 0 messages


agrandir


License : Copyright Emeric Nasi, some rights reserved
This work is licensed under a Creative Commons Attribution 4.0 International License.
Creative Commons License

Introduction

I decided a few weeks ago to create my own Java "stealth malware" I called Bromo. This malware’s goal is to test and demonstrate Java security and insecurity in a corporate environment by targeting a Java application. For example an "evil" Jar that could be included by a developer.
I adapted Bromo to Web Application trojaning so that a distant attacker could control from anywhere via Firefox for example. The problem that occurred to me was to secure the communication between the attacker navigator and the Web server.
In this case I do not have the hand on the server, and I need to be as stealthy as possible. Moreover I need an encryption system that can prevent anyone (WAF and admins) from reading the content of the requests and responses I send to the malware.
That’s why it led me to use Javascript encryption.
In this article I do not describe the malware itself.
This article sections are :

  • The encryption algorithm I chose
  • The Java implementation of the algorithm
  • The Javascript implementation of the algorithm

The difficulty here is to have compatible implementation between Java and Javascript (which is not a piece of cake).

Warning : I do not recommend to use Javascript encryption. It is often the worst choice. However there are cases (like mine) where it can be helpful. If you want to read more about the pros and the cons of Javascript encryption read this article.

I. Tiny Encryption Algorithm

Also called "TEA" or just "Tiny", the Tiny Encryption Algorithm was first presented in 1994 by David Wheeler and Roger Needham from Cambridge.
TEA encryption relies on a cipher operation that encrypts two 32bit Integers using a 4*32bits key.
This algorithm has two main assets. First it is not subject to any sort of patent or license, next it offers a strong cryptography in regard to the easiness of its implementation.
If you want to learn more about TEA, you should have a look at the TEA official page. This website presents a lot of TEA implementation and I relied heavily on it when I had to build my own Java and JavaScript implementation.

II. Java TEA implementation

II.1 About Java TEA implementation

The next Java TEA implementation is based on various TEA implementation you can find on the TEA official page. The main problem with a Java TEA implementation is the lack of "unsigned" types in the Java language. The TEA algorithm relies on fast shifting on unsigned 32-bits integers, and that is also the case for other language implementation. This suggests we will have a compatibility problem between Java and other language implementation.
Because we cannot force Java to use unsigned int we will have to use a classical Java TEA implementation, and force unsigned int usage on the other side (JavaScript implementation).

II.2 Utility functions

The Java implementation part is not a big problem, base 64 conversion, int[] to byte[] and other utility function can be found easily on the Internet.
You can always email me if you want the complete source codes.

II.3 The TEA cipher

TEA is mainly a cipher operating on blocks of 64 bits. The next encipher and decipher are very common to all language TEA implementations. However you can notice the use of the >>> operator witch is an unsigned right shift (all bits are shift from one position to the right, the left positions are filled with zeros).

  1.  
  2. /**
  3. * Contains the 128 bit key.
  4. */
  5. private int __key__[];
  6.  
  7. /**
  8. * Encipher two ints.
  9. * Replaces the original contents of the parameters with the results.
  10. * @param v two int array as input.
  11. * @return array of two enciphered ints.
  12. */
  13. private int[] encipher(final int v[]) {
  14. int y = v[0];
  15. int z = v[1];
  16. int sum = 0;
  17. final int delta = 0x9E3779B9;
  18. final int a = this.__key__[0];
  19. final int b = this.__key__[1];
  20. final int c = this.__key__[2];
  21. final int d = this.__key__[3];
  22. int n = 32;
  23.  
  24. while (n-- > 0) {
  25. sum += delta;
  26. y += (z << 4) + a ^ z + sum ^ (z >>> 5) + b;
  27. z += (y << 4) + c ^ y + sum ^ (y >>> 5) + d;
  28. }
  29.  
  30. v[0] = y;
  31. v[1] = z;
  32.  
  33. return v;
  34. }
  35.  
  36. /**
  37. * Decipher two ints.
  38. * Replaces the original contents of the parameters with the results.
  39. * @param v 2 int array
  40. * @return deciphered 2 int array
  41. */
  42. private int[] decipher(final int v[]) {
  43. int y = v[0];
  44. int z = v[1];
  45. int sum = 0xC6EF3720;
  46. final int delta = 0x9E3779B9;
  47. final int a = this.__key__[0];
  48. final int b = this.__key__[1];
  49. final int c = this.__key__[2];
  50. final int d = this.__key__[3];
  51. int n = 32;
  52.  
  53. while (n-- > 0) {
  54. z -= (y << 4) + c ^ y + sum ^ (y >>> 5) + d;
  55. y -= (z << 4) + a ^ z + sum ^ (z >>> 5) + b;
  56. sum -= delta;
  57. }
  58.  
  59. v[0] = y;
  60. v[1] = z;
  61.  
  62. return v;
  63. }
  64.  
  65.  

II.4 Encryption/Decryption

The next functions are the entry point for the TEA algorithm.
The data en encode or decode is stored in an array of bytes.

  1.  
  2. /**
  3.   * Amount of padding added in byte --> integer conversion.
  4.   */
  5. private int __padding__;
  6.  
  7. /**
  8. * Turns a given byte array into an encrypted integers array.
  9. * @param b incoming <code>byte array
  10. * @param byte count
  11. * @return integer conversion array, possibly with padding.
  12. * @see #padding
  13. */
  14. private int[] encode(final byte b[], final int count) {
  15. int j, i;
  16. int bLen = count;
  17. byte bp[] = b;
  18. // We check if we need to add some padding
  19. this.__padding__ = bLen % 8;
  20. if (this.__padding__ != 0) // Add some padding, if necessary.
  21. {
  22. this.__padding__ = 8 - bLen % 8;
  23. bp = new byte[bLen + this.__padding__];
  24. System.arraycopy(b, 0, bp, 0, bLen);
  25. bLen = bp.length;
  26. }
  27.  
  28. final int intCount = bLen / 4;
  29. final int r[] = new int[2];
  30. final int out[] = new int[intCount];
  31. // Here we encipher all the bytes
  32. for (i = 0, j = 0; j < bLen; j += 8, i += 2) {
  33. // 8 byte to 2 int conversion
  34. r[0] = bp[j] << 24 | (bp[j + 1] & 0xff) << 16 | (bp[j + 2] & 0xff) << 8 | bp[j + 3] & 0xff;
  35. r[1] = bp[j + 4] << 24 | (bp[j + 5] & 0xff) << 16 | (bp[j + 6] & 0xff) << 8 | bp[j + 7] & 0xff;
  36. encipher(r);
  37. // Store enciphered bytes in "out" 2 bytes array
  38. out[i] = r[0];
  39. out[i + 1] = r[1];
  40. }
  41.  
  42. return out;
  43. }
  44.  
  45. /**
  46. * Decode an integer array. There may be some padding at the end of the byte array from the previous encode operation.
  47. * @param b bytes to decode
  48. * @return byte array of decoded bytes.
  49. */
  50. private byte[] decode(final int b[]) {
  51. // create the large number and start stripping ints out, two at a time.
  52. final int intCount = b.length;
  53.  
  54. final byte outb[] = new byte[intCount * 4];
  55. final int tmp[] = new int[2];
  56.  
  57. // decipher all the ints.
  58. int i, j;
  59. for (j = 0, i = 0; i < intCount; i += 2, j += 8) {
  60. tmp[0] = b[i];
  61. tmp[1] = b[i + 1];
  62. decipher(tmp);
  63. outb[j] = (byte) (tmp[0] >>> 24);
  64. outb[j + 1] = (byte) (tmp[0] >>> 16);
  65. outb[j + 2] = (byte) (tmp[0] >>> 8);
  66. outb[j + 3] = (byte) tmp[0];
  67. outb[j + 4] = (byte) (tmp[1] >>> 24);
  68. outb[j + 5] = (byte) (tmp[1] >>> 16);
  69. outb[j + 6] = (byte) (tmp[1] >>> 8);
  70. outb[j + 7] = (byte) tmp[1];
  71. }
  72.  
  73. return outb;
  74. }
  75.  

III. JavaScript TEA implementation

III.1 About JavaScript TEA implementation

The goal of this implementation is to provide conversion functions between JavaScript strings and encrypted base64 strings. These base64 encrypted strings should be compatible with the Java implementation encrypted strings.
Even if there are a lot of good TEA JavaScript implementation on the Internet, none of them are "Java compliant". Remember, Java does not manage unsigned integers! The problem we have is that all JavaScript integer are unsigned by default. And all the existing TEA JavaScript implementation use unsigned integers (which is normal because TEA is supposed to be more efficient with unsigned integers).
My JavaScript TEA implementation is an extension of the JavaScript TEA implementation of Chris Veness.
Here is the code header :

  1. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  2. /* Tiny Encryption Algorithm implementation in JavaScript */
  3. /* JavaScript implementation Based on : Chris Veness, Movable Type Ltd: www.movable-type.co.uk */
  4. /* Java compatibility added by Emeric Nasi */
  5. /* About Java compatibility :
  6. The javascript implementation was modified to use signed integer due to the lack of
  7. unsigned types in Java.
  8. The output and input of the encrypt/decrypt methods are a base64 encoding of and UTF-8 string */
  9. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  10. /* Algorithm: David Wheeler & Roger Needham, Cambridge University Computer Lab */
  11. /* http://www.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html (1994) */
  12. /* http://www.cl.cam.ac.uk/ftp/users/djw3/xtea.ps (1997) */
  13. /* http://www.cl.cam.ac.uk/ftp/users/djw3/xxtea.ps (1998) */
  14. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

III.2 Utility functions

Fist we need to define a set of utility functions that we will need in our TEA implementation.

Note : Notice the use of "integer|0" operation. This is the workaround used to force unsigned integers into signed integers.
  1. /**
  2.  * Convert an int into 4 bytes
  3.  */
  4. function getBytes( x ){
  5. //alert("x :"+x);
  6. var bytes = [];
  7. var padding = 0;
  8. var i = 4;
  9. do {
  10. bytes[--i] = ((x & (255))|0);
  11. x = ((x|0)>>8)|0;
  12. bytes[i] = (bytes[i]|0);
  13. } while ( i )
  14. return bytes;
  15. }
  16.  
  17. /**
  18.  * Convert 4 chars (8 bits) of s to a numeric long.
  19.  */
  20. function Str4ToLong(s) //
  21. {
  22. var key = (s.charCodeAt(0) << 24) | (((s.charCodeAt(1)) & 0xff) << 16)
  23. | (((s.charCodeAt(2)) & 0xff) << 8) | ((s.charCodeAt(3)) & 0xff);
  24. return key;
  25. }
  26.  
  27. /**
  28.  * Convert a numeric long to 4 8 bits chars string.
  29.  */
  30. function LongToStr4(v){
  31. // Get bytes corresponding to int
  32. var bytes = getBytes(v);
  33. // Convert the bytes to a String
  34. var s = "";
  35. s+=String.fromCharCode(bytes[0]);
  36. s+=String.fromCharCode(bytes[1]);
  37. s+=String.fromCharCode(bytes[2]);
  38. s+=String.fromCharCode(bytes[3]);
  39. return(s);
  40. }
  41.  

In my JavaScript implementation I used Base64 and UFT-8 encoding/decoding functions. Because they are just a copy/past from the Chris Veness JavaScript TEA implementation, I will not describe them here. If you want to implement the same system as I did, you can get these functions source code here.

III.3 The TEA cipher

As in the Java implementation, the cipher functions are the heart of the encryption algorithm.
The Tea cipher and decipher functions take 2 integers and apply the cipher in part I.2.

  1. /**
  2.  * Encipher two ints.
  3.  * Replaces the original contents of the parameters with the results.
  4.  * The integers are usually created from 8 bytes.
  5.  * NOTE : All operation are made using signed integers for java/javascript compatibility.
  6.  * @param v 2 int array
  7.  * @param k 4 int key
  8.  * @return 2 encrypted ints.
  9.  */
  10. function cipher(v, k){
  11.  
  12. var y = v[0], z = v[1];
  13. // Note that delta is forced to the signed int value corresponding to 0x9E3779B9
  14. var delta = -1640531527, limit = delta*32, sum = 0;
  15.  
  16. var a = new Number(k[0]);
  17. var b = new Number(k[1]);
  18. var c = new Number(k[2]);
  19. var d = new Number(k[3]);
  20.  
  21. var n = 32;
  22. while (n-- > 0) {
  23. sum = ((delta+sum)|0);
  24. y += ((((z << 4) + a)|0) ^ ((z + sum)|0) ^ (((z >>> 5) + b)|0))|0;
  25. y = y|0;
  26. z += ( ((((y << 4) + c)|0) ^ ((y + sum)|0) ^ (((y >>> 5) + d)|0))|0);
  27. z = z|0;
  28. }
  29.  
  30. v[0] = y;
  31. v[1] = z;
  32. }
  33.  
  34. /**
  35.  * Decipher two ints.
  36.  * Replaces the original contents of the parameters with the results.
  37.  * The integers are decoded to 8 bytes.
  38.  * NOTE : All operations are made using signed integers for java/javascript compatibility.
  39.  * @param v 2 int array
  40.  * @param k 4 int key
  41.  * @return 2 encrypted ints.
  42.  */
  43. function decipher(v, k){
  44. var y = v[0], z = v[1];
  45. // Note that delta is forced to the signed int value corresponding to 0x9E3779B9
  46. var delta = -1640531527;
  47. var sum = delta*32;
  48.  
  49. var a = new Number(k[0]);
  50. var b = new Number(k[1]);
  51. var c = new Number(k[2]);
  52. var d = new Number(k[3]);
  53. var n = 32;
  54. while (n-- > 0) {
  55. z -= ( ((((y << 4) + c)|0) ^ ((y + sum)|0) ^ (((y >>> 5) + d)|0))|0);
  56. z = z|0;
  57. y -= ((((z << 4) + a)|0) ^ ((z + sum)|0) ^ (((z >>> 5) + b)|0))|0;
  58. y = y|0;
  59. sum = ((sum-delta)|0);
  60. }
  61.  
  62. v[0] = y;
  63. v[1] = z;
  64. }
  65.  

III.4 Encryption/Decryption

These are the entry points of our JavaScript TEA implementation.

  1. /**
  2.  * Encryption using Tea algorithm.
  3.  * @param val The string we want to encrypt
  4.  * @param key The 16 byte encryption key
  5.  * @return base64 encoding of encrypted val.
  6.  */
  7. function encrypt(val, key)
  8. {
  9. // 128 bits (16 chars) of string 'key' are used to encrypt string 'val'; function
  10. // returns encrypted version of 'val'.
  11. var v = new Array(2), k = new Array(4), s = "", i;
  12. val = Utf8.encode(val); // Convert val to UTF-8
  13.  
  14. k[0] = Str4ToLong(key.substr(0,4));
  15. k[1] = Str4ToLong(key.substr(4,4));
  16. k[2] = Str4ToLong(key.substr(8,4));
  17. k[3] = Str4ToLong(key.substr(12,4));
  18.  
  19. for (i=0; i<val.length; i+=8) {
  20.  
  21. // Convert 64 bits (8 chars) into 2 32 bits integers
  22. v[0] = Str4ToLong(val.substr(i,4));
  23. v[1] = Str4ToLong(val.substr(i+4,4));
  24.  
  25. // Cipher the two integers
  26. cipher(v, k);
  27.  
  28. // Fill array with encrypted integers
  29. s+=LongToStr4(v[0]);
  30. s+=LongToStr4(v[1]);
  31. }
  32. return(Base64.encode(s));
  33. }
  34.  
  35. /**
  36.  * Decryption using Tea algorithm.
  37.  * @param b64val The base64 encoding of val we want to decrypt
  38.  * @param key The 16 byte encryption key
  39.  * @return The original string.
  40.  */
  41. function decrypt(b64val, key){
  42.  
  43. var v = new Array(2), k = new Array(4), s = "", i;
  44. var val = Base64.decode(b64val); // Base64 decode of val.
  45.  
  46. k[0] = Str4ToLong(key.substr(0,4));
  47. k[1] = Str4ToLong(key.substr(4,4));
  48. k[2] = Str4ToLong(key.substr(8,4));
  49. k[3] = Str4ToLong(key.substr(12,4));
  50.  
  51. val = unescape(val); // corrected NVS 2005.04.27
  52. // decode val into s in 64-bit (8 char) blocks
  53. for (i=0; i<val.length; i+=8) {
  54. v[0] = Str4ToLong(val.substr(i,4));
  55. v[1] = Str4ToLong(val.substr(i+4,4));
  56. decipher(v, k);
  57. s += LongToStr4(v[0]) + LongToStr4(v[1]);
  58. }
  59.  
  60. // strip trailing null chars resulting from filling 4-char blocks
  61. if (s.indexOf("\x00") != -1) {
  62. s = s.substr(0, s.indexOf("\x00"));
  63. }
  64.  
  65. return(Utf8.decode(s));
  66. }

As you can see, encryption/decryption compatibility between language is not always something trivial. If you wonder why Java does not implement unsigned integers you can always have a look at that discussion on the stackoverflow Q&A.
Concerning JavaScript, there are a lot of implementation of encryption function out there but remember that JavaScript encryption is almost never a good solution, and that you have to deal with the problems of navigators compatibility and server language compatibility.
I did not post all the source code in this article, if you want to have the complete JavaScript or Java source you can email me at emeric.nasi[at]sevagas.com

Also in this section

2 January – XSS : Get string without quote

23 October 2010 – One time passwords

Any message or comments?
pre-moderation

This forum is moderated before publication: your contribution will only appear after being validated by an administrator.

Who are you?
Your post