package com.subgraph.orchid.data; import com.subgraph.orchid.TorException; public class Base32 { private final static String BASE32_CHARS = "abcdefghijklmnopqrstuvwxyz234567"; public static String base32Encode(byte[] source) { return base32Encode(source, 0, source.length); } public static String base32Encode(byte[] source, int offset, int length) { final int nbits = length * 8; if(nbits % 5 != 0) throw new TorException("Base32 input length must be a multiple of 5 bits"); final int outlen = nbits / 5; final StringBuffer outbuffer = new StringBuffer(); int bit = 0; for(int i = 0; i < outlen; i++) { int v = (source[bit / 8] & 0xFF) << 8; if(bit + 5 < nbits) v += (source[bit / 8 + 1] & 0xFF); int u = (v >> (11 - (bit % 8))) & 0x1F; outbuffer.append(BASE32_CHARS.charAt(u)); bit += 5; } return outbuffer.toString(); } public static byte[] base32Decode(String source) { int[] v = stringToIntVector(source); int nbits = source.length() * 5; if(nbits % 8 != 0) throw new TorException("Base32 decoded array must be a muliple of 8 bits"); int outlen = nbits / 8; byte[] outbytes = new byte[outlen]; int bit = 0; for(int i = 0; i < outlen; i++) { int bb = bit / 5; outbytes[i] = (byte) decodeByte(bit, v[bb], v[bb + 1], v[bb + 2]); bit += 8; } return outbytes; } private static int decodeByte(int bitOffset, int b0, int b1, int b2) { switch(bitOffset % 40) { case 0: return ls(b0, 3) + rs(b1, 2); case 8: return ls(b0, 6) + ls(b1, 1) + rs (b2, 4); case 16: return ls(b0, 4) + rs(b1, 1); case 24: return ls(b0, 7) + ls(b1, 2) + rs(b2, 3); case 32: return ls(b0, 5) + (b1 & 0xFF); } throw new TorException("Illegal bit offset"); } private static int ls(int n, int shift) { return ((n << shift) & 0xFF); } private static int rs(int n, int shift) { return ((n >> shift) & 0xFF); } private static int[] stringToIntVector(String s) { final int[] ints = new int[s.length() + 1]; for(int i = 0; i < s.length(); i++) { int b = s.charAt(i) & 0xFF; if(b > 0x60 && b < 0x7B) ints[i] = b - 0x61; else if(b > 0x31 && b < 0x38) ints[i] = b - 0x18; else if(b > 0x40 && b < 0x5B) ints[i] = b - 0x41; else throw new TorException("Illegal character in base32 encoded string: "+ s.charAt(i)); } return ints; } }