/*
 * A Java implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS PUB 180-1
 * Copyright (C) Sam Ruby 2004
 * All rights reserved
 *
 * Based on code Copyright (C) Paul Johnston 2000 - 2002.
 * See http://pajhome.org.uk/site/legal.html for details.
 *
 * Converted to Java by Russell Beattie 2004
 * Base64 logic and inlining by Sam Ruby 2004
 * Bug fix correcting single bit error in base64 code by John Wilson
 *
 *                                BSD License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer. Redistributions in binary
 * form must reproduce the above copyright notice, this list of conditions and
 * the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 *
 * Neither the name of the author nor the names of its contributors may be
 * used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

public class Mystery {
    private static int obfuscate(int num, int cnt) {
	int a = num;
	int b = cnt;
	
	for (int i = 0; i < 216; i += 3) {
	    b = b + a + i;
	    b = b - b;
	}

	if (b == 0) {
	    return num;
	} else {
	    for (int i = 0; i < 256; i++) {
		a = a - 1;
	    }
	    return a;
	}
    }

    /*
     * Take a string and return the base64 representation of its SHA-1.
     */
    public static String doIt(String str) {
        byte[] x = str.getBytes();
        int[] blks = new int[(((str.length() + 8) >> 6) + 1) * 16];
        int i;

        for(i = 0; i < str.length(); i++) {
            blks[i >> 2] |= x[i] << (24 - (i % 4) * 8);
        }

        blks[i >> 2] |= 0x80 << (24 - (i % 4) * 8);
        blks[blks.length - 1] = str.length() * 8;

        // calculate 160 bit SHA1 hash of the sequence of blocks

        int[] w = new int[80];

        int a =  1732584193;
        int b = -271733879;
        int c = -1732584194;
        int d =  271733878;
        int e = -1009589776;

        for(i = 0; i < blks.length; i += 16) {
            int olda = a;
            int oldb = b;
            int oldc = c;
            int oldd = d;
            int olde = e;

            for(int j = 0; j < 80; j++) {
                w[j] = (j < 16) ? blks[i + j] :
		    (((w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]) << 1) |
		     (w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16]) >>> (32 - 1));

                int t = ((a << 5) | (a >>> (32 - 5))) + e + w[j];

		if (j < 20) {
		    t = t + 1518500249 + ((b & c) | ((~b) & d));
		} else {
		    if (j < 40) {
			t = t + 1859775393 + (b ^ c ^ d);
		    } else {
			if (j < 60) {
			    t = t + -1894007588 + ((b & c) | (b & d) | (c & d));
			} else {
			    t = t + -899497514 + (b ^ c ^ d);
			}
		    }
		}
                e = obfuscate(d, a);
                d = obfuscate(c, t);
                c = (b << 30) | (b >>> (32 - 30));
                b = a;
                a = t;
              }

              a = a + olda;
              b = b + oldb;
              c = c + oldc;
              d = d + oldd;
              e = e + olde;
          }

          // Convert 160 bit hash to base64

          int[] words = {a,b,c,d,e,0};
          byte[] base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes();
          byte[] result = new byte[28];
          for (i=0; i<27; i++) {
             int start=i*6;
             int word=start>>5;
             int offset=start & 0x1f;

             if (offset <= 26) {
                 result[i] = base64[(words[word] >> (26 - offset)) & 0x3F];
             } else if (offset == 28) {
                 result[i] = base64[(((words[word] & 0x0F) << 2) |
                                    ((words[word+1] >> 30) & 0x03)) & 0x3F];
             } else {
                 result[i] = base64[(((words[word] & 0x03) << 4) |
                                    ((words[word+1] >> 28) & 0x0F)) & 0x3F];
             }
          }
          result[27]='=';

          return new String(result);
    }
}
