/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is JIM.
 *
 * The Initial Developer of the Original Code is
 * Pawel Chmielowski <prefiks@o2.pl>
 *
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Pawel Chmielowski <prefiks@o2.pl>
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * crypto.MD5
 *
 *
 */
ML.load("crypto/utils.js");

function md5_F(X,Y,Z) {
    return (X&Y)|((~X)&Z);
}

function md5_G(X,Y,Z) {
    return (X&Z)|(Y&(~Z));
}

function md5_H(X,Y,Z) {
    return X ^ Y ^ Z;
}

function md5_I(X,Y,Z) {
    return Y ^ (X|(~Z));
}

function md5_bin(data, length) {
    var A, B, C, D;
    var AA, BB, CC, DD;
    var i;

    A =  1732584193;
    B = -271733879;
    C = -1732584194;
    D =  271733878;

    data[length >> 5] |= 0x80 << (length % 32);
    data[((length + 64 >>> 9) << 4) + 14] = length;
    data=swapWords(swapWords(data))
    
    for (i = 0; i < data.length; i+=16) {
        AA = A;
        BB = B;
        CC = C;
        DD = D;

        A=madd(B, bitroll(madd(madd(A, md5_F(B,C,D)), madd(data[i   ], -680876936)), 7));
        D=madd(A, bitroll(madd(madd(D, md5_F(A,B,C)), madd(data[i+ 1], -389564586)), 12));
        C=madd(D, bitroll(madd(madd(C, md5_F(D,A,B)), madd(data[i+ 2],  606105819)), 17));
        B=madd(C, bitroll(madd(madd(B, md5_F(C,D,A)), madd(data[i+ 3], -1044525330)), 22));
        A=madd(B, bitroll(madd(madd(A, md5_F(B,C,D)), madd(data[i+ 4], -176418897)), 7));
        D=madd(A, bitroll(madd(madd(D, md5_F(A,B,C)), madd(data[i+ 5],  1200080426)), 12));
        C=madd(D, bitroll(madd(madd(C, md5_F(D,A,B)), madd(data[i+ 6], -1473231341)), 17));
        B=madd(C, bitroll(madd(madd(B, md5_F(C,D,A)), madd(data[i+ 7], -45705983)), 22));
        A=madd(B, bitroll(madd(madd(A, md5_F(B,C,D)), madd(data[i+ 8],  1770035416)), 7));
        D=madd(A, bitroll(madd(madd(D, md5_F(A,B,C)), madd(data[i+ 9], -1958414417)), 12));
        C=madd(D, bitroll(madd(madd(C, md5_F(D,A,B)), madd(data[i+10], -42063)), 17));
        B=madd(C, bitroll(madd(madd(B, md5_F(C,D,A)), madd(data[i+11], -1990404162)), 22));
        A=madd(B, bitroll(madd(madd(A, md5_F(B,C,D)), madd(data[i+12],  1804603682)), 7));
        D=madd(A, bitroll(madd(madd(D, md5_F(A,B,C)), madd(data[i+13], -40341101)), 12));
        C=madd(D, bitroll(madd(madd(C, md5_F(D,A,B)), madd(data[i+14], -1502002290)), 17));
        B=madd(C, bitroll(madd(madd(B, md5_F(C,D,A)), madd(data[i+15],  1236535329)), 22));
                                                                                     
        A=madd(B, bitroll(madd(madd(A, md5_G(B,C,D)), madd(data[i+ 1], -165796510)), 5));
        D=madd(A, bitroll(madd(madd(D, md5_G(A,B,C)), madd(data[i+ 6], -1069501632)), 9));
        C=madd(D, bitroll(madd(madd(C, md5_G(D,A,B)), madd(data[i+11],  643717713)), 14));
        B=madd(C, bitroll(madd(madd(B, md5_G(C,D,A)), madd(data[i   ], -373897302)), 20));
        A=madd(B, bitroll(madd(madd(A, md5_G(B,C,D)), madd(data[i+ 5], -701558691)), 5));
        D=madd(A, bitroll(madd(madd(D, md5_G(A,B,C)), madd(data[i+10],  38016083)), 9));
        C=madd(D, bitroll(madd(madd(C, md5_G(D,A,B)), madd(data[i+15], -660478335)), 14));
        B=madd(C, bitroll(madd(madd(B, md5_G(C,D,A)), madd(data[i+ 4], -405537848)), 20));
        A=madd(B, bitroll(madd(madd(A, md5_G(B,C,D)), madd(data[i+ 9],  568446438)), 5));
        D=madd(A, bitroll(madd(madd(D, md5_G(A,B,C)), madd(data[i+14], -1019803690)), 9));
        C=madd(D, bitroll(madd(madd(C, md5_G(D,A,B)), madd(data[i+ 3], -187363961)), 14));
        B=madd(C, bitroll(madd(madd(B, md5_G(C,D,A)), madd(data[i+ 8],  1163531501)), 20));
        A=madd(B, bitroll(madd(madd(A, md5_G(B,C,D)), madd(data[i+13], -1444681467)), 5));
        D=madd(A, bitroll(madd(madd(D, md5_G(A,B,C)), madd(data[i+ 2], -51403784)), 9));
        C=madd(D, bitroll(madd(madd(C, md5_G(D,A,B)), madd(data[i+ 7],  1735328473)), 14));
        B=madd(C, bitroll(madd(madd(B, md5_G(C,D,A)), madd(data[i+12], -1926607734)), 20));
                                                                                     
        A=madd(B, bitroll(madd(madd(A, md5_H(B,C,D)), madd(data[i+ 5], -378558)), 4));
        D=madd(A, bitroll(madd(madd(D, md5_H(A,B,C)), madd(data[i+ 8], -2022574463)), 11));
        C=madd(D, bitroll(madd(madd(C, md5_H(D,A,B)), madd(data[i+11],  1839030562)), 16));
        B=madd(C, bitroll(madd(madd(B, md5_H(C,D,A)), madd(data[i+14], -35309556)), 23));
        A=madd(B, bitroll(madd(madd(A, md5_H(B,C,D)), madd(data[i+ 1], -1530992060)), 4));
        D=madd(A, bitroll(madd(madd(D, md5_H(A,B,C)), madd(data[i+ 4],  1272893353)), 11));
        C=madd(D, bitroll(madd(madd(C, md5_H(D,A,B)), madd(data[i+ 7], -155497632)), 16));
        B=madd(C, bitroll(madd(madd(B, md5_H(C,D,A)), madd(data[i+10], -1094730640)), 23));
        A=madd(B, bitroll(madd(madd(A, md5_H(B,C,D)), madd(data[i+13],  681279174)), 4));
        D=madd(A, bitroll(madd(madd(D, md5_H(A,B,C)), madd(data[i   ], -358537222)), 11));
        C=madd(D, bitroll(madd(madd(C, md5_H(D,A,B)), madd(data[i+ 3], -722521979)), 16));
        B=madd(C, bitroll(madd(madd(B, md5_H(C,D,A)), madd(data[i+ 6],  76029189)), 23));
        A=madd(B, bitroll(madd(madd(A, md5_H(B,C,D)), madd(data[i+ 9], -640364487)), 4));
        D=madd(A, bitroll(madd(madd(D, md5_H(A,B,C)), madd(data[i+12], -421815835)), 11));
        C=madd(D, bitroll(madd(madd(C, md5_H(D,A,B)), madd(data[i+15],  530742520)), 16));
        B=madd(C, bitroll(madd(madd(B, md5_H(C,D,A)), madd(data[i+ 2], -995338651)), 23));
                                                                                     
        A=madd(B, bitroll(madd(madd(A, md5_I(B,C,D)), madd(data[i   ], -198630844)), 6));
        D=madd(A, bitroll(madd(madd(D, md5_I(A,B,C)), madd(data[i+ 7],  1126891415)), 10));
        C=madd(D, bitroll(madd(madd(C, md5_I(D,A,B)), madd(data[i+14], -1416354905)), 15));
        B=madd(C, bitroll(madd(madd(B, md5_I(C,D,A)), madd(data[i+ 5], -57434055)), 21));
        A=madd(B, bitroll(madd(madd(A, md5_I(B,C,D)), madd(data[i+12],  1700485571)), 6));
        D=madd(A, bitroll(madd(madd(D, md5_I(A,B,C)), madd(data[i+ 3], -1894986606)), 10));
        C=madd(D, bitroll(madd(madd(C, md5_I(D,A,B)), madd(data[i+10], -1051523)), 15));
        B=madd(C, bitroll(madd(madd(B, md5_I(C,D,A)), madd(data[i+ 1], -2054922799)), 21));
        A=madd(B, bitroll(madd(madd(A, md5_I(B,C,D)), madd(data[i+ 8],  1873313359)), 6));
        D=madd(A, bitroll(madd(madd(D, md5_I(A,B,C)), madd(data[i+15], -30611744)), 10));
        C=madd(D, bitroll(madd(madd(C, md5_I(D,A,B)), madd(data[i+ 6], -1560198380)), 15));
        B=madd(C, bitroll(madd(madd(B, md5_I(C,D,A)), madd(data[i+13],  1309151649)), 21));
        A=madd(B, bitroll(madd(madd(A, md5_I(B,C,D)), madd(data[i+ 4], -145523070)), 6));
        D=madd(A, bitroll(madd(madd(D, md5_I(A,B,C)), madd(data[i+11], -1120210379)), 10));
        C=madd(D, bitroll(madd(madd(C, md5_I(D,A,B)), madd(data[i+ 2],  718787259)), 15));
        B=madd(C, bitroll(madd(madd(B, md5_I(C,D,A)), madd(data[i+ 9], -343485551)), 21));

        A = madd(A, AA);
        B = madd(B, BB);
        C = madd(C, CC);
        D = madd(D, DD);
    }
    return new Array(A, B, C, D);
}

function md5(data, isWideChar) {
    return bin2hex(md5_bin(string2bin(data, false, isWideChar), data.length*(isWideChar ? 16 : 8)));
}

