package org.openstack.atlas.util.b64aes; import java.io.UnsupportedEncodingException; import java.util.List; public class Base64 { // static vars public static final int PAGESIZE = 4096; public static final int MAX_FILTER_ENTRY_SIZE = 4096; public static final int[] charToSix; public static final int[] sixToChar; private static String[] hexmap = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}; // instance vars static { int ch; sixToChar = new int[64]; charToSix = new int[256]; for (int i = 0; i < 256; i++) { charToSix[i] = -1; } for (int i = 0; i < 64; i++) { sixToChar[i] = 46; } for (int i = 0; i < 64; i++) { if (i < 26) { ch = (int) ((byte) 'A' + i - 0); } else if (i < 52) { ch = (int) ((byte) 'a' + i - 26); } else if (i < 62) { ch = (int) ((byte) '0' + i - 52); } else if (i == 62) { // '+' = 43 ch = 43; } else if (i == 63) { // '/' = 47 ch = 47; } else { ch = -1; } sixToChar[i] = ch; charToSix[ch] = i; } charToSix[61] = 0; // Treat '=' as padding } // for jython public static String decode(String strIn) throws PaddingException, UnsupportedEncodingException { byte[] bytesIn = strIn.getBytes("utf-8"); byte[] bytesOut = decode(bytesIn, bytesIn.length); return new String(bytesOut); } public static byte[] decode(byte[] unfilteredBytes, int unFilterLen) throws PaddingException { int[] map = charToSix; byte[] bi = filterPemBytes(unfilteredBytes, unFilterLen); byte[] bo; if (bi.length == 0) { return new byte[0]; } String dbgStr; try { dbgStr = new String(bi, "us-ascii"); } catch (UnsupportedEncodingException ex) { dbgStr = "WTF"; } int ilen = bi.length; int olen; int ibp = 0; int obp = 0; byte b0; byte b1; byte b2; byte b3; int ib0; int ib1; int ib2; int ib3; if (ilen % 4 != 0) { throw new PaddingException(String.format("b64 bytes was %d bytes lond eas expecting a multiple of 4", ilen)); } olen = ((ilen / 4) - 1) * 3; // Compute length based on padding if (bi[ilen - 2] == '=') { olen += 1; } else if (bi[ilen - 1] == '=') { olen += 2; } else { olen += 3; } bo = new byte[olen]; while (ilen - ibp > 4) { // Encode all but the last bytes b0 = bi[ibp + 0]; b1 = bi[ibp + 1]; b2 = bi[ibp + 2]; b3 = bi[ibp + 3]; ib0 = (b0 >= 0) ? (int) b0 : (int) b0 + 256; ib1 = (b1 >= 0) ? (int) b1 : (int) b1 + 256; ib2 = (b2 >= 0) ? (int) b2 : (int) b2 + 256; ib3 = (b3 >= 0) ? (int) b3 : (int) b3 + 256; bo[obp + 0] = (byte) (map[ib0] << 2 | map[ib1] >> 4); bo[obp + 1] = (byte) (map[ib1] << 4 & 0xf0 | map[ib2] >> 2); bo[obp + 2] = (byte) (map[ib2] << 6 & 0xc0 | map[ib3]); ibp += 4; obp += 3; } b0 = bi[ibp + 0]; b1 = bi[ibp + 1]; b2 = bi[ibp + 2]; b3 = bi[ibp + 3]; ib0 = (b0 >= 0) ? (int) b0 : (int) b0 + 256; ib1 = (b1 >= 0) ? (int) b1 : (int) b1 + 256; ib2 = (b2 >= 0) ? (int) b2 : (int) b2 + 256; ib3 = (b3 >= 0) ? (int) b3 : (int) b3 + 256; switch (olen % 3) { case 0: b0 = bi[ibp + 0]; b1 = bi[ibp + 1]; b2 = bi[ibp + 2]; b3 = bi[ibp + 3]; ib0 = (b0 >= 0) ? (int) b0 : (int) b0 + 256; ib1 = (b1 >= 0) ? (int) b1 : (int) b1 + 256; ib2 = (b2 >= 0) ? (int) b2 : (int) b2 + 256; ib3 = (b3 >= 0) ? (int) b3 : (int) b3 + 256; // No padding bo[obp + 0] = (byte) (map[ib0] << 2 | map[ib1] >> 4); bo[obp + 1] = (byte) (map[ib1] << 4 & 0xf0 | map[ib2] >> 2); bo[obp + 2] = (byte) (map[ib2] << 6 & 0xc0 | map[ib3]); break; case 1: // use '=' padding bo[obp + 0] = (byte) (map[ib0] << 2 | map[ib1] >> 4); break; case 2: // use '==' padding bo[obp + 0] = (byte) (map[ib0] << 2 | map[ib1] >> 4); bo[obp + 1] = (byte) (map[ib1] << 4 & 0xf0 | map[ib2] >> 2); break; } return bo; } public static byte[] filterPemBytes(byte[] bi, int blen) { int[] map = charToSix; int maxEntrySize = MAX_FILTER_ENTRY_SIZE; byte[] filteredInput; byte[] out; ByteBufferList bb = new ByteBufferList(); List<ByteBuffer> entries = bb.getByteBufferEntries(); byte[] entry; entry = new byte[maxEntrySize]; int used = 0; for (int i = 0; i < blen; i++) { byte currByte = bi[i]; int b = (currByte >= 0) ? (int) currByte : (int) currByte + 256; if (map[b] == -1) { continue; } if (used >= maxEntrySize) { entries.add(new ByteBuffer(entry, used)); used = 0; entry = new byte[maxEntrySize]; } entry[used] = (byte) b; used++; } if (used > 0) { entries.add(new ByteBuffer(entry, used)); } filteredInput = bb.getAllBytes(); return filteredInput; } public static String encode(String utf8Str) throws UnsupportedEncodingException{ byte[] bytes = toUTF8Bytes(utf8Str); byte[] encoded = encode(bytes,bytes.length); return toUTF8String(encoded); } public static byte[] encode(byte[] bi, int ilen) { final int[] map = sixToChar; int olen = ((ilen + 2) / 3) * 4; byte[] bo = new byte[olen]; byte currByte; int ibp = 0; int obp = 0; byte b0; byte b1; byte b2; byte b3; int ib0; int ib1; int ib2; while (ibp < ilen) { switch (ilen - ibp) { case 1: b0 = bi[ibp + 0]; ib0 = (b0 >= 0) ? (int) b0 : (int) b0 + 256; bo[obp + 0] = (byte) map[ib0 >> 2]; bo[obp + 1] = (byte) map[ib0 << 4 & 0x30]; bo[obp + 2] = '='; bo[obp + 3] = '='; break; case 2: b0 = bi[ibp + 0]; b1 = bi[ibp + 1]; ib0 = (b0 >= 0) ? (int) b0 : (int) b0 + 256; ib1 = (b1 >= 0) ? (int) b1 : (int) b1 + 256; bo[obp + 0] = (byte) map[ib0 >> 2]; bo[obp + 1] = (byte) map[ib0 << 4 & 0x30 | ib1 >> 4]; bo[obp + 2] = (byte) map[ib1 << 2 & 0x3c]; bo[obp + 3] = '='; break; default: b0 = bi[ibp + 0]; b1 = bi[ibp + 1]; b2 = bi[ibp + 2]; ib0 = (b0 >= 0) ? (int) b0 : (int) b0 + 256; ib1 = (b1 >= 0) ? (int) b1 : (int) b1 + 256; ib2 = (b2 >= 0) ? (int) b2 : (int) b2 + 256; bo[obp + 0] = (byte) map[ib0 >> 2]; bo[obp + 1] = (byte) map[ib0 << 4 & 0x30 | ib1 >> 4]; bo[obp + 2] = (byte) map[ib1 << 2 & 0x3c | ib2 >> 6]; bo[obp + 3] = (byte) map[ib2 & 0x3f]; break; } ibp += 3; obp += 4; } return bo; } public static String toHex(byte[] bytes) { StringBuilder sb = new StringBuilder(PAGESIZE); int bl = bytes.length; for (int i = 0; i < bl; i++) { int val = (int) bytes[i]; if (val < 0) { val += 256; } sb.append(hexmap[val >> 4]); sb.append(hexmap[val & 0x0f]); } return sb.toString(); } // For jython public static byte[] toUTF8Bytes(String strIn) throws UnsupportedEncodingException{ byte[] out = strIn.getBytes("utf-8"); return out; } public static String toUTF8String(byte[] bytes) throws UnsupportedEncodingException{ String out = new String(bytes,"utf-8"); return out; } private static int utoi(byte in) { return (in >= 0) ? (int) in : (int) in + 256; } private static byte itou(int in) { in &= 0xff; return (in < 128) ? (byte) in : (byte) (in - 256); } }