Copyright (c) 2006, 2012 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2006, 2012 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.osgi.internal.signedcontent; public class Base64 { private static final byte equalSign = (byte) '='; static char digits[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
This method decodes the byte array in base 64 encoding into a char array Base 64 encoding has to be according to the specification given by the RFC 1521 (5.2).
Params:
  • data – the encoded byte array
Returns:the decoded byte array
/** * This method decodes the byte array in base 64 encoding into a char array * Base 64 encoding has to be according to the specification given by the * RFC 1521 (5.2). * * @param data the encoded byte array * @return the decoded byte array */
public static byte[] decode(byte[] data) { if (data.length == 0) return data; int lastRealDataIndex = data.length - 1; while (data[lastRealDataIndex] == equalSign) lastRealDataIndex--; // original data digit is 8 bits long, but base64 digit is 6 bits long int padBytes = data.length - 1 - lastRealDataIndex; int byteLength = data.length * 6 / 8 - padBytes; byte[] result = new byte[byteLength]; // Each 4 bytes of input (encoded) we end up with 3 bytes of output int dataIndex = 0; int resultIndex = 0; int allBits = 0; // how many result chunks we can process before getting to pad bytes int resultChunks = (lastRealDataIndex + 1) / 4; for (int i = 0; i < resultChunks; i++) { allBits = 0; // Loop 4 times gathering input bits (4 * 6 = 24) for (int j = 0; j < 4; j++) allBits = (allBits << 6) | decodeDigit(data[dataIndex++]); // Loop 3 times generating output bits (3 * 8 = 24) for (int j = resultIndex + 2; j >= resultIndex; j--) { result[j] = (byte) (allBits & 0xff); // Bottom 8 bits allBits = allBits >>> 8; } resultIndex += 3; // processed 3 result bytes } // Now we do the extra bytes in case the original (non-encoded) data // was not multiple of 3 bytes switch (padBytes) { case 1 : // 1 pad byte means 3 (4-1) extra Base64 bytes of input, 18 // bits, of which only 16 are meaningful // Or: 2 bytes of result data allBits = 0; // Loop 3 times gathering input bits for (int j = 0; j < 3; j++) allBits = (allBits << 6) | decodeDigit(data[dataIndex++]); // NOTE - The code below ends up being equivalent to allBits = // allBits>>>2 // But we code it in a non-optimized way for clarity // The 4th, missing 6 bits are all 0 allBits = allBits << 6; // The 3rd, missing 8 bits are all 0 allBits = allBits >>> 8; // Loop 2 times generating output bits for (int j = resultIndex + 1; j >= resultIndex; j--) { result[j] = (byte) (allBits & 0xff); // Bottom 8 // bits allBits = allBits >>> 8; } break; case 2 : // 2 pad bytes mean 2 (4-2) extra Base64 bytes of input, 12 bits // of data, of which only 8 are meaningful // Or: 1 byte of result data allBits = 0; // Loop 2 times gathering input bits for (int j = 0; j < 2; j++) allBits = (allBits << 6) | decodeDigit(data[dataIndex++]); // NOTE - The code below ends up being equivalent to allBits = // allBits>>>4 // But we code it in a non-optimized way for clarity // The 3rd and 4th, missing 6 bits are all 0 allBits = allBits << 6; allBits = allBits << 6; // The 3rd and 4th, missing 8 bits are all 0 allBits = allBits >>> 8; allBits = allBits >>> 8; result[resultIndex] = (byte) (allBits & 0xff); // Bottom // 8 // bits break; } return result; }
This method converts a Base 64 digit to its numeric value.
Params:
  • data – digit (character) to convert
Returns:value for the digit
/** * This method converts a Base 64 digit to its numeric value. * * @param data digit (character) to convert * @return value for the digit */
static int decodeDigit(byte data) { char charData = (char) data; if (charData <= 'Z' && charData >= 'A') return charData - 'A'; if (charData <= 'z' && charData >= 'a') return charData - 'a' + 26; if (charData <= '9' && charData >= '0') return charData - '0' + 52; switch (charData) { case '+' : return 62; case '/' : return 63; default : throw new IllegalArgumentException("Invalid char to decode: " + data); //$NON-NLS-1$ } }
This method encodes the byte array into a char array in base 64 according to the specification given by the RFC 1521 (5.2).
Params:
  • data – the encoded char array
Returns:the byte array that needs to be encoded
/** * This method encodes the byte array into a char array in base 64 according * to the specification given by the RFC 1521 (5.2). * * @param data the encoded char array * @return the byte array that needs to be encoded */
public static byte[] encode(byte[] data) { int sourceChunks = data.length / 3; int len = ((data.length + 2) / 3) * 4; byte[] result = new byte[len]; int extraBytes = data.length - (sourceChunks * 3); // Each 4 bytes of input (encoded) we end up with 3 bytes of output int dataIndex = 0; int resultIndex = 0; int allBits = 0; for (int i = 0; i < sourceChunks; i++) { allBits = 0; // Loop 3 times gathering input bits (3 * 8 = 24) for (int j = 0; j < 3; j++) allBits = (allBits << 8) | (data[dataIndex++] & 0xff); // Loop 4 times generating output bits (4 * 6 = 24) for (int j = resultIndex + 3; j >= resultIndex; j--) { result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom // 6 // bits allBits = allBits >>> 6; } resultIndex += 4; // processed 4 result bytes } // Now we do the extra bytes in case the original (non-encoded) data // is not multiple of 4 bytes switch (extraBytes) { case 1 : allBits = data[dataIndex++]; // actual byte allBits = allBits << 8; // 8 bits of zeroes allBits = allBits << 8; // 8 bits of zeroes // Loop 4 times generating output bits (4 * 6 = 24) for (int j = resultIndex + 3; j >= resultIndex; j--) { result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom // 6 // bits allBits = allBits >>> 6; } // 2 pad tags result[result.length - 1] = (byte) '='; result[result.length - 2] = (byte) '='; break; case 2 : allBits = data[dataIndex++]; // actual byte allBits = (allBits << 8) | (data[dataIndex++] & 0xff); // actual // byte allBits = allBits << 8; // 8 bits of zeroes // Loop 4 times generating output bits (4 * 6 = 24) for (int j = resultIndex + 3; j >= resultIndex; j--) { result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom // 6 // bits allBits = allBits >>> 6; } // 1 pad tag result[result.length - 1] = (byte) '='; break; } return result; } }