// xxtea.js

function strToLongs(s)
{
    // convert string to array of longs, each containing 4 chars
    // note chars must be within ISO-8859-1 (with Unicode code-point < 256) to fit 4/long
    var l = new Array(Math.ceil(s.length/4));
    for (var i=0; i<l.length; i++) {
        // note little-endian encoding - endianness is irrelevant as long as
        // it is the same in longsToStr()
        l[i] = s.charCodeAt(i*4) + (s.charCodeAt(i*4+1)<<8) +
               (s.charCodeAt(i*4+2)<<16) + (s.charCodeAt(i*4+3)<<24);
    }
    return l;  // note running off the end of the string generates nulls since
}              // bitwise operators treat NaN as 0

function longsToStr(l)
{
    // convert array of longs back to string
    var a = new Array(l.length);
    for (var i=0; i<l.length; i++) {
        var aa = l[i] & 0xFF;
        var ab = l[i]>>>8 & 0xFF;
        var ac = l[i]>>>16 & 0xFF;
        var ad = l[i]>>>24 & 0xFF;

        a[i] = String.fromCharCode(aa,ab,ac,ad);
    }

    return a.join('');  // use Array.join() rather than repeated string appends for efficiency
}

function TEAEncrypt(plaintext, password)
{
    if (plaintext.length == 0) {
        return('');
    }

    var asciitext = new Base64().encode(plaintext);
    var v = strToLongs(asciitext);  // convert string to array of longs

    if (v.length <= 1) {
        v[1] = 0;  // algorithm doesnt work for n<2 so fudge by adding a null
    }
    var k = strToLongs(password.slice(0,16));  // simply convert first 16 chars of password as key

    var n = v.length;

    var z = v[n-1], y = v[0], delta = 0x9E3779B9;
    var mx, e, q = Math.floor(6 + 52/n), sum = 0;

    while (q-- > 0) {  // 6 + 52/n operations gives between 6 & 32 mixes on each word
        sum += delta;
        e = sum>>>2 & 3;
        for (var p = 0; p < n; p++) {
            y = v[(p+1)%n];
            mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
            z = v[p] += mx;
        }
    }

    var ciphertext = longsToStr(v);

    return ciphertext;
}

//
// TEADecrypt: Use Corrected Block TEA to decrypt ciphertext using password
//
function TEADecrypt(ciphertext, password)
{
    if (ciphertext.length == 0) return('');
    var v = strToLongs(ciphertext);
    var k = strToLongs(password.slice(0,16)); 
    var n = v.length;

    var z = v[n-1], y = v[0], delta = 0x9E3779B9;
    var mx, e, q = Math.floor(6 + 52/n), sum = q*delta;

    while (sum != 0) {
        e = sum>>>2 & 3;
        for (var p = n-1; p >= 0; p--) {
            z = v[p>0 ? p-1 : n-1];
            mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
            y = v[p] -= mx;
        }
        sum -= delta;
    }

    var plaintext = longsToStr(v);
    
    // strip trailing null chars resulting from filling 4-char blocks:
    plaintext = plaintext.replace(/\0+$/,'');

    plaintext = new Base64().decode(plaintext);
    
    return plaintext;
}

