package com.sleazyweasel.pandora;/* Pandoroid Radio - open source pandora.com client for android
* Copyright (C) 2011 Andrew Regner <andrew@aregner.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* This is a Java port of the "blowfish.py" module from the Pithos source code.
*
* Pithos is released under the GNU GPL v3, Copyright (C) 2010 Kevin Mehall <km@kevinmehall.net>
* blowfish.py is (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>
*/
import java.util.ArrayList;
import java.util.List;
public class Blowfish {
// Cipher directions
private static final int ENCRYPT = 0;
private static final int DECRYPT = 1;
// For the roundFunc()
private static final long modulus = (long) Math.pow(2L, 32);
private long[] p_boxes;
private long[][] s_boxes;
public Blowfish(long[] p_boxes, long[][] s_boxes) {
this.p_boxes = p_boxes;
this.s_boxes = s_boxes;
}
protected long[] cipher(long xl, long xr, int direction) {
long temp_x;
long[] result = {0L, 0L};
if (direction == Blowfish.ENCRYPT) {
for (int i = 0; i < 16; i++) {
xl = xl ^ this.p_boxes[i];
xr = this.roundFunc(xl) ^ xr;
temp_x = xl;
xl = xr;
xr = temp_x;
}
temp_x = xl;
xl = xr;
xr = temp_x;
xr = xr ^ this.p_boxes[16];
xl = xl ^ this.p_boxes[17];
} else if (direction == Blowfish.DECRYPT) {
for (int i = 17; i > 1; i--) {
xl = xl ^ this.p_boxes[i];
xr = this.roundFunc(xl) ^ xr;
temp_x = xl;
xl = xr;
xr = temp_x;
}
temp_x = xl;
xl = xr;
xr = temp_x;
xr = xr ^ this.p_boxes[1];
xl = xl ^ this.p_boxes[0];
}
result[0] = xl;
result[1] = xr;
return result;
}
private long roundFunc(long xl) {
long a = (xl & 0xff000000) >> 24;
long b = (xl & 0x00ff0000) >> 16;
long c = (xl & 0x0000ff00) >> 8;
long d = xl & 0x000000ff;
// Perform all ops as longs then and out the last 32-bits to obtain the integer
long f = ((long) this.s_boxes[0][(int) a] + (long) this.s_boxes[1][(int) b]) % Blowfish.modulus;
f = f ^ (long) this.s_boxes[2][(int) c];
f = f + (long) this.s_boxes[3][(int) d];
f = (f % Blowfish.modulus) & 0xffffffff;
return f;
}
public long[] encrypt(char[] data) {
long[] chars = new long[8];
if (data.length != 8) {
throw new RuntimeException("Attempted to encrypt data of invalid block length: " + data.length);
}
// Use big endianess since that's what everyone else uses
long xl = (long) data[3] | ((long) data[2] << 8) | ((long) data[1] << 16) | ((long) data[0] << 24);
long xr = (long) data[7] | ((long) data[6] << 8) | ((long) data[5] << 16) | ((long) data[4] << 24);
long[] temp_x = this.cipher(xl, xr, Blowfish.ENCRYPT);
long cl = temp_x[0];
long cr = temp_x[1];
chars[0] = ((cl >> 24) & 0xff);
chars[1] = ((cl >> 16) & 0xff);
chars[2] = ((cl >> 8) & 0xff);
chars[3] = (cl & 0xff);
chars[4] = ((cr >> 24) & 0xff);
chars[5] = ((cr >> 16) & 0xff);
chars[6] = ((cr >> 8) & 0xff);
chars[7] = (cr & 0xff);
return chars;
}
public String decrypt(char[] data) {
List<Character> characters = decryptToBytes(data);
StringBuilder stringBuilder = new StringBuilder();
for (Character character : characters) {
stringBuilder.append(character);
}
return stringBuilder.toString();
}
public List<Character> decryptToBytes(char[] data) {
long[] chars = new long[8];
if (data.length != 8) {
throw new RuntimeException("Attempted to encrypt data of invalid block length: " + data.length);
}
// Use big endianess since that's what everyone else uses
long cl = (long) data[3] | ((long) data[2] << 8) | ((long) data[1] << 16) | ((long) data[0] << 24);
long cr = (long) data[7] | ((long) data[6] << 8) | ((long) data[5] << 16) | ((long) data[4] << 24);
long[] temp_x = this.cipher(cl, cr, Blowfish.DECRYPT);
long xl = temp_x[0];
long xr = temp_x[1];
chars[0] = ((xl >> 24) & 0xff);
chars[1] = ((xl >> 16) & 0xff);
chars[2] = ((xl >> 8) & 0xff);
chars[3] = (xl & 0xff);
chars[4] = ((xr >> 24) & 0xff);
chars[5] = ((xr >> 16) & 0xff);
chars[6] = ((xr >> 8) & 0xff);
chars[7] = (xr & 0xff);
List<Character> results = new ArrayList<Character>();
for (long character : chars) {
results.add((char) character);
}
return results;
}
public int blocksize() {
return 8;
}
public int keyLength() {
return 56;
}
public int keyBits() {
return 56 * 8;
}
public static void main(String[] args) {
}
}