/* Copyright (C) 2003 Donald J Bindner. * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. */ var delta = 0x9E3779B9; var k = new Array(); var r=0; function tea_encode( str, key ) { /* Encodes a string 'str' using secret key 'key' and returns * a Base64 encoded string. */ return TEAArrayToBase64( tea_encodeCBC( stringToTEAArray(str), MD5key(key)) ); } function tea_decode( str, key ) { /* Decodes a Base64 encoded string 'str' using secret key 'key' and * returns the original plaintext. */ return TEAArrayToString( tea_decodeCBC( base64ToTEAArray(str), MD5key(key)) ); } function stringToTEAArray( str ) { /* converts a string to an padded array of longs with an IV */ var i,j,l; var strl = str.length; var y,z; y = Math.floor( Math.random() * 256 * 256 * 256 * 256 ); z = Math.floor( Math.random() * 256 * 256 * 256 * 256 ); var arr = [ 0x646e6152, 0x56496d6f, y, z ]; arr.length = Math.floor(strl/8+1)*2+4; i=4; j=0; l = strl - strl%8; while( j < l ) { arr[i++] = str.charCodeAt( j++ ) | str.charCodeAt( j++ )<<8 | str.charCodeAt( j++ )<<16 | str.charCodeAt( j++ )<<24; arr[i++] = str.charCodeAt( j++ ) | str.charCodeAt( j++ )<<8 | str.charCodeAt( j++ )<<16 | str.charCodeAt( j++ )<<24; } /* Pad the end of the string */ var tail = str.slice(l,strl); for( j = 0; j < 8-strl+l; j++ ) { tail += String.fromCharCode( 8-strl+l ); } arr[i++] = tail.charCodeAt( 0 ) | tail.charCodeAt( 1 )<<8 | tail.charCodeAt( 2 )<<16 | tail.charCodeAt( 3 )<<24; arr[i++] = tail.charCodeAt( 4 ) | tail.charCodeAt( 5 )<<8 | tail.charCodeAt( 6 )<<16 | tail.charCodeAt( 7 )<<24; return arr; } function TEAArrayToString( arr ) { /* converts a padded array of longs to a string */ var l = arr.length - 2; str = new String; for( var i = 4; i < l; i++ ) { str += String.fromCharCode( arr[i] & 0xff ) + String.fromCharCode( arr[i]>>>8 & 0xff ) + String.fromCharCode( arr[i]>>>16 & 0xff ) + String.fromCharCode( arr[i]>>>24 & 0xff ); } var tail = String.fromCharCode( arr[l] & 0xff ) + String.fromCharCode( arr[l]>>>8 & 0xff ) + String.fromCharCode( arr[l]>>>16 & 0xff ) + String.fromCharCode( arr[l]>>>24 & 0xff ) + String.fromCharCode( arr[l+1] & 0xff ) + String.fromCharCode( arr[l+1]>>>8 & 0xff ) + String.fromCharCode( arr[l+1]>>>16 & 0xff ) + String.fromCharCode( arr[l+1]>>>24 & 0xff ); /* clip off the padding characters */ var clip = arr[l+1]>>>24; str += tail.slice(0,8-clip); return str; } function tea_setup( key, rounds ) { /* sets up the cipher with key and rounds */ r = rounds; k = key; } function tea_encodeCBC( arr, md5key ) { /* accepts a padded array of longs and a key array of 4 32 bit numbers * (typically the MD5 of the password), and returns an encrypted array * of longs */ var sum; var y, z; /* Get the IV */ y = arr[2]; z = arr[3]; /* initialize TEA with MD5 hash of our key and 32 rounds */ tea_setup( md5key, 32 ); var l = arr.length; var i = 4; /* xor each block with the cipher text from previous round and encode */ while( i < l ) { y ^= arr[i]; z ^= arr[i+1]; /* This is the actual encode step */ sum=0; for( var j = 0; j < r; j++ ) { y += ( ((z<<4)^(z>>>5)) + z ) ^ ( sum + k[sum&3] ); sum += delta; z += ( ((y<<4)^(y>>>5)) + y ) ^ ( sum + k[(sum>>>11)&3]); } arr[i++] = y^0; arr[i++] = z^0; } return arr; } function tea_decodeCBC( arr, md5key ) { /* accepts a padded array of longs and a key array of 4 32 bit * numbers (typically the MD5 of the password), and returns a * decrypted array */ var y,z; var ny, nz; /* random initial vector */ var oy = arr[2]; var oz = arr[3]; /* initialize TEA with MD5 hash of our key and 32 rounds */ tea_setup( md5key, 32 ); var l = arr.length; var i = 4; /* decrypt each block and xor with the cipher text from previous round */ while( i < l ) { y = ny = arr[i]; z = nz = arr[i+1]; /* This is the actual decode step */ sum = delta*r; for( var j = 0; j < r; j++ ) { z -= ( ((y<<4)^(y>>>5)) + y ) ^ ( sum + k[(sum>>>11)&3]); sum -= delta; y -= ( ((z<<4)^(z>>>5)) + z ) ^ ( sum + k[sum&3] ); } arr[i++] = y^oy; arr[i++] = z^oz; oy = ny; oz = nz; } return arr; } var b64chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; function TEAArrayToBase64( arr ) { /* Converts an array of longs to a base64 string */ var str = new String(); var a, b, c, d; var llen; /* characters to keep in the next iteration of the loop */ var o1, o2; var j; var offset = 0; var l = arr.length; var llen = 0; for( var i = 0; i < l; i++ ) { a = arr[i] & 0xff; b = arr[i]>>>8 & 0xff; c = arr[i]>>>16 & 0xff; d = arr[i]>>>24 & 0xff; if( offset == 0 ) { str += b64chr.charAt( a>>>2 & 0x3f ); str += b64chr.charAt( ((a&3)<<4) + (b>>>4) ); str += b64chr.charAt( ((b&15)<<2) + (c>>>6) ); str += b64chr.charAt( c & 0x3f ); o1 = d; } else if( offset == 1 ) { str += b64chr.charAt( o1>>>2 & 0x3f ); str += b64chr.charAt( ((o1&3)<<4) + (a>>>4) ); str += b64chr.charAt( ((a&15)<<2) + (b>>>6) ); str += b64chr.charAt( b & 0x3f ); o1 = c; o2 = d; } else { str += b64chr.charAt( o1>>>2 & 0x3f ); str += b64chr.charAt( ((o1&3)<<4) + (o2>>>4) ); str += b64chr.charAt( ((o2&15)<<2) + (a>>>6) ); str += b64chr.charAt( a & 0x3f ); llen += 4; if( llen >= 60 ) { str += "\n"; llen = 0; } str += b64chr.charAt( b>>>2 & 0x3f ); str += b64chr.charAt( ((b&3)<<4) + (c>>>4) ); str += b64chr.charAt( ((c&15)<<2) + (d>>>6) ); str += b64chr.charAt( d & 0x3f ); } offset = ( offset + 1 )%3; llen += 4; if( llen >= 60 ) { str += "\n"; llen = 0; } } if( offset == 1 ) { str += b64chr.charAt( o1>>>2 ); str += b64chr.charAt( (o1&3)<<4 ); str += "=="; } else if( offset == 2 ) { str += b64chr.charAt( o1>>>2 ); str += b64chr.charAt( ((o1&3)<<4) + (o2>>>4) ); str += b64chr.charAt( (o2&15)<<2 ); str += "="; } return str; } function base64ToTEAArray( str ) { /* Decodes a base64 string to an array of longs */ var arr = new Array; var j = 0; var offset = 0; var tmp, pad=0; var l = str.length; var i = 0; while( i < l ) { while( i= l ) break; if( str.charAt(i) == "=" ) break; a = b64chr.indexOf( str.charAt( i++ )); while( i= l ) break; if( str.charAt(i) == "=" ) break; b = b64chr.indexOf( str.charAt( i++ )); while( i= l ) break; if( str.charAt(i) == "=" ) { pad = 2; c = d = 0; break; } c = b64chr.indexOf( str.charAt( i++ )); while( i= l ) break; if( str.charAt(i) == "=" ) { pad = 1; d = 0; break; } d = b64chr.indexOf( str.charAt( i++ )); tmp = (a<<2) | (d<<16) | (b>>>4) | ((b & 0xf)<<12 ) | ((c & 0x03)<<22) | ((c & 0x3c)<<6 ); if( offset == 0 ) { arr[j] = tmp; } else if( offset == 1 ) { arr[j++] |= tmp<<8; } else if( offset == 2 ) { arr[j++] |= tmp<<16; arr[j] = tmp>>>16; } else if( offset == 3 ) { arr[j++] |= tmp<<24; arr[j] = tmp>>>8; } offset = (offset + 3)%4; } tmp = (a<<2) | (b>>>4) | ((b & 0xf)<<12 ) | ((c & 0x03)<<22) | ((c & 0x3c)<<6 ); if( pad == 2 ) { arr[j] |= tmp << 24; } else if( pad == 1 ) { arr[j] |= tmp << 16; } return arr; }