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;
}
}